diff options
Diffstat (limited to 'indra/llrender')
36 files changed, 3666 insertions, 2067 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 0bb835970f..5c13df9f81 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -9,6 +9,7 @@ include(LLCommon) include(LLImage) include(LLMath) include(LLRender) +include(LLVFS) include(LLWindow) include(LLXML) include(LLVFS) @@ -19,6 +20,7 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} @@ -26,7 +28,7 @@ include_directories( set(llrender_SOURCE_FILES llcubemap.cpp - llfont.cpp + llfontfreetype.cpp llfontgl.cpp llfontbitmapcache.cpp llfontregistry.cpp @@ -36,6 +38,7 @@ set(llrender_SOURCE_FILES llpostprocess.cpp llrendersphere.cpp llshadermgr.cpp + lltexture.cpp llvertexbuffer.cpp ) @@ -44,7 +47,7 @@ set(llrender_HEADER_FILES llcubemap.h llfontgl.h - llfont.h + llfontfreetype.h llfontbitmapcache.h llfontregistry.h llgl.h @@ -58,6 +61,7 @@ set(llrender_HEADER_FILES llrender.h llrendersphere.h llshadermgr.h + lltexture.h llvertexbuffer.h ) diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 754d90c854..fb22d7f1f5 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -2,31 +2,25 @@ * @file llcubemap.cpp * @brief LLCubeMap class implementation * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" @@ -63,6 +57,12 @@ LLCubeMap::LLCubeMap() mTextureCoordStage(0), mMatrixStage(0) { + 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; } LLCubeMap::~LLCubeMap() @@ -75,13 +75,6 @@ void LLCubeMap::initGL() 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()) { @@ -106,7 +99,7 @@ void LLCubeMap::initGL() } else { - llwarns << "Using cube map without extension!" << llendl + llwarns << "Using cube map without extension!" << llendl; } } diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h index c8544850d9..ee2c41e026 100644 --- a/indra/llrender/llcubemap.h +++ b/indra/llrender/llcubemap.h @@ -2,31 +2,25 @@ * @file llcubemap.h * @brief LLCubeMap class definition * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index 052510e6ed..c985f6b959 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -2,31 +2,25 @@ * @file llfontbitmapcache.cpp * @brief Storage for previously rendered glyphs. * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,13 +31,13 @@ LLFontBitmapCache::LLFontBitmapCache(): mNumComponents(0), - mMaxCharWidth(0), - mMaxCharHeight(0), mBitmapWidth(0), mBitmapHeight(0), + mBitmapNum(-1), + mMaxCharWidth(0), + mMaxCharHeight(0), mCurrentOffsetX(1), - mCurrentOffsetY(1), - mCurrentBitmapNum(-1) + mCurrentOffsetY(1) { } @@ -64,7 +58,7 @@ void LLFontBitmapCache::init(S32 num_components, LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const { - if ((bitmap_num < 0) || (bitmap_num >= mImageRawVec.size())) + if (bitmap_num >= mImageRawVec.size()) return NULL; return mImageRawVec[bitmap_num]; @@ -72,7 +66,7 @@ LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const LLImageGL *LLFontBitmapCache::getImageGL(U32 bitmap_num) const { - if ((bitmap_num < 0) || (bitmap_num >= mImageGLVec.size())) + if (bitmap_num >= mImageGLVec.size()) return NULL; return mImageGLVec[bitmap_num]; @@ -160,10 +154,10 @@ void LLFontBitmapCache::reset() mImageRawVec.clear(); mImageGLVec.clear(); - mBitmapWidth = 0, - mBitmapHeight = 0, - mCurrentOffsetX = 0, - mCurrentOffsetY = 0, - mCurrentBitmapNum = -1; + mBitmapWidth = 0; + mBitmapHeight = 0; + mBitmapNum = -1; + mCurrentOffsetX = 1; + mCurrentOffsetY = 1; } diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index 4beea0d026..c93b0c7320 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -2,31 +2,25 @@ * @file llfontbitmapcache.h * @brief Storage for previously rendered glyphs. * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,7 +30,7 @@ #include <vector> // Maintain a collection of bitmaps containing rendered glyphs. -// Generalizes the single-bitmap logic from LLFont and LLFontGL. +// Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL. class LLFontBitmapCache: public LLRefCount { public: @@ -71,7 +65,6 @@ private: S32 mMaxCharHeight; S32 mCurrentOffsetX; S32 mCurrentOffsetY; - S32 mCurrentBitmapNum; std::vector<LLPointer<LLImageRaw> > mImageRawVec; std::vector<LLPointer<LLImageGL> > mImageGLVec; }; diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp new file mode 100644 index 0000000000..b84e696e2d --- /dev/null +++ b/indra/llrender/llfontfreetype.cpp @@ -0,0 +1,592 @@ +/** + * @file llfontfreetype.cpp + * @brief Freetype font library wrapper + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfontfreetype.h" +#include "llfontgl.h" + +// Freetype stuff +#include <ft2build.h> + +// For some reason, this won't work if it's not wrapped in the ifdef +#ifdef FT_FREETYPE_H +#include FT_FREETYPE_H +#endif + +#include "llerror.h" +#include "llimage.h" +//#include "llimagej2c.h" +#include "llmath.h" // Linden math +#include "llstring.h" +//#include "imdebug.h" +#include "llfontbitmapcache.h" +#include "llgl.h" + +FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; + +LLFontManager *gFontManagerp = NULL; + +FT_Library gFTLibrary = NULL; + +//static +void LLFontManager::initClass() +{ + gFontManagerp = new LLFontManager; +} + +//static +void LLFontManager::cleanupClass() +{ + delete gFontManagerp; + gFontManagerp = NULL; +} + +LLFontManager::LLFontManager() +{ + int error; + error = FT_Init_FreeType(&gFTLibrary); + if (error) + { + // Clean up freetype libs. + llerrs << "Freetype initialization failure!" << llendl; + FT_Done_FreeType(gFTLibrary); + } +} + +LLFontManager::~LLFontManager() +{ + FT_Done_FreeType(gFTLibrary); +} + + +LLFontGlyphInfo::LLFontGlyphInfo(U32 index) +: mGlyphIndex(index), + mWidth(0), // In pixels + mHeight(0), // In pixels + mXAdvance(0.f), // In pixels + mYAdvance(0.f), // In pixels + mXBitmapOffset(0), // Offset to the origin in the bitmap + mYBitmapOffset(0), // Offset to the origin in the bitmap + mXBearing(0), // Distance from baseline to left in pixels + mYBearing(0), // Distance from baseline to top in pixels + mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph +{ +} + +LLFontFreetype::LLFontFreetype() +: mFontBitmapCachep(new LLFontBitmapCache), + mValid(FALSE), + mAscender(0.f), + mDescender(0.f), + mLineHeight(0.f), + mIsFallback(FALSE), + mFTFace(NULL), + mRenderGlyphCount(0), + mAddGlyphCount(0), + mStyle(0), + mPointSize(0) +{ +} + + +LLFontFreetype::~LLFontFreetype() +{ + // Clean up freetype libs. + if (mFTFace) + FT_Done_Face(mFTFace); + mFTFace = NULL; + + // Delete glyph info + std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); + + // mFontBitmapCachep will be cleaned up by LLPointer destructor. + // mFallbackFonts cleaned up by LLPointer destructor +} + +BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback) +{ + // Don't leak face objects. This is also needed to deal with + // changed font file names. + if (mFTFace) + { + FT_Done_Face(mFTFace); + mFTFace = NULL; + } + + int error; + + error = FT_New_Face( gFTLibrary, + filename.c_str(), + 0, + &mFTFace ); + + if (error) + { + return FALSE; + } + + mIsFallback = is_fallback; + F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi + + error = FT_Set_Char_Size(mFTFace, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + (S32)(point_size*64), /* char_height in 1/64th of points */ + (U32)horz_dpi, /* horizontal device resolution */ + (U32)vert_dpi); /* vertical device resolution */ + + if (error) + { + // Clean up freetype libs. + FT_Done_Face(mFTFace); + mFTFace = NULL; + return FALSE; + } + + F32 y_max, y_min, x_max, x_min; + F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; + F32 pixels_per_unit = pixels_per_em * ems_per_unit; + + // Get size of bbox in pixels + y_max = mFTFace->bbox.yMax * pixels_per_unit; + y_min = mFTFace->bbox.yMin * pixels_per_unit; + x_max = mFTFace->bbox.xMax * pixels_per_unit; + x_min = mFTFace->bbox.xMin * pixels_per_unit; + mAscender = mFTFace->ascender * pixels_per_unit; + mDescender = -mFTFace->descender * pixels_per_unit; + mLineHeight = mFTFace->height * pixels_per_unit; + + S32 max_char_width = llround(0.5f + (x_max - x_min)); + S32 max_char_height = llround(0.5f + (y_max - y_min)); + + mFontBitmapCachep->init(components, max_char_width, max_char_height); + + if (!mFTFace->charmap) + { + //llinfos << " no unicode encoding, set whatever encoding there is..." << llendl; + FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); + } + + if (!mIsFallback) + { + // Add the default glyph + addGlyphFromFont(this, 0, 0); + } + + mName = filename; + mPointSize = point_size; + + mStyle = LLFontGL::NORMAL; + if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) + { + mStyle |= LLFontGL::BOLD; + mStyle &= ~LLFontGL::NORMAL; + } + + if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) + { + mStyle |= LLFontGL::ITALIC; + mStyle &= ~LLFontGL::NORMAL; + } + + return TRUE; +} + +void LLFontFreetype::setFallbackFonts(const font_vector_t &font) +{ + mFallbackFonts = font; +} + +const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const +{ + return mFallbackFonts; +} + +F32 LLFontFreetype::getLineHeight() const +{ + return mLineHeight; +} + +F32 LLFontFreetype::getAscenderHeight() const +{ + return mAscender; +} + +F32 LLFontFreetype::getDescenderHeight() const +{ + return mDescender; +} + +F32 LLFontFreetype::getXAdvance(llwchar wch) const +{ + if (mFTFace == NULL) + return 0.0; + + // Return existing info only if it is current + LLFontGlyphInfo* gi = getGlyphInfo(wch); + if (gi) + { + return gi->mXAdvance; + } + else + { + char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); + if (found_it != mCharGlyphInfoMap.end()) + { + return found_it->second->mXAdvance; + } + } + + // Last ditch fallback - no glyphs defined at all. + return (F32)mFontBitmapCachep->getMaxCharWidth(); +} + +F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const +{ + if (mFTFace == NULL) + return 0.0; + + return glyph->mXAdvance; +} + +F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const +{ + if (mFTFace == NULL) + return 0.0; + + //llassert(!mIsFallback); + LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);; + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + // Kern this puppy. + LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right); + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + + FT_Vector delta; + + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + + return delta.x*(1.f/64.f); +} + +F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const +{ + if (mFTFace == NULL) + return 0.0; + + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + + FT_Vector delta; + + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + + return delta.x*(1.f/64.f); +} + +BOOL LLFontFreetype::hasGlyph(llwchar wch) const +{ + llassert(!mIsFallback); + return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); +} + +LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const +{ + if (mFTFace == NULL) + return FALSE; + + llassert(!mIsFallback); + //lldebugs << "Adding new glyph for " << wch << " to font" << llendl; + + FT_UInt glyph_index; + + // Initialize char to glyph map + glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) + { + //llinfos << "Trying to add glyph from fallback font!" << llendl; + font_vector_t::const_iterator iter; + for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++) + { + glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(*iter, wch, glyph_index); + } + } + } + + char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); + if (iter == mCharGlyphInfoMap.end()) + { + return addGlyphFromFont(this, wch, glyph_index); + } + return NULL; +} + +LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const +{ + if (mFTFace == NULL) + return NULL; + + llassert(!mIsFallback); + fontp->renderGlyph(glyph_index); + S32 width = fontp->mFTFace->glyph->bitmap.width; + S32 height = fontp->mFTFace->glyph->bitmap.rows; + + S32 pos_x, pos_y; + S32 bitmap_num; + mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num); + mAddGlyphCount++; + + LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index); + gi->mXBitmapOffset = pos_x; + gi->mYBitmapOffset = pos_y; + gi->mBitmapNum = bitmap_num; + gi->mWidth = width; + gi->mHeight = height; + gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; + gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; + // Convert these from 26.6 units to float pixels. + gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; + gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; + + insertGlyphInfo(wch, gi); + + llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO + || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); + + if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO + || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) + { + U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; + S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; + U8 *tmp_graydata = NULL; + + if (fontp->mFTFace->glyph->bitmap.pixel_mode + == FT_PIXEL_MODE_MONO) + { + // need to expand 1-bit bitmap to 8-bit graymap. + tmp_graydata = new U8[width * height]; + S32 xpos, ypos; + for (ypos = 0; ypos < height; ++ypos) + { + S32 bm_row_offset = buffer_row_stride * ypos; + for (xpos = 0; xpos < width; ++xpos) + { + U32 bm_col_offsetbyte = xpos / 8; + U32 bm_col_offsetbit = 7 - (xpos % 8); + U32 bit = + !!(buffer_data[bm_row_offset + + bm_col_offsetbyte + ] & (1 << bm_col_offsetbit) ); + tmp_graydata[width*ypos + xpos] = + 255 * bit; + } + } + // use newly-built graymap. + buffer_data = tmp_graydata; + buffer_row_stride = width; + } + + switch (mFontBitmapCachep->getNumComponents()) + { + case 1: + mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x, + pos_y, + width, + height, + buffer_data, + buffer_row_stride, + TRUE); + break; + case 2: + setSubImageLuminanceAlpha(pos_x, + pos_y, + bitmap_num, + width, + height, + buffer_data, + buffer_row_stride); + break; + default: + break; + } + + if (tmp_graydata) + delete[] tmp_graydata; + } else { + // we don't know how to handle this pixel format from FreeType; + // omit it from the font-image. + } + + LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num); + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); + image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); + + return gi; +} + +LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const +{ + char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); + if (iter != mCharGlyphInfoMap.end()) + { + return iter->second; + } + else + { + // this glyph doesn't yet exist, so render it and return the result + return addGlyph(wch); + } +} + +void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const +{ + char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); + if (iter != mCharGlyphInfoMap.end()) + { + delete iter->second; + iter->second = gi; + } + else + { + mCharGlyphInfoMap[wch] = gi; + } +} + +void LLFontFreetype::renderGlyph(U32 glyph_index) const +{ + if (mFTFace == NULL) + return; + + int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT ); + llassert(!error); + + error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode); + + mRenderGlyphCount++; + + llassert(!error); +} + +void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) +{ + resetBitmapCache(); + loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback); + if (!mIsFallback) + { + // This is the head of the list - need to rebuild ourself and all fallbacks. + if (mFallbackFonts.empty()) + { + llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl; + } + else + { + for(font_vector_t::iterator it = mFallbackFonts.begin(); + it != mFallbackFonts.end(); + ++it) + { + (*it)->reset(vert_dpi, horz_dpi); + } + } + } +} + +void LLFontFreetype::resetBitmapCache() +{ + for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); + mCharGlyphInfoMap.clear(); + mFontBitmapCachep->reset(); + + // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). + // This if was added as fix for EXT-4971. + if(!mIsFallback) + { + // Add the empty glyph + addGlyphFromFont(this, 0, 0); + } +} + +void LLFontFreetype::destroyGL() +{ + mFontBitmapCachep->destroyGL(); +} + +const std::string &LLFontFreetype::getName() const +{ + return mName; +} + +const LLPointer<LLFontBitmapCache> LLFontFreetype::getFontBitmapCache() const +{ + return mFontBitmapCachep; +} + +void LLFontFreetype::setStyle(U8 style) +{ + mStyle = style; +} + +U8 LLFontFreetype::getStyle() const +{ + return mStyle; +} + +void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const +{ + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); + + llassert(!mIsFallback); + llassert(image_raw && (image_raw->getComponents() == 2)); + + + U8 *target = image_raw->getData(); + + if (!data) + { + return; + } + + if (0 == stride) + stride = width; + + U32 i, j; + U32 to_offset; + U32 from_offset; + U32 target_width = image_raw->getWidth(); + for (i = 0; i < height; i++) + { + to_offset = (y + i)*target_width + x; + from_offset = (height - 1 - i)*stride; + for (j = 0; j < width; j++) + { + *(target + to_offset*2 + 1) = *(data + from_offset); + to_offset++; + from_offset++; + } + } +} + diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h new file mode 100644 index 0000000000..f1b23f22d5 --- /dev/null +++ b/indra/llrender/llfontfreetype.h @@ -0,0 +1,176 @@ +/** + * @file llfontfreetype.h + * @brief Font library wrapper + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFONTFREETYPE_H +#define LL_LLFONTFREETYPE_H + +#include <boost/unordered_map.hpp> +#include "llpointer.h" +#include "llstl.h" + +#include "llimagegl.h" +#include "llfontbitmapcache.h" + +// Hack. FT_Face is just a typedef for a pointer to a struct, +// but there's no simple forward declarations file for FreeType, +// and the main include file is 200K. +// We'll forward declare the struct here. JC +struct FT_FaceRec_; +typedef struct FT_FaceRec_* LLFT_Face; + +class LLFontManager +{ +public: + static void initClass(); + static void cleanupClass(); + +private: + LLFontManager(); + ~LLFontManager(); +}; + +struct LLFontGlyphInfo +{ + LLFontGlyphInfo(U32 index); + + U32 mGlyphIndex; + + // Metrics + S32 mWidth; // In pixels + S32 mHeight; // In pixels + F32 mXAdvance; // In pixels + F32 mYAdvance; // In pixels + + // Information for actually rendering + S32 mXBitmapOffset; // Offset to the origin in the bitmap + S32 mYBitmapOffset; // Offset to the origin in the bitmap + S32 mXBearing; // Distance from baseline to left in pixels + S32 mYBearing; // Distance from baseline to top in pixels + S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph +}; + +extern LLFontManager *gFontManagerp; + +class LLFontFreetype : public LLRefCount +{ +public: + LLFontFreetype(); + ~LLFontFreetype(); + + // is_fallback should be true for fallback fonts that aren't used + // to render directly (Unicode backup, primarily) + BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback); + + typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t; + + void setFallbackFonts(const font_vector_t &font); + const font_vector_t &getFallbackFonts() const; + + // Global font metrics - in units of pixels + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; + + +// For a lowercase "g": +// +// ------------------------------ +// ^ ^ +// | | +// xxx x |Ascender +// x x v | +// --------- xxxx-------------- Baseline +// ^ x | +// | Descender x | +// v xxxx |LineHeight +// ----------------------- | +// v +// ------------------------------ + + enum + { + FIRST_CHAR = 32, + NUM_CHARS = 127 - 32, + LAST_CHAR_BASIC = 127, + + // Need full 8-bit ascii range for spanish + NUM_CHARS_FULL = 255 - 32, + LAST_CHAR_FULL = 255 + }; + + F32 getXAdvance(llwchar wc) const; + F32 getXAdvance(const LLFontGlyphInfo* glyph) const; + F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters + + LLFontGlyphInfo* getGlyphInfo(llwchar wch) const; + + void reset(F32 vert_dpi, F32 horz_dpi); + + void destroyGL(); + + const std::string& getName() const; + + const LLPointer<LLFontBitmapCache> getFontBitmapCache() const; + + void setStyle(U8 style); + U8 getStyle() const; + +private: + void resetBitmapCache(); + void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const; + BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character + LLFontGlyphInfo* addGlyph(llwchar wch) const; // Add a new character to the font if necessary + LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) + void renderGlyph(U32 glyph_index) const; + void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; + + std::string mName; + + U8 mStyle; + + F32 mPointSize; + F32 mAscender; + F32 mDescender; + F32 mLineHeight; + + LLFT_Face mFTFace; + + BOOL mIsFallback; + font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) + + BOOL mValid; + + typedef boost::unordered_map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t; + mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap + + mutable LLPointer<LLFontBitmapCache> mFontBitmapCachep; + + mutable S32 mRenderGlyphCount; + mutable S32 mAddGlyphCount; +}; + +#endif // LL_FONTFREETYPE_H diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 048bfe8e0d..386bb987f9 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -2,31 +2,25 @@ * @file llfontgl.cpp * @brief Wrapper around FreeType * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +29,7 @@ #include "llfontgl.h" // Linden library includes -#include "llfont.h" +#include "llfontfreetype.h" #include "llfontbitmapcache.h" #include "llfontregistry.h" #include "llgl.h" @@ -43,6 +37,8 @@ #include "llrender.h" #include "llstl.h" #include "v4color.h" +#include "lltexture.h" +#include "lldir.h" // Third party library includes #include <boost/tokenizer.hpp> @@ -72,349 +68,81 @@ const F32 PIXEL_CORRECTION_DISTANCE = 0.01f; const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f; -F32 llfont_round_x(F32 x) +static F32 llfont_round_x(F32 x) { //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX; //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY; return x; } -F32 llfont_round_y(F32 y) +static F32 llfont_round_y(F32 y) { //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY; //return llfloor(y+0.5f); return y; } -// static -U8 LLFontGL::getStyleFromString(const std::string &style) -{ - S32 ret = 0; - if (style.find("NORMAL") != style.npos) - { - ret |= NORMAL; - } - if (style.find("BOLD") != style.npos) - { - ret |= BOLD; - } - if (style.find("ITALIC") != style.npos) - { - ret |= ITALIC; - } - if (style.find("UNDERLINE") != style.npos) - { - ret |= UNDERLINE; - } - return ret; -} - LLFontGL::LLFontGL() - : LLFont() -{ - clearEmbeddedChars(); -} - -LLFontGL::LLFontGL(const LLFontGL &source) { - llerrs << "Not implemented!" << llendl; } LLFontGL::~LLFontGL() { - clearEmbeddedChars(); } void LLFontGL::reset() { - if (!mIsFallback) - { - // This is the head of the list - need to rebuild ourself and all fallbacks. - loadFace(mName,mPointSize,sVertDPI,sHorizDPI,mFontBitmapCachep->getNumComponents(),mIsFallback); - if (mFallbackFontp==NULL) - { - llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl; - } - else - { - for (LLFontList::iterator it = mFallbackFontp->begin(); - it != mFallbackFontp->end(); - ++it) - { - (*it)->reset(); - } - } - } - resetBitmapCache(); -} - -// static -std::string LLFontGL::getFontPathSystem() -{ - std::string system_path; - - // Try to figure out where the system's font files are stored. - char *system_root = NULL; -#if LL_WINDOWS - system_root = getenv("SystemRoot"); /* Flawfinder: ignore */ - if (!system_root) - { - llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl; - } -#endif - - if (system_root) - { - system_path = llformat("%s/fonts/", system_root); - } - else - { -#if LL_WINDOWS - // HACK for windows 98/Me - system_path = "/WINDOWS/FONTS/"; -#elif LL_DARWIN - // HACK for Mac OS X - system_path = "/System/Library/Fonts/"; -#endif - } - return system_path; -} - - -// static -std::string LLFontGL::getFontPathLocal() -{ - std::string local_path; - - // Backup files if we can't load from system fonts directory. - // We could store this in an end-user writable directory to allow - // end users to switch fonts. - if (LLFontGL::sAppDir.length()) - { - // use specified application dir to look for fonts - local_path = LLFontGL::sAppDir + "/fonts/"; - } - else - { - // assume working directory is executable directory - local_path = "./fonts/"; - } - return local_path; -} - -bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc) -{ - // Don't delete existing fonts, if any, here, because they've - // already been deleted by LLFontRegistry::clear() - fontp = LLFontGL::getFont(desc); - return (fontp != NULL); -} - -// static -void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, - const std::string& app_dir, - const std::vector<std::string>& xui_paths, - bool create_gl_textures) -{ - sVertDPI = (F32)llfloor(screen_dpi * y_scale); - sHorizDPI = (F32)llfloor(screen_dpi * x_scale); - sScaleX = x_scale; - sScaleY = y_scale; - sAppDir = app_dir; - - // Font registry init - if (!sFontRegistry) - { - sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures); - sFontRegistry->parseFontInfo("fonts.xml"); - } - else - { - sFontRegistry->reset(); - } -} - -// Force standard fonts to get generated up front. -// This is primarily for error detection purposes. -// Don't do this during initClass because it can be slow and we want to get -// the viewer window on screen first. JC -// static -bool LLFontGL::loadDefaultFonts() -{ - bool succ = true; - succ &= (NULL != getFontSansSerifSmall()); - succ &= (NULL != getFontSansSerif()); - succ &= (NULL != getFontSansSerifBig()); - succ &= (NULL != getFontSansSerifHuge()); - succ &= (NULL != getFontSansSerifBold()); - succ &= (NULL != getFontMonospace()); - succ &= (NULL != getFontExtChar()); - return succ; -} - - - -// static -void LLFontGL::destroyDefaultFonts() -{ - // Remove the actual fonts. - delete sFontRegistry; - sFontRegistry = NULL; -} - -//static -void LLFontGL::destroyAllGL() -{ - if (sFontRegistry) - { - sFontRegistry->destroyGL(); - } + mFontFreetype->reset(sVertDPI, sHorizDPI); } void LLFontGL::destroyGL() { - mFontBitmapCachep->destroyGL(); + mFontFreetype->destroyGL(); } - - -LLFontGL &LLFontGL::operator=(const LLFontGL &source) +BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback) { - llerrs << "Not implemented" << llendl; - return *this; -} - -BOOL LLFontGL::loadFace(const std::string& filename, - const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, - const S32 components, BOOL is_fallback) -{ - if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback)) + if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL)) { - return FALSE; + mFontFreetype = new LLFontFreetype; } - return TRUE; -} - -//static -LLFontGL* LLFontGL::getFontMonospace() -{ - return getFont(LLFontDescriptor("Monospace","Monospace",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerifSmall() -{ - return getFont(LLFontDescriptor("SansSerif","Small",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerif() -{ - return getFont(LLFontDescriptor("SansSerif","Medium",0)); -} -//static -LLFontGL* LLFontGL::getFontSansSerifBig() -{ - return getFont(LLFontDescriptor("SansSerif","Large",0)); + return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback); } -//static -LLFontGL* LLFontGL::getFontSansSerifHuge() -{ - return getFont(LLFontDescriptor("SansSerif","Huge",0)); -} +static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts"); -//static -LLFontGL* LLFontGL::getFontSansSerifBold() -{ - return getFont(LLFontDescriptor("SansSerif","Medium",BOLD)); -} - -//static -LLFontGL* LLFontGL::getFontExtChar() -{ - return getFontSansSerif(); -} - -//static -LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) +S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, + ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const { - return sFontRegistry->getFont(desc); -} + F32 x = rect.mLeft; + F32 y = 0.f; -//static -LLFontGL* LLFontGL::getFontByName(const std::string& name) -{ - // check for most common fonts first - if (name == "SANSSERIF") - { - return getFontSansSerif(); - } - else if (name == "SANSSERIF_SMALL") + switch(valign) { - return getFontSansSerifSmall(); - } - else if (name == "SANSSERIF_BIG") - { - return getFontSansSerifBig(); - } - else if (name == "SMALL" || name == "OCRA") - { - // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? - // Does "SMALL" mean "SERIF"? - return getFontMonospace(); - } - else - { - return NULL; - } -} - -BOOL LLFontGL::addChar(const llwchar wch) const -{ - if (!LLFont::addChar(wch)) - { - return FALSE; + case TOP: + y = rect.mTop; + break; + case VCENTER: + y = rect.getCenterY(); + break; + case BASELINE: + case BOTTOM: + y = rect.mBottom; + break; + default: + y = rect.mBottom; + break; } - - stop_glerror(); - - LLFontGlyphInfo *glyph_info = getGlyphInfo(wch); - U32 bitmap_num = glyph_info->mBitmapNum; - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num); - LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); - image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); - return TRUE; + return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses); } -S32 LLFontGL::renderUTF8(const std::string &text, const S32 offset, - const F32 x, const F32 y, - const LLColor4 &color, - const HAlign halign, const VAlign valign, - U8 style, - ShadowType shadow, - const S32 max_chars, const S32 max_pixels, - F32* right_x, - BOOL use_ellipses) const +S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, + ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const { - LLWString wstr = utf8str_to_wstring(text); - return render(wstr, offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, FALSE, use_ellipses); -} + LLFastTimer _(FTM_RENDER_FONTS); -S32 LLFontGL::render(const LLWString &wstr, - const S32 begin_offset, - const F32 x, const F32 y, - const LLColor4 &color, - const HAlign halign, const VAlign valign, - U8 style, - ShadowType shadow, - const S32 max_chars, S32 max_pixels, - F32* right_x, - BOOL use_embedded, - BOOL use_ellipses) const -{ if(!sDisplayFont) //do not display texts { return wstr.length() ; @@ -429,8 +157,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); - // Strip off any style bits that are already accounted for by the font. - style = style & (~getFontDesc().getStyle()); + // determine which style flags need to be added programmatically by stripping off the + // style bits that are drawn by the underlying Freetype font + U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle(); F32 drop_shadow_strength = 0.f; if (shadow != NO_SHADOW) @@ -444,18 +173,22 @@ S32 LLFontGL::render(const LLWString &wstr, } } - gGL.pushMatrix(); - glLoadIdentity(); - gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ); + gGL.pushUIMatrix(); + + gGL.loadUIIdentity(); + + //gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ); // this code snaps the text origin to a pixel grid to start with - F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX); - F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); - gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f); + //F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX); + //F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); + //gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f); - LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS); + LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY)); + // snap the text origin to a pixel grid to start with + origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX); + origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); - gGL.color4fv( color.mV ); S32 chars_drawn = 0; S32 i; @@ -475,20 +208,20 @@ S32 LLFontGL::render(const LLWString &wstr, // Not guaranteed to be set correctly gGL.setSceneBlendType(LLRender::BT_ALPHA); - cur_x = ((F32)x * sScaleX); - cur_y = ((F32)y * sScaleY); + cur_x = ((F32)x * sScaleX) + origin.mV[VX]; + cur_y = ((F32)y * sScaleY) + origin.mV[VY]; // Offset y by vertical alignment. switch (valign) { case TOP: - cur_y -= mAscender; + cur_y -= mFontFreetype->getAscenderHeight(); break; case BOTTOM: - cur_y += mDescender; + cur_y += mFontFreetype->getDescenderHeight(); break; case VCENTER: - cur_y -= ((mAscender - mDescender)/2.f); + cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f; break; case BASELINE: // Baseline, do nothing. @@ -502,10 +235,10 @@ S32 LLFontGL::render(const LLWString &wstr, case LEFT: break; case RIGHT: - cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)); + cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)); break; case HCENTER: - cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2; + cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2; break; default: break; @@ -514,19 +247,22 @@ S32 LLFontGL::render(const LLWString &wstr, cur_render_y = cur_y; cur_render_x = cur_x; - F32 start_x = cur_x; + F32 start_x = llround(cur_x); - F32 inv_width = 1.f / mFontBitmapCachep->getBitmapWidth(); - F32 inv_height = 1.f / mFontBitmapCachep->getBitmapHeight(); + const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); - const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL; + F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth(); + F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight(); + + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; BOOL draw_ellipses = FALSE; - if (use_ellipses && halign == LEFT) + if (use_ellipses) { // check for too long of a string - if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels) + S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX); + if (string_width > scaled_max_pixels) { // use four dots for ellipsis width to generate padding const LLWString dots(utf8str_to_wstring(std::string("...."))); @@ -536,185 +272,178 @@ S32 LLFontGL::render(const LLWString &wstr, } - // Remember last-used texture to avoid unnecesssary bind calls. - LLImageGL *last_bound_texture = NULL; + const LLFontGlyphInfo* next_glyph = NULL; + + const S32 GLYPH_BATCH_SIZE = 30; + LLVector3 vertices[GLYPH_BATCH_SIZE * 4]; + LLVector2 uvs[GLYPH_BATCH_SIZE * 4]; + LLColor4U colors[GLYPH_BATCH_SIZE * 4]; + + LLColor4U text_color(color); + S32 bitmap_num = -1; + S32 glyph_count = 0; for (i = begin_offset; i < begin_offset + length; i++) { llwchar wch = wstr[i]; - // Handle embedded characters first, if they're enabled. - // Embedded characters are a hack for notecards - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) { - LLImageGL* ext_image = ext_data->mImage; - const LLWString& label = ext_data->mLabel; - - F32 ext_height = (F32)ext_image->getHeight() * sScaleY; - - F32 ext_width = (F32)ext_image->getWidth() * sScaleX; - F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width; - - if (!label.empty()) - { - ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX; - } - - if (start_x + scaled_max_pixels < cur_x + ext_advance) - { - // Not enough room for this character. - break; - } - - if (last_bound_texture != ext_image) - { - gGL.getTexUnit(0)->bind(ext_image); - last_bound_texture = ext_image; - } - - // snap origin to whole screen pixel - const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX)); - const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight)); - - LLRectf uv_rect(0.f, 1.f, 1.f, 0.f); - LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y); - drawGlyph(screen_rect, uv_rect, LLColor4::white, style, shadow, drop_shadow_strength); - - if (!label.empty()) - { - gGL.pushMatrix(); - //glLoadIdentity(); - //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f); - //glScalef(sScaleX, sScaleY, 1.f); - getFontExtChar()->render(label, 0, - /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), - /*llfloor*/(cur_y / sScaleY), - color, - halign, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, - TRUE ); - gGL.popMatrix(); - } - - gGL.color4fv(color.mV); - - chars_drawn++; - cur_x += ext_advance; - if (((i + 1) < length) && wstr[i+1]) - { - cur_x += EXT_KERNING * sScaleX; - } - cur_render_x = cur_x; + fgi = mFontFreetype->getGlyphInfo(wch); } - else + if (!fgi) { - if (!hasGlyph(wch)) - { - addChar(wch); - } + llerrs << "Missing Glyph Info" << llendl; + break; + } + // Per-glyph bitmap texture. + S32 next_bitmap_num = fgi->mBitmapNum; + if (next_bitmap_num != bitmap_num) + { + bitmap_num = next_bitmap_num; + LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num); + gGL.getTexUnit(0)->bind(font_image); + } + + if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) + { + // Not enough room for this character. + break; + } - const LLFontGlyphInfo* fgi= getGlyphInfo(wch); - if (!fgi) - { - llerrs << "Missing Glyph Info" << llendl; - break; - } - // Per-glyph bitmap texture. - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum); - if (last_bound_texture != image_gl) + // Draw the text at the appropriate location + //Specify vertices and texture coordinates + LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width, + (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, + (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, + (fgi->mYBitmapOffset - PAD_UVY) * inv_height); + // snap glyph origin to whole screen pixel + LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing), + llround(cur_render_y + (F32)fgi->mYBearing), + llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, + llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); + + if (glyph_count >= GLYPH_BATCH_SIZE) + { + gGL.begin(LLRender::QUADS); { - gGL.getTexUnit(0)->bind(image_gl); - last_bound_texture = image_gl; + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); } + gGL.end(); - if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) - { - // Not enough room for this character. - break; - } + glyph_count = 0; + } - // Draw the text at the appropriate location - //Specify vertices and texture coordinates - LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width, - (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, - (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, - (fgi->mYBitmapOffset - PAD_UVY) * inv_height); - // snap glyph origin to whole screen pixel - LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing), - llround(cur_render_y + (F32)fgi->mYBearing), - llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, - llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); - - drawGlyph(screen_rect, uv_rect, color, style, shadow, drop_shadow_strength); + drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength); - chars_drawn++; - cur_x += fgi->mXAdvance; - cur_y += fgi->mYAdvance; + chars_drawn++; + cur_x += fgi->mXAdvance; + cur_y += fgi->mYAdvance; - llwchar next_char = wstr[i+1]; - if (next_char && (next_char < LAST_CHARACTER)) - { - // Kern this puppy. - if (!hasGlyph(next_char)) - { - addChar(next_char); - } - cur_x += getXKerning(wch, next_char); - } + llwchar next_char = wstr[i+1]; + if (next_char && (next_char < LAST_CHARACTER)) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); + } - // Round after kerning. - // Must do this to cur_x, not just to cur_render_x, otherwise you - // will squish sub-pixel kerned characters too close together. - // For example, "CCCCC" looks bad. - cur_x = (F32)llfloor(cur_x + 0.5f); - //cur_y = (F32)llfloor(cur_y + 0.5f); + // Round after kerning. + // Must do this to cur_x, not just to cur_render_x, otherwise you + // will squish sub-pixel kerned characters too close together. + // For example, "CCCCC" looks bad. + cur_x = (F32)llround(cur_x); + //cur_y = (F32)llround(cur_y); + + cur_render_x = cur_x; + cur_render_y = cur_y; + } - cur_render_x = cur_x; - cur_render_y = cur_y; - } + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); } + gGL.end(); + if (right_x) { - *right_x = cur_x / sScaleX; + *right_x = (cur_x - origin.mV[VX]) / sScaleX; } - if (style & UNDERLINE) + //FIXME: add underline as glyph? + if (style_to_add & UNDERLINE) { + F32 descender = mFontFreetype->getDescenderHeight(); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::LINES); - gGL.vertex2f(start_x, cur_y - (mDescender)); - gGL.vertex2f(cur_x, cur_y - (mDescender)); + gGL.vertex2f(start_x, cur_y - (descender)); + gGL.vertex2f(cur_x, cur_y - (descender)); gGL.end(); } - // *FIX: get this working in all alignment cases, etc. if (draw_ellipses) { + // recursively render ellipses at end of string // we've already reserved enough room - gGL.pushMatrix(); - //glLoadIdentity(); - //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f); - //glScalef(sScaleX, sScaleY, 1.f); + gGL.pushUIMatrix(); renderUTF8(std::string("..."), 0, - cur_x / sScaleX, (F32)y, + (cur_x - origin.mV[VX]) / sScaleX, (F32)y, color, LEFT, valign, - style, + style_to_add, shadow, S32_MAX, max_pixels, right_x, FALSE); - gGL.popMatrix(); + gGL.popUIMatrix(); } - gGL.popMatrix(); + gGL.popUIMatrix(); return chars_drawn; } +S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const +{ + return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +} + +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const +{ + return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses); +} + +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const +{ + return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +} + +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const +{ + return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE); +} + +// font metrics - override for LLFontFreetype that returns units of virtual pixels +F32 LLFontGL::getLineHeight() const +{ + return (F32)llround(mFontFreetype->getLineHeight() / sScaleY); +} + +F32 LLFontGL::getAscenderHeight() const +{ + return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY); +} + +F32 LLFontGL::getDescenderHeight() const +{ + return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY); +} S32 LLFontGL::getWidth(const std::string& utf8text) const { @@ -727,15 +456,15 @@ S32 LLFontGL::getWidth(const llwchar* wchars) const return getWidth(wchars, 0, S32_MAX); } -S32 LLFontGL::getWidth(const std::string& utf8text, const S32 begin_offset, const S32 max_chars) const +S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const { LLWString wtext = utf8str_to_wstring(utf8text); return getWidth(wtext.c_str(), begin_offset, max_chars); } -S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const +S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars) const { - F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded); + F32 width = getWidthF32(wchars, begin_offset, max_chars); return llround(width); } @@ -750,62 +479,65 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars) const return getWidthF32(wchars, 0, S32_MAX); } -F32 LLFontGL::getWidthF32(const std::string& utf8text, const S32 begin_offset, const S32 max_chars ) const +F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const { LLWString wtext = utf8str_to_wstring(utf8text); return getWidthF32(wtext.c_str(), begin_offset, max_chars); } -F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const +F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const { - const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL; + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; F32 cur_x = 0; const S32 max_index = begin_offset + max_chars; - for (S32 i = begin_offset; i < max_index; i++) + + const LLFontGlyphInfo* next_glyph = NULL; + + F32 width_padding = 0.f; + for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++) { - const llwchar wch = wchars[i]; - if (wch == 0) + llwchar wch = wchars[i]; + + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) { - break; // done + fgi = mFontFreetype->getGlyphInfo(wch); } - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) - { - // Handle crappy embedded hack - cur_x += getEmbeddedCharAdvance(ext_data); - if( ((i+1) < max_chars) && (i+1 < max_index)) - { - cur_x += EXT_KERNING * sScaleX; - } - } - else - { - cur_x += getXAdvance(wch); - llwchar next_char = wchars[i+1]; + F32 advance = mFontFreetype->getXAdvance(fgi); - if (((i + 1) < max_chars) - && next_char - && (next_char < LAST_CHARACTER)) - { - // Kern this puppy. - cur_x += getXKerning(wch, next_char); - } + // for the last character we want to measure the greater of its width and xadvance values + // so keep track of the difference between these values for the each character we measure + // so we can fix things up at the end + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - advance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character + + cur_x += advance; + llwchar next_char = wchars[i+1]; + + if (((i + 1) < begin_offset + max_chars) + && next_char + && (next_char < LAST_CHARACTER)) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + cur_x = (F32)llround(cur_x); } + // add in extra pixels for last character's width past its xadvance + cur_x += width_padding; + return cur_x / sScaleX; } - - // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels -S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, - BOOL end_on_word_boundary, const BOOL use_embedded, - F32* drawn_pixels) const +S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const { if (!wchars || !wchars[0] || max_chars == 0) { @@ -822,7 +554,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch S32 start_of_last_word = 0; BOOL in_word = FALSE; - F32 scaled_max_pixels = (F32)llceil(max_pixels * sScaleX); + // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point + F32 scaled_max_pixels = ceil(max_pixels * sScaleX); + F32 width_padding = 0.f; + + LLFontGlyphInfo* next_glyph = NULL; S32 i; for (i=0; (i < max_chars); i++) @@ -835,100 +571,92 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch break; } - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + if (in_word) { - if (in_word) - { - in_word = FALSE; - } - else - { - start_of_last_word = i; - } - cur_x += getEmbeddedCharAdvance(ext_data); - - if (scaled_max_pixels < cur_x) + if (iswspace(wch)) { - clip = TRUE; - break; + if(wch !=(0x00A0)) + { + in_word = FALSE; + } } - - if (((i+1) < max_chars) && wchars[i+1]) + if (iswindividual(wch)) { - cur_x += EXT_KERNING * sScaleX; - } - - if( scaled_max_pixels < cur_x ) - { - clip = TRUE; - break; - } - } - else - { - if (in_word) - { - if (iswspace(wch)) + if (iswpunct(wchars[i+1])) { - if(wch !=(0x00A0)) - { - in_word = FALSE; - } + in_word=TRUE; } - if (iswindividual(wch)) + else { - if (iswpunct(wchars[i+1])) - { - in_word=TRUE; - } - else - { - in_word=FALSE; - start_of_last_word = i; - } + in_word=FALSE; + start_of_last_word = i; } } - else + } + else + { + start_of_last_word = i; + if (!iswspace(wch)||!iswindividual(wch)) { - start_of_last_word = i; - if (!iswspace(wch)||!iswindividual(wch)) - { - in_word = TRUE; - } + in_word = TRUE; } + } + + LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } - cur_x += getXAdvance(wch); - - if (scaled_max_pixels < cur_x) - { - clip = TRUE; - break; - } + // account for glyphs that run beyond the starting point for the next glyphs + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - fgi->mXAdvance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character - if (((i+1) < max_chars) && wchars[i+1]) - { - // Kern this puppy. - cur_x += getXKerning(wch, wchars[i+1]); - } + cur_x += fgi->mXAdvance; + + // clip if current character runs past scaled_max_pixels (using width_padding) + if (scaled_max_pixels < cur_x + width_padding) + { + clip = TRUE; + break; } + + if (((i+1) < max_chars) && wchars[i+1]) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); + } + // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + cur_x = llround(cur_x); drawn_x = cur_x; } - if( clip && end_on_word_boundary && (start_of_last_word != 0) ) - { - i = start_of_last_word; - } - if (drawn_pixels) + if( clip ) { - *drawn_pixels = drawn_x; + switch (end_on_word_boundary) + { + case ONLY_WORD_BOUNDARIES: + i = start_of_last_word; + break; + case WORD_BOUNDARY_IF_POSSIBLE: + if (start_of_last_word != 0) + { + i = start_of_last_word; + } + break; + default: + case ANYWHERE: + // do nothing + break; + } } return i; } - S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const { if (!wchars || !wchars[0] || max_chars == 0) @@ -946,15 +674,20 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ { llwchar wch = wchars[i]; - const embedded_data_t* ext_data = getEmbeddedCharData(wch); - F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : getXAdvance(wch); + const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); - if( scaled_max_pixels < (total_width + char_width) ) + // last character uses character width, since the whole character needs to be visible + // other characters just use advance + F32 width = (i == start) + ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character + : fgi->mXAdvance; // use advance for all other characters + + if( scaled_max_pixels < (total_width + width) ) { break; } - total_width += char_width; + total_width += width; drawable_chars++; if( max_chars >= 0 && drawable_chars >= max_chars ) @@ -965,18 +698,27 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ if ( i > 0 ) { // kerning - total_width += ext_data ? (EXT_KERNING * sScaleX) : getXKerning(wchars[i-1], wch); + total_width += mFontFreetype->getXKerning(wchars[i-1], wch); } // Round after kerning. total_width = llround(total_width); } - return start_pos - drawable_chars; + if (drawable_chars == 0) + { + return start_pos; // just draw last character + } + else + { + // if only 1 character is drawable, we want to return start_pos as the first character to draw + // if 2 are drawable, return start_pos and character before start_pos, etc. + return start_pos + 1 - drawable_chars; + } + } - -S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const +S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const { if (!wchars || !wchars[0] || max_chars == 0) { @@ -984,255 +726,189 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, } F32 cur_x = 0; - S32 pos = 0; target_x *= sScaleX; // max_chars is S32_MAX by default, so make sure we don't get overflow - const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars); + const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1); F32 scaled_max_pixels = max_pixels * sScaleX; + + const LLFontGlyphInfo* next_glyph = NULL; - for (S32 i = begin_offset; (i < max_index); i++) + S32 pos; + for (pos = begin_offset; pos < max_index; pos++) { - llwchar wch = wchars[i]; + llwchar wch = wchars[pos]; if (!wch) { break; // done } - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + + const LLFontGlyphInfo* glyph = next_glyph; + next_glyph = NULL; + if(!glyph) { - F32 ext_advance = getEmbeddedCharAdvance(ext_data); - - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + ext_advance/2) - { - break; - } - } - else - { - if (target_x < cur_x + ext_advance) - { - break; - } - } + glyph = mFontFreetype->getGlyphInfo(wch); + } + + F32 char_width = mFontFreetype->getXAdvance(glyph); - if (scaled_max_pixels < cur_x + ext_advance) + if (round) + { + // Note: if the mouse is on the left half of the character, the pick is to the character's left + // If it's on the right half, the pick is to the right. + if (target_x < cur_x + char_width*0.5f) { break; } - - pos++; - cur_x += ext_advance; - - if (((i + 1) < max_index) - && (wchars[(i + 1)])) - { - cur_x += EXT_KERNING * sScaleX; - } - // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); } - else + else if (target_x < cur_x + char_width) { - F32 char_width = getXAdvance(wch); + break; + } - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + char_width*0.5f) - { - break; - } - } - else if (target_x < cur_x + char_width) - { - break; - } + if (scaled_max_pixels < cur_x + char_width) + { + break; + } - if (scaled_max_pixels < cur_x + char_width) - { - break; - } + cur_x += char_width; - pos++; - cur_x += char_width; + if (((pos + 1) < max_index) + && (wchars[(pos + 1)])) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]); + cur_x += mFontFreetype->getXKerning(glyph, next_glyph); + } - if (((i + 1) < max_index) - && (wchars[(i + 1)])) - { - llwchar next_char = wchars[i + 1]; - // Kern this puppy. - cur_x += getXKerning(wch, next_char); - } - // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); - } + // Round after kerning. + cur_x = llround(cur_x); } - return pos; + return llmin(max_chars, pos - begin_offset); } - -const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const +const LLFontDescriptor& LLFontGL::getFontDesc() const { - // Handle crappy embedded hack - embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch); - if (iter != mEmbeddedChars.end()) - { - return iter->second; - } - return NULL; + return mFontDescriptor; } - -F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const +// static +void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures) { - const LLWString& label = ext_data->mLabel; - LLImageGL* ext_image = ext_data->mImage; + sVertDPI = (F32)llfloor(screen_dpi * y_scale); + sHorizDPI = (F32)llfloor(screen_dpi * x_scale); + sScaleX = x_scale; + sScaleY = y_scale; + sAppDir = app_dir; - F32 ext_width = (F32)ext_image->getWidth(); - if( !label.empty() ) + // Font registry init + if (!sFontRegistry) { - ext_width += (EXT_X_BEARING + getFontExtChar()->getWidthF32(label.c_str())) * sScaleX; + sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures); + sFontRegistry->parseFontInfo("fonts.xml"); + } + else + { + sFontRegistry->reset(); } - - return (EXT_X_BEARING * sScaleX) + ext_width; -} - - -void LLFontGL::clearEmbeddedChars() -{ - for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer()); - mEmbeddedChars.clear(); } -void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label ) const +// Force standard fonts to get generated up front. +// This is primarily for error detection purposes. +// Don't do this during initClass because it can be slow and we want to get +// the viewer window on screen first. JC +// static +bool LLFontGL::loadDefaultFonts() { - LLWString wlabel = utf8str_to_wstring(label); - addEmbeddedChar(wc, image, wlabel); + bool succ = true; + succ &= (NULL != getFontSansSerifSmall()); + succ &= (NULL != getFontSansSerif()); + succ &= (NULL != getFontSansSerifBig()); + succ &= (NULL != getFontSansSerifHuge()); + succ &= (NULL != getFontSansSerifBold()); + succ &= (NULL != getFontMonospace()); + succ &= (NULL != getFontExtChar()); + return succ; } -void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel ) const +// static +void LLFontGL::destroyDefaultFonts() { - embedded_data_t* ext_data = new embedded_data_t(image, wlabel); - mEmbeddedChars[wc] = ext_data; + // Remove the actual fonts. + delete sFontRegistry; + sFontRegistry = NULL; } -void LLFontGL::removeEmbeddedChar( llwchar wc ) const +//static +void LLFontGL::destroyAllGL() { - embedded_map_t::iterator iter = mEmbeddedChars.find(wc); - if (iter != mEmbeddedChars.end()) + if (sFontRegistry) { - delete iter->second; - mEmbeddedChars.erase(wc); + sFontRegistry->destroyGL(); } } - -void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const +// static +U8 LLFontGL::getStyleFromString(const std::string &style) { - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mRight), - llfont_round_y(screen_rect.mTop)); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft), - llfont_round_y(screen_rect.mTop)); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), - llfont_round_y(screen_rect.mBottom)); - - gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), - llfont_round_y(screen_rect.mBottom)); + S32 ret = 0; + if (style.find("NORMAL") != style.npos) + { + ret |= NORMAL; + } + if (style.find("BOLD") != style.npos) + { + ret |= BOLD; + } + if (style.find("ITALIC") != style.npos) + { + ret |= ITALIC; + } + if (style.find("UNDERLINE") != style.npos) + { + ret |= UNDERLINE; + } + return ret; } -void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const +// static +std::string LLFontGL::getStringFromStyle(U8 style) { - F32 slant_offset; - slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f); - - gGL.begin(LLRender::QUADS); + std::string style_string; + if (style & NORMAL) { - //FIXME: bold and drop shadow are mutually exclusive only for convenience - //Allow both when we need them. - if (style & BOLD) - { - gGL.color4fv(color.mV); - for (S32 pass = 0; pass < 2; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } - } - else if (shadow == DROP_SHADOW_SOFT) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH; - gGL.color4fv(shadow_color.mV); - for (S32 pass = 0; pass < 5; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - switch(pass) - { - case 0: - screen_rect_offset.translate(-1.f, -1.f); - break; - case 1: - screen_rect_offset.translate(1.f, -1.f); - break; - case 2: - screen_rect_offset.translate(1.f, 1.f); - break; - case 3: - screen_rect_offset.translate(-1.f, 1.f); - break; - case 4: - screen_rect_offset.translate(0, -2.f); - break; - } - - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else if (shadow == DROP_SHADOW) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength; - gGL.color4fv(shadow_color.mV); - LLRectf screen_rect_shadow = screen_rect; - screen_rect_shadow.translate(1.f, -1.f); - renderQuad(screen_rect_shadow, uv_rect, slant_offset); - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else // normal rendering - { - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - + style_string += "|NORMAL"; } - gGL.end(); + if (style & BOLD) + { + style_string += "|BOLD"; + } + if (style & ITALIC) + { + style_string += "|ITALIC"; + } + if (style & UNDERLINE) + { + style_string += "|UNDERLINE"; + } + return style_string; } +// static std::string LLFontGL::nameFromFont(const LLFontGL* fontp) { - return fontp->getFontDesc().getName(); + return fontp->mFontDescriptor.getName(); +} + + +// static +std::string LLFontGL::sizeFromFont(const LLFontGL* fontp) +{ + return fontp->mFontDescriptor.getSize(); } // static @@ -1297,3 +973,244 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name) //else leave baseline return gl_vfont_align; } + +//static +LLFontGL* LLFontGL::getFontMonospace() +{ + return getFont(LLFontDescriptor("Monospace","Monospace",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifSmall() +{ + return getFont(LLFontDescriptor("SansSerif","Small",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerif() +{ + return getFont(LLFontDescriptor("SansSerif","Medium",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifBig() +{ + return getFont(LLFontDescriptor("SansSerif","Large",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifHuge() +{ + return getFont(LLFontDescriptor("SansSerif","Huge",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifBold() +{ + return getFont(LLFontDescriptor("SansSerif","Medium",BOLD)); +} + +//static +LLFontGL* LLFontGL::getFontExtChar() +{ + return getFontSansSerif(); +} + +//static +LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) +{ + return sFontRegistry->getFont(desc); +} + +//static +LLFontGL* LLFontGL::getFontByName(const std::string& name) +{ + // check for most common fonts first + if (name == "SANSSERIF") + { + return getFontSansSerif(); + } + else if (name == "SANSSERIF_SMALL") + { + return getFontSansSerifSmall(); + } + else if (name == "SANSSERIF_BIG") + { + return getFontSansSerifBig(); + } + else if (name == "SMALL" || name == "OCRA") + { + // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? + // Does "SMALL" mean "SERIF"? + return getFontMonospace(); + } + else + { + return NULL; + } +} + +//static +LLFontGL* LLFontGL::getFontDefault() +{ + return getFontSansSerif(); // Fallback to sans serif as default font +} + + +// static +std::string LLFontGL::getFontPathSystem() +{ + std::string system_path; + + // Try to figure out where the system's font files are stored. + char *system_root = NULL; +#if LL_WINDOWS + system_root = getenv("SystemRoot"); /* Flawfinder: ignore */ + if (!system_root) + { + llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl; + } +#endif + + if (system_root) + { + system_path = llformat("%s/fonts/", system_root); + } + else + { +#if LL_WINDOWS + // HACK for windows 98/Me + system_path = "/WINDOWS/FONTS/"; +#elif LL_DARWIN + // HACK for Mac OS X + system_path = "/System/Library/Fonts/"; +#endif + } + return system_path; +} + + +// static +std::string LLFontGL::getFontPathLocal() +{ + std::string local_path; + + // Backup files if we can't load from system fonts directory. + // We could store this in an end-user writable directory to allow + // end users to switch fonts. + if (LLFontGL::sAppDir.length()) + { + // use specified application dir to look for fonts + local_path = LLFontGL::sAppDir + "/fonts/"; + } + else + { + // assume working directory is executable directory + local_path = "./fonts/"; + } + return local_path; +} + +LLFontGL::LLFontGL(const LLFontGL &source) +{ + llerrs << "Not implemented!" << llendl; +} + +LLFontGL &LLFontGL::operator=(const LLFontGL &source) +{ + llerrs << "Not implemented" << llendl; + return *this; +} + +void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const +{ + S32 index = 0; + + vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mTop), 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + colors_out[index] = color; + index++; + + vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mTop), 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); + colors_out[index] = color; + index++; + + vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mBottom), 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); + colors_out[index] = color; + index++; + + vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mBottom), 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); + colors_out[index] = color; +} + +void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const +{ + F32 slant_offset; + slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f); + + //FIXME: bold and drop shadow are mutually exclusive only for convenience + //Allow both when we need them. + if (style & BOLD) + { + for (S32 pass = 0; pass < 2; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset); + glyph_count++; + } + } + else if (shadow == DROP_SHADOW_SOFT) + { + LLColor4U shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH); + for (S32 pass = 0; pass < 5; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + switch(pass) + { + case 0: + screen_rect_offset.translate(-1.f, -1.f); + break; + case 1: + screen_rect_offset.translate(1.f, -1.f); + break; + case 2: + screen_rect_offset.translate(1.f, 1.f); + break; + case 3: + screen_rect_offset.translate(-1.f, 1.f); + break; + case 4: + screen_rect_offset.translate(0, -2.f); + break; + } + + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset); + glyph_count++; + } + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else if (shadow == DROP_SHADOW) + { + LLColor4U shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength); + LLRectf screen_rect_shadow = screen_rect; + screen_rect_shadow.translate(1.f, -1.f); + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset); + glyph_count++; + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else // normal rendering + { + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } +} diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 204c6908af..dc8d848ed2 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -3,31 +3,25 @@ * @author Doug Soo * @brief Wrapper around FreeType * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,21 +29,21 @@ #define LL_LLFONTGL_H #include "llcoord.h" -#include "llfont.h" #include "llfontregistry.h" +#include "llimagegl.h" #include "llpointer.h" #include "llrect.h" #include "v2math.h" class LLColor4; -class LLImageGL; // Key used to request a font. class LLFontDescriptor; +class LLFontFreetype; // Structure used to store previously requested fonts. class LLFontRegistry; -class LLFontGL : public LLFont +class LLFontGL { public: enum HAlign @@ -72,11 +66,10 @@ public: enum StyleFlags { // text style to render. May be combined (these are bit flags) - // TODO:: Maybe change the value to 0x01 << 0 for 1 0x01 << 1 for 2, 0x01 << 2 for 4 - NORMAL = 0, - BOLD = 1, - ITALIC = 2, - UNDERLINE = 4 + NORMAL = 0x00, + BOLD = 0x01, + ITALIC = 0x02, + UNDERLINE = 0x04 }; enum ShadowType @@ -85,132 +78,92 @@ public: DROP_SHADOW, DROP_SHADOW_SOFT }; - - // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" - static U8 getStyleFromString(const std::string &style); LLFontGL(); - LLFontGL(const LLFontGL &source); ~LLFontGL(); - void init(); // Internal init, or reinitialization + void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font. - LLFontGL &operator=(const LLFontGL &source); + void destroyGL(); - static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, - const std::string& app_dir, - const std::vector<std::string>& xui_paths, - bool create_gl_textures = true); + BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback); - // Load sans-serif, sans-serif-small, etc. - // Slow, requires multiple seconds to load fonts. - static bool loadDefaultFonts(); - static void destroyDefaultFonts(); - static void destroyAllGL(); - void destroyGL(); + S32 render(const LLWString &text, S32 begin_offset, + const LLRect& rect, + const LLColor4 &color, + HAlign halign = LEFT, VAlign valign = BASELINE, + U8 style = NORMAL, ShadowType shadow = NO_SHADOW, + S32 max_chars = S32_MAX, + F32* right_x=NULL, + BOOL use_ellipses = FALSE) const; - /* virtual*/ BOOL loadFace(const std::string& filename, - const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, - const S32 components, BOOL is_fallback); + S32 render(const LLWString &text, S32 begin_offset, + F32 x, F32 y, + const LLColor4 &color, + HAlign halign = LEFT, VAlign valign = BASELINE, + U8 style = NORMAL, ShadowType shadow = NO_SHADOW, + S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, + F32* right_x=NULL, + BOOL use_ellipses = FALSE) const; + S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const; - S32 renderUTF8(const std::string &text, const S32 begin_offset, - S32 x, S32 y, - const LLColor4 &color) const - { - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, - LEFT, BASELINE, NORMAL, NO_SHADOW, - S32_MAX, S32_MAX, NULL, FALSE); - } - - S32 renderUTF8(const std::string &text, const S32 begin_offset, - S32 x, S32 y, - const LLColor4 &color, - HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const - { - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, - halign, valign, style, shadow, - S32_MAX, S32_MAX, NULL, FALSE); - } - // renderUTF8 does a conversion, so is slower! - S32 renderUTF8(const std::string &text, - S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color, - HAlign halign, - VAlign valign, - U8 style, - ShadowType shadow, - S32 max_chars, - S32 max_pixels, - F32* right_x, - BOOL use_ellipses) const; - - S32 render(const LLWString &text, const S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color) const - { - return render(text, begin_offset, x, y, color, - LEFT, BASELINE, NORMAL, NO_SHADOW, - S32_MAX, S32_MAX, NULL, FALSE, FALSE); - } - + S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; - S32 render(const LLWString &text, - S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color, - HAlign halign = LEFT, - VAlign valign = BASELINE, - U8 style = NORMAL, - ShadowType shadow = NO_SHADOW, - S32 max_chars = S32_MAX, - S32 max_pixels = S32_MAX, - F32* right_x=NULL, - BOOL use_embedded = FALSE, - BOOL use_ellipses = FALSE) const; - - // font metrics - override for LLFont that returns units of virtual pixels - /*virtual*/ F32 getLineHeight() const { return (F32)llround(mLineHeight / sScaleY); } - /*virtual*/ F32 getAscenderHeight() const { return (F32)llround(mAscender / sScaleY); } - /*virtual*/ F32 getDescenderHeight() const { return (F32)llround(mDescender / sScaleY); } - - virtual S32 getWidth(const std::string& utf8text) const; - virtual S32 getWidth(const llwchar* wchars) const; - virtual S32 getWidth(const std::string& utf8text, const S32 offset, const S32 max_chars ) const; - virtual S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const; + // font metrics - override for LLFontFreetype that returns units of virtual pixels + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; + + S32 getWidth(const std::string& utf8text) const; + S32 getWidth(const llwchar* wchars) const; + S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars ) const; + S32 getWidth(const llwchar* wchars, S32 offset, S32 max_chars) const; - virtual F32 getWidthF32(const std::string& utf8text) const; - virtual F32 getWidthF32(const llwchar* wchars) const; - virtual F32 getWidthF32(const std::string& text, const S32 offset, const S32 max_chars ) const; - virtual F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const; + F32 getWidthF32(const std::string& utf8text) const; + F32 getWidthF32(const llwchar* wchars) const; + F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const; + F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars) const; // The following are called often, frequently with large buffers, so do not use a string interface // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels - virtual S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, - BOOL end_on_word_boundary = FALSE, const BOOL use_embedded = FALSE, - F32* drawn_pixels = NULL) const; + typedef enum e_word_wrap_style + { + ONLY_WORD_BOUNDARIES, + WORD_BOUNDARY_IF_POSSIBLE, + ANYWHERE + } EWordWrapStyle ; + S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE) const; // Returns the index of the first complete characters from text that can be drawn in max_pixels // given that the character at start_pos should be the last character (or as close to last as possible). - virtual S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; + S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars) - virtual S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset, - F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, - BOOL round = TRUE, BOOL use_embedded = FALSE) const; + S32 charFromPixelOffset(const llwchar* wchars, S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE) const; + + const LLFontDescriptor& getFontDesc() const; - LLImageGL *getImageGL() const; + static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures = true); - void addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label) const; - void addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& label) const; - void removeEmbeddedChar( llwchar wc ) const; + // Load sans-serif, sans-serif-small, etc. + // Slow, requires multiple seconds to load fonts. + static bool loadDefaultFonts(); + static void destroyDefaultFonts(); + static void destroyAllGL(); + + // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" + static U8 getStyleFromString(const std::string &style); + static std::string getStringFromStyle(U8 style); static std::string nameFromFont(const LLFontGL* fontp); + static std::string sizeFromFont(const LLFontGL* fontp); static std::string nameFromHAlign(LLFontGL::HAlign align); static LLFontGL::HAlign hAlignFromName(const std::string& name); @@ -218,28 +171,7 @@ public: static std::string nameFromVAlign(LLFontGL::VAlign align); static LLFontGL::VAlign vAlignFromName(const std::string& name); - static void setFontDisplay(BOOL flag) { sDisplayFont = flag ; } - -protected: - struct embedded_data_t - { - embedded_data_t(LLImageGL* image, const LLWString& label) : mImage(image), mLabel(label) {} - LLPointer<LLImageGL> mImage; - LLWString mLabel; - }; - const embedded_data_t* getEmbeddedCharData(const llwchar wch) const; - F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const; - void clearEmbeddedChars(); - void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const; - void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; - -public: - static F32 sVertDPI; - static F32 sHorizDPI; - static F32 sScaleX; - static F32 sScaleY; - static BOOL sDisplayFont ; - static std::string sAppDir; // For loading fonts + static void setFontDisplay(BOOL flag) { sDisplayFont = flag; } static LLFontGL* getFontMonospace(); static LLFontGL* getFontSansSerifSmall(); @@ -251,33 +183,39 @@ public: static LLFontGL* getFont(const LLFontDescriptor& desc); // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" static LLFontGL* getFontByName(const std::string& name); + static LLFontGL* getFontDefault(); // default fallback font + + static std::string getFontPathLocal(); + static std::string getFontPathSystem(); + + static LLCoordFont sCurOrigin; + static std::vector<LLCoordFont> sOriginStack; static LLColor4 sShadowColor; + static F32 sVertDPI; + static F32 sHorizDPI; + static F32 sScaleX; + static F32 sScaleY; + static BOOL sDisplayFont ; + static std::string sAppDir; // For loading fonts + +private: + friend class LLFontRegistry; friend class LLTextBillboard; friend class LLHUDText; -protected: - /*virtual*/ BOOL addChar(const llwchar wch) const; + LLFontGL(const LLFontGL &source); + LLFontGL &operator=(const LLFontGL &source); -protected: - typedef std::map<llwchar,embedded_data_t*> embedded_map_t; - mutable embedded_map_t mEmbeddedChars; - - LLFontDescriptor mFontDesc; + LLFontDescriptor mFontDescriptor; + LLPointer<LLFontFreetype> mFontFreetype; + + void renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const; + void drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; // Registry holds all instantiated fonts. static LLFontRegistry* sFontRegistry; - -public: - static std::string getFontPathLocal(); - static std::string getFontPathSystem(); - - static LLCoordFont sCurOrigin; - static std::vector<LLCoordFont> sOriginStack; - - const LLFontDescriptor &getFontDesc() const { return mFontDesc; } - void setFontDesc(const LLFontDescriptor& font_desc) { mFontDesc = font_desc; } }; #endif diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 18e4a6915d..4d22eba3d9 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -3,38 +3,33 @@ * @author Brad Payne * @brief Storage for fonts. * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llgl.h" -#include "llfontregistry.h" +#include "llfontfreetype.h" #include "llfontgl.h" +#include "llfontregistry.h" #include <boost/tokenizer.hpp> #include "llcontrol.h" #include "lldir.h" @@ -104,7 +99,7 @@ bool removeSubString(std::string& str, const std::string& substr) size_t pos = str.find(substr); if (pos != string::npos) { - str.replace(pos,substr.length(),(const char *)NULL, 0); + str.erase(pos, substr.size()); return true; } return false; @@ -379,10 +374,20 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) LLFontDescriptor nearest_exact_desc = *match_desc; nearest_exact_desc.setSize(norm_desc.getSize()); font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc); - if (it != mFontMap.end()) + // If we fail to find a font in the fonts directory, it->second might be NULL. + // We shouldn't construcnt a font with a NULL mFontFreetype. + // This may not be the best solution, but it at least prevents a crash. + if (it != mFontMap.end() && it->second != NULL) { llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl; - return it->second; + + // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor + LLFontGL *font = new LLFontGL; + font->mFontDescriptor = desc; + font->mFontFreetype = it->second->mFontFreetype; + mFontMap[desc] = font; + + return font; } // Build list of font names to look for. @@ -410,10 +415,11 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) llwarns << "createFont failed, no file names specified" << llendl; return NULL; } - LLFontList *fontlistp = new LLFontList; + + LLFontFreetype::font_vector_t fontlist; LLFontGL *result = NULL; - // Snarf all fonts we can into fontlistp. First will get pulled + // Snarf all fonts we can into fontlist. First will get pulled // off the list and become the "head" font, set to non-fallback. // Rest will consitute the fallback list. BOOL is_first_found = TRUE; @@ -455,23 +461,29 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) is_first_found = false; } else - fontlistp->addAtEnd(fontp); + { + fontlist.push_back(fontp->mFontFreetype); + delete fontp; + fontp = NULL; + } } } - if (result && !fontlistp->empty()) + + if (result && !fontlist.empty()) { - result->setFallbackFont(fontlistp); + result->mFontFreetype->setFallbackFonts(fontlist); } - norm_desc.setStyle(match_desc->getStyle()); if (result) - result->setFontDesc(norm_desc); - - if (!result) + { + result->mFontDescriptor = desc; + } + else { llwarns << "createFont failed in some way" << llendl; } - mFontMap[norm_desc] = result; + + mFontMap[desc] = result; return result; } @@ -511,21 +523,19 @@ void LLFontRegistry::destroyGL() } } -LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& orig_desc) +LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& desc) { - LLFontDescriptor norm_desc = orig_desc.normalize(); - - font_reg_map_t::iterator it = mFontMap.find(norm_desc); + font_reg_map_t::iterator it = mFontMap.find(desc); if (it != mFontMap.end()) return it->second; else { - LLFontGL *fontp = createFont(orig_desc); + LLFontGL *fontp = createFont(desc); if (!fontp) { - llwarns << "getFont failed, name " << orig_desc.getName() - <<" style=[" << ((S32) orig_desc.getStyle()) << "]" - << " size=[" << orig_desc.getSize() << "]" << llendl; + llwarns << "getFont failed, name " << desc.getName() + <<" style=[" << ((S32) desc.getStyle()) << "]" + << " size=[" << desc.getSize() << "]" << llendl; } return fontp; } @@ -653,3 +663,8 @@ void LLFontRegistry::dump() } } } + +const string_vec_t& LLFontRegistry::getUltimateFallbackList() const +{ + return mUltimateFallbackList; +} diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index 198ca0b920..8b06191c56 100644 --- a/indra/llrender/llfontregistry.h +++ b/indra/llrender/llfontregistry.h @@ -3,31 +3,25 @@ * @author Brad Payne * @brief Storage for fonts. * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -98,7 +92,7 @@ public: void dump(); - const string_vec_t& getUltimateFallbackList() const { return mUltimateFallbackList; } + const string_vec_t& getUltimateFallbackList() const; private: LLFontGL *createFont(const LLFontDescriptor& desc); diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 7e1df0e565..c0edd92bc1 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2,31 +2,25 @@ * @file llgl.cpp * @brief LLGL implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,6 +58,8 @@ BOOL gDebugSession = FALSE; BOOL gDebugGL = FALSE; BOOL gClothRipple = FALSE; BOOL gNoRender = FALSE; +BOOL gGLActive = FALSE; + std::ofstream gFailLog; @@ -107,6 +103,7 @@ LLMatrix4 gGLObliqueProjectionInverse; #define LL_GL_NAME_POOLING 0 LLGLNamePool::pool_list_t LLGLNamePool::sInstances; +std::list<LLGLUpdate*> LLGLUpdate::sGLQ; #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS // ATI prototypes @@ -182,6 +179,9 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = // GL_EXT_framebuffer_blit PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL; +// GL_EXT_blend_func_separate +PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL; + // GL_ARB_draw_buffers PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL; @@ -321,6 +321,7 @@ LLGLManager::LLGLManager() : mHasCompressedTextures(FALSE), mHasFramebufferObject(FALSE), mHasFramebufferMultisample(FALSE), + mHasBlendFuncSeparate(FALSE), mHasVertexBufferObject(FALSE), mHasPBuffer(FALSE), @@ -329,6 +330,8 @@ LLGLManager::LLGLManager() : mHasFragmentShader(FALSE), mHasOcclusionQuery(FALSE), mHasPointParameters(FALSE), + mHasDrawBuffers(FALSE), + mHasTextureRectangle(FALSE), mHasAnisotropic(FALSE), mHasARBEnvCombine(FALSE), @@ -347,6 +350,8 @@ LLGLManager::LLGLManager() : mHasSeparateSpecularColor(FALSE), + mDebugGPU(FALSE), + mDriverVersionMajor(1), mDriverVersionMinor(0), mDriverVersionRelease(0), @@ -514,11 +519,23 @@ bool LLGLManager::initGL() return false; } + setToDebugGPU(); initGLStates(); return true; } +void LLGLManager::setToDebugGPU() +{ + //"MOBILE INTEL(R) 965 EXPRESS CHIP", + if (mGLRenderer.find("INTEL") != std::string::npos && mGLRenderer.find("965") != std::string::npos) + { + mDebugGPU = TRUE ; + } + + return ; +} + void LLGLManager::getGLInfo(LLSD& info) { info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR)); @@ -590,8 +607,6 @@ void LLGLManager::shutdownGL() // 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 @@ -630,6 +645,11 @@ void LLGLManager::initExtensions() #else mHasDrawBuffers = FALSE; # endif +# if GL_EXT_blend_func_separate + mHasBlendFuncSeparate = TRUE; +#else + mHasBlendFuncSeparate = FALSE; +# endif mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -656,6 +676,7 @@ void LLGLManager::initExtensions() && ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts); mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); + mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); @@ -670,7 +691,7 @@ void LLGLManager::initExtensions() llinfos << "initExtensions() checking shell variables to adjust features..." << llendl; // Our extension support for the Linux Client is very young with some // potential driver gotchas, so offer a semi-secret way to turn it off. - if (getenv("LL_GL_NOEXT")) /* Flawfinder: ignore */ + if (getenv("LL_GL_NOEXT")) { //mHasMultitexture = FALSE; // NEEDED! mHasARBEnvCombine = FALSE; @@ -679,6 +700,7 @@ void LLGLManager::initExtensions() mHasFramebufferObject = FALSE; mHasFramebufferMultisample = FALSE; mHasDrawBuffers = FALSE; + mHasBlendFuncSeparate = FALSE; mHasMipMapGeneration = FALSE; mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; @@ -703,6 +725,7 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasBlendFuncSeparate = FALSE; LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL; } if (getenv("LL_GL_BLACKLIST")) /* Flawfinder: ignore */ @@ -731,7 +754,8 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE; if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE; - + if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S + } #endif // LL_LINUX || LL_SOLARIS @@ -779,6 +803,14 @@ void LLGLManager::initExtensions() { LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL; } + if (!mHasBlendFuncSeparate) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL; + } + if (!mHasDrawBuffers) + { + LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_draw_buffers" << LL_ENDL; + } // Disable certain things due to known bugs if (mIsIntel && mHasMipMapGeneration) @@ -849,6 +881,10 @@ void LLGLManager::initExtensions() { glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB"); } + if (mHasBlendFuncSeparate) + { + glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT"); + } #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS // This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); @@ -1011,14 +1047,9 @@ void flush_glerror() glGetError(); } -void assert_glerror() +void do_assert_glerror() { - if (gNoRender || !gDebugGL) - { - return; - } - - if (!gGLManager.mInited) + if (LL_UNLIKELY(!gGLManager.mInited)) { LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL; } @@ -1026,10 +1057,9 @@ void assert_glerror() GLenum error; error = glGetError(); BOOL quit = FALSE; - while (error) + while (LL_UNLIKELY(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) { @@ -1053,7 +1083,6 @@ void assert_glerror() } } error = glGetError(); -#endif } if (quit) @@ -1069,6 +1098,25 @@ void assert_glerror() } } +void assert_glerror() +{ + if (!gGLActive) + { + //llwarns << "GL used while not active!" << llendl; + + if (gDebugSession) + { + //ll_fail("GL used while not active"); + } + } + + if (!gNoRender && gDebugGL) + { + do_assert_glerror(); + } +} + + void clear_glerror() { // Create or update texture to be used with this data @@ -1082,7 +1130,7 @@ void clear_glerror() // // Static members -std::map<LLGLenum, LLGLboolean> LLGLState::sStateMap; +boost::unordered_map<LLGLenum, LLGLboolean> LLGLState::sStateMap; GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default @@ -1130,7 +1178,7 @@ void LLGLState::resetTextureStates() void LLGLState::dumpStates() { LL_INFOS("RenderState") << "GL States:" << LL_ENDL; - for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); + for (boost::unordered_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; @@ -1166,7 +1214,7 @@ void LLGLState::checkStates(const std::string& msg) } } - for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); + for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); iter != sStateMap.end(); ++iter) { LLGLenum state = iter->first; @@ -1258,8 +1306,10 @@ void LLGLState::checkTextureChannels(const std::string& msg) }; GLint stackDepth = 0; - LLMatrix4 identity; - LLMatrix4 matrix; + + glh::matrix4f mat; + glh::matrix4f identity; + identity.identity(); for (GLint i = 1; i < maxTextureUnits; i++) { @@ -1280,10 +1330,10 @@ void LLGLState::checkTextureChannels(const std::string& msg) } } - glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix); + glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.m); stop_glerror(); - if (matrix != identity) + if (mat != identity) { error = TRUE; LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL; @@ -1309,10 +1359,6 @@ void LLGLState::checkTextureChannels(const std::string& msg) stop_glerror(); } - glh::matrix4f mat; - glh::matrix4f identity; - identity.identity(); - glGetFloatv(GL_TEXTURE_MATRIX, mat.m); stop_glerror(); @@ -1910,6 +1956,16 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { stop_glerror(); + + checkState(); + + if (!depth_enabled) + { // always disable depth writes if depth testing is disabled + // GL spec defines this as a requirement, but some implementations allow depth writes with testing disabled + // The proper way to write to depth buffer with testing disabled is to enable testing and use a depth_func of GL_ALWAYS + write_enabled = FALSE; + } + if (depth_enabled != sDepthEnabled) { gGL.flush(); @@ -1933,6 +1989,7 @@ LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, G LLGLDepthTest::~LLGLDepthTest() { + checkState(); if (sDepthEnabled != mPrevDepthEnabled ) { gGL.flush(); @@ -1954,6 +2011,32 @@ LLGLDepthTest::~LLGLDepthTest() } } +void LLGLDepthTest::checkState() +{ + if (gDebugGL) + { + GLint func = 0; + GLboolean mask = FALSE; + + glGetIntegerv(GL_DEPTH_FUNC, &func); + glGetBooleanv(GL_DEPTH_WRITEMASK, &mask); + + if (glIsEnabled(GL_DEPTH_TEST) != sDepthEnabled || + sWriteEnabled != mask || + sDepthFunc != func) + { + if (gDebugSession) + { + gFailLog << "Unexpected depth testing state." << std::endl; + } + else + { + LL_GL_ERRS << "Unexpected depth testing state." << LL_ENDL; + } + } + } +} + LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P) { for (U32 i = 0; i < 4; i++) diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 34dd982259..5e8965c06a 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -2,31 +2,25 @@ * @file llgl.h * @brief LLGL definition * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,7 +30,8 @@ // This file contains various stuff for handling gl extensions and other gl related stuff. #include <string> -#include <map> +#include <boost/unordered_map.hpp> +#include <list> #include "llerror.h" #include "v4color.h" @@ -86,6 +81,7 @@ public: BOOL mHasCompressedTextures; BOOL mHasFramebufferObject; BOOL mHasFramebufferMultisample; + BOOL mHasBlendFuncSeparate; // ARB Extensions BOOL mHasVertexBufferObject; @@ -118,6 +114,9 @@ public: // Misc extensions BOOL mHasSeparateSpecularColor; + + //whether this GPU is in the debug list. + BOOL mDebugGPU; S32 mDriverVersionMajor; S32 mDriverVersionMinor; @@ -146,6 +145,7 @@ private: void initExtensions(); void initGLStates(); void initGLImages(); + void setToDebugGPU(); }; extern LLGLManager gGLManager; @@ -239,7 +239,7 @@ public: static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001); protected: - static std::map<LLGLenum, LLGLboolean> sStateMap; + static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap; public: enum { CURRENT_STATE = -2 }; @@ -367,6 +367,35 @@ protected: virtual void releaseName(GLuint name) = 0; }; +/* + Interface for objects that need periodic GL updates applied to them. + Used to synchronize GL updates with GL thread. +*/ +class LLGLUpdate +{ +public: + + static std::list<LLGLUpdate*> sGLQ; + + BOOL mInQ; + LLGLUpdate() + : mInQ(FALSE) + { + } + virtual ~LLGLUpdate() + { + if (mInQ) + { + std::list<LLGLUpdate*>::iterator iter = std::find(sGLQ.begin(), sGLQ.end(), this); + if (iter != sGLQ.end()) + { + sGLQ.erase(iter); + } + } + } + virtual void updateGL() = 0; +}; + extern LLMatrix4 gGLObliqueProjectionInverse; #include "llglstates.h" @@ -385,4 +414,6 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor extern BOOL gClothRipple; extern BOOL gNoRender; +extern BOOL gGLActive; + #endif // LL_LLGL_H diff --git a/indra/llrender/llgldbg.cpp b/indra/llrender/llgldbg.cpp index c54ab18f9b..4b68194db3 100644 --- a/indra/llrender/llgldbg.cpp +++ b/indra/llrender/llgldbg.cpp @@ -2,31 +2,25 @@ * @file llgldbg.cpp * @brief Definitions for OpenGL debugging support * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llgldbg.h b/indra/llrender/llgldbg.h index d98909162e..963579cb82 100644 --- a/indra/llrender/llgldbg.h +++ b/indra/llrender/llgldbg.h @@ -2,31 +2,25 @@ * @file llgldbg.h * @brief Definitions for OpenGL debugging support * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index c7178a5552..5a34b46d0c 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -2,31 +2,25 @@ * @file llglheaders.h * @brief LLGL definitions * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,8 +47,6 @@ # include "GL/glxext.h" //# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB((const GLubyte*)(p)) # define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddress((const GLubyte*)(p)) -// the X headers define 'Status'. Undefine to avoid confusion. -#undef Status // The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly // This header is distributed with SL. You'll find it in linden/libraries/include/GL/ @@ -218,6 +210,9 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -251,7 +246,10 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; # include "GL/glh_extensions.h" # undef __APPLE__ -#elif LL_LINUX +#elif LL_LINUX +//---------------------------------------------------------------------------- +// LL_LINUX + //---------------------------------------------------------------------------- // Linux, MESA headers, but not necessarily assuming MESA runtime. // quotes so we get libraries/.../GL/ version @@ -277,8 +275,6 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; // 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 #if LL_LINUX && defined(WINGDIAPI) @@ -289,6 +285,7 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; # define LL_LINUX_NV_GL_HEADERS 0 #endif // LL_LINUX && defined(WINGDIAPI) + #if LL_LINUX_NV_GL_HEADERS // Missing functions when using nvidia headers: extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; @@ -449,6 +446,9 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -477,7 +477,10 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; //GL_ARB_draw_buffers extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; + #elif LL_WINDOWS +//---------------------------------------------------------------------------- +// LL_WINDOWS // windows gl headers depend on things like APIENTRY, so include windows. #define WIN32_LEAN_AND_MEAN @@ -645,6 +648,9 @@ extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; +//GL_EXT_blend_func_separate +extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; + //GL_EXT_framebuffer_object extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; @@ -673,6 +679,7 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT; //GL_ARB_draw_buffers extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; + #elif LL_DARWIN //---------------------------------------------------------------------------- // LL_DARWIN @@ -689,6 +696,9 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; // 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_blend_func_separate +extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // 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; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 830617063b..16534fa9a5 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -2,31 +2,25 @@ * @file llglslshader.cpp * @brief GLSL helper functions and state. * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -70,7 +64,7 @@ hasGamma(false), hasLighting(false), calculatesAtmospherics(false) // LLGLSL Shader implementation //=============================== LLGLSLShader::LLGLSLShader() -: mProgramObject(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT) + : mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE) { } diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 166d4af04c..c11bd50716 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -2,31 +2,25 @@ * @file llglslshader.h * @brief GLSL shader wrappers * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 4a51cac438..d5a29dcd0c 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -2,31 +2,25 @@ * @file llglstates.h * @brief LLGL states definitions * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,6 +40,8 @@ public: ~LLGLDepthTest(); + void checkState(); + GLboolean mPrevDepthEnabled; GLenum mPrevDepthFunc; GLboolean mPrevWriteEnabled; diff --git a/indra/llrender/llgltypes.h b/indra/llrender/llgltypes.h index 9b0e81faea..6c217ef727 100644 --- a/indra/llrender/llgltypes.h +++ b/indra/llrender/llgltypes.h @@ -2,31 +2,25 @@ * @file llgltypes.h * @brief LLGL definition * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index e1231eeeb4..9d037f2565 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2,31 +2,25 @@ * @file llimagegl.cpp * @brief Generic GL image handler * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,10 +37,7 @@ #include "llmath.h" #include "llgl.h" #include "llrender.h" - - //---------------------------------------------------------------------------- - const F32 MIN_TEXTURE_LIFETIME = 10.f; //statics @@ -58,12 +49,38 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; S32 LLImageGL::sBoundTextureMemoryInBytes = 0; S32 LLImageGL::sCurBoundTextureMemory = 0; S32 LLImageGL::sCount = 0; +std::list<U32> LLImageGL::sDeadTextureList; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; +BOOL LLImageGL::sAllowReadBackRaw = FALSE ; +LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; std::set<LLImageGL*> LLImageGL::sImageList; +//**************************************************************************************************** +//The below for texture auditing use only +//**************************************************************************************************** +//----------------------- +//debug use +BOOL gAuditTexture = FALSE ; +#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048 +std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ; +std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; +std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ; +S32 LLImageGL::sCurTexSizeBar = -1 ; +S32 LLImageGL::sCurTexPickSize = -1 ; +LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL; +S32 LLImageGL::sMaxCatagories = 1 ; + +std::vector<S32> LLImageGL::sTextureMemByCategory; +std::vector<S32> LLImageGL::sTextureMemByCategoryBound ; +std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ; +//------------------------ +//**************************************************************************************************** +//End for texture auditing use only +//**************************************************************************************************** + //************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. @@ -82,15 +99,24 @@ void check_all_images() } } -void LLImageGL::checkTexSize() const +void LLImageGL::checkTexSize(bool forced) const { - if (gDebugGL && mTarget == GL_TEXTURE_2D) + if ((forced || gDebugGL) && mTarget == GL_TEXTURE_2D) { + { + //check viewport + GLint vp[4] ; + glGetIntegerv(GL_VIEWPORT, vp) ; + llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl ; + } + GLint texname; glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); BOOL error = FALSE; if (texname != mTexName) { + llinfos << "Bound: " << texname << " Should bind: " << mTexName << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << llendl; + error = TRUE; if (gDebugSession) { @@ -106,6 +132,8 @@ void LLImageGL::checkTexSize() const glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_WIDTH, (GLint*)&x); glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_HEIGHT, (GLint*)&y) ; stop_glerror() ; + llcallstacks << "w: " << x << " h: " << y << llcallstacksendl ; + if(!x || !y) { return ; @@ -115,11 +143,13 @@ void LLImageGL::checkTexSize() const error = TRUE; if (gDebugSession) { - gFailLog << "wrong texture size and discard level!" << std::endl; + gFailLog << "wrong texture size and discard level!" << + mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << std::endl; } else { - llerrs << "wrong texture size and discard level!" << llendl ; + llerrs << "wrong texture size and discard level: width: " << + mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << llendl ; } } @@ -133,6 +163,60 @@ void LLImageGL::checkTexSize() const //************************************************************************************** //---------------------------------------------------------------------------- +BOOL is_little_endian() +{ + S32 a = 0x12345678; + U8 *c = (U8*)(&a); + + return (*c == 0x78) ; +} +//static +void LLImageGL::initClass(S32 num_catagories) +{ + sMaxCatagories = num_catagories ; + + sTextureMemByCategory.resize(sMaxCatagories); + sTextureMemByCategoryBound.resize(sMaxCatagories) ; + sTextureCurMemByCategoryBound.resize(sMaxCatagories) ; +} + +//static +void LLImageGL::cleanupClass() +{ + sTextureMemByCategory.clear() ; + sTextureMemByCategoryBound.clear() ; + sTextureCurMemByCategoryBound.clear() ; +} + +//static +void LLImageGL::setHighlightTexture(S32 category) +{ + const S32 dim = 128; + sHighlightTexturep = new LLImageGL() ; + LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3); + U8* data = image_raw->getData(); + for (S32 i = 0; i<dim; i++) + { + for (S32 j = 0; j<dim; j++) + { + const S32 border = 2; + if (i<border || j<border || i>=(dim-border) || j>=(dim-border)) + { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0xff; + } + else + { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0x00; + } + } + } + sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category); + image_raw = NULL; +} //static S32 LLImageGL::dataFormatBits(S32 dataformat) @@ -199,12 +283,32 @@ void LLImageGL::updateStats(F32 current_time) sLastFrameTime = current_time; sBoundTextureMemoryInBytes = sCurBoundTextureMemory; sCurBoundTextureMemory = 0; + + if(gAuditTexture) + { + for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++) + { + sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ; + sTextureCurBoundCounter[i] = 0 ; + } + for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++) + { + sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ; + sTextureCurMemByCategoryBound[i] = 0 ; + } + } } //static -S32 LLImageGL::updateBoundTexMem(const S32 delta) +S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) { - LLImageGL::sCurBoundTextureMemory += delta; + if(gAuditTexture && ncomponents > 0 && category > -1) + { + sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ; + sTextureCurMemByCategoryBound[category] += mem ; + } + + LLImageGL::sCurBoundTextureMemory += mem ; return LLImageGL::sCurBoundTextureMemory; } @@ -218,6 +322,7 @@ void LLImageGL::destroyGL(BOOL save_state) gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); } + sAllowReadBackRaw = true ; for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); iter != sImageList.end(); iter++) { @@ -227,7 +332,7 @@ void LLImageGL::destroyGL(BOOL save_state) if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) { glimage->mSaveData = new LLImageRaw; - if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) + if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. { glimage->mSaveData = NULL ; } @@ -237,6 +342,7 @@ void LLImageGL::destroyGL(BOOL save_state) stop_glerror(); } } + sAllowReadBackRaw = false ; } //static @@ -254,7 +360,7 @@ void LLImageGL::restoreGL() { if (glimage->getComponents() && glimage->mSaveData->getComponents()) { - glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData); + glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory()); stop_glerror(); } glimage->mSaveData = NULL; // deletes data @@ -264,6 +370,7 @@ void LLImageGL::restoreGL() //---------------------------------------------------------------------------- +//for server side use only. //static BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps) { @@ -271,12 +378,14 @@ BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps) return TRUE; } +//for server side use only. BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps) { dest = new LLImageGL(width, height, components, usemipmaps); return TRUE; } +//for server side use only. BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps) { dest = new LLImageGL(imageraw, usemipmaps); @@ -326,42 +435,58 @@ LLImageGL::~LLImageGL() void LLImageGL::init(BOOL usemipmaps) { -#ifdef DEBUG_MISS - mMissed = FALSE; -#endif + // keep these members in the same order as declared in llimagehl.h + // so that it is obvious by visual inspection if we forgot to + // init a field. + + mTextureMemory = 0; + mLastBindTime = 0.f; - mPickMask = NULL; - mTextureState = NO_DELETE ; - mTextureMemory = 0; - mLastBindTime = 0.f; + mPickMask = NULL; + mPickMaskWidth = 0; + mPickMaskHeight = 0; + mUseMipMaps = usemipmaps; + mHasExplicitFormat = FALSE; + mAutoGenMips = FALSE; + + mIsMask = FALSE; + mNeedsAlphaAndPickMask = TRUE ; + mAlphaStride = 0 ; + mAlphaOffset = 0 ; + + mGLTextureCreated = FALSE ; + mTexName = 0; + mWidth = 0; + mHeight = 0; + mCurrentDiscardLevel = -1; + + mDiscardLevelInAtlas = -1 ; + mTexelsInAtlas = 0 ; + mTexelsInGLTexture = 0 ; + + mTarget = GL_TEXTURE_2D; + mBindTarget = LLTexUnit::TT_TEXTURE; + mHasMipMaps = false; + + mIsResident = 0; - mTarget = GL_TEXTURE_2D; - mBindTarget = LLTexUnit::TT_TEXTURE; - mUseMipMaps = usemipmaps; - mHasMipMaps = false; - mAutoGenMips = FALSE; - mTexName = 0; - mIsResident = 0; + mComponents = 0; + mMaxDiscardLevel = MAX_DISCARD_LEVEL; mTexOptionsDirty = true; mAddressMode = LLTexUnit::TAM_WRAP; mFilterOption = LLTexUnit::TFO_ANISOTROPIC; - mWidth = 0; - mHeight = 0; - mComponents = 0; - - mMaxDiscardLevel = MAX_DISCARD_LEVEL; - mCurrentDiscardLevel = -1; - mDontDiscard = FALSE; mFormatInternal = -1; mFormatPrimary = (LLGLenum) 0; mFormatType = GL_UNSIGNED_BYTE; mFormatSwapBytes = FALSE; - mHasExplicitFormat = FALSE; - mGLTextureCreated = FALSE ; - mIsMask = FALSE; +#ifdef DEBUG_MISS + mMissed = FALSE; +#endif + + mCategory = -1; } void LLImageGL::cleanup() @@ -403,7 +528,7 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents) // Check if dimensions are a power of two! if (!checkSize(width,height)) { - llerrs << llformat("Texture has non power of two dimention: %dx%d",width,height) << llendl; + llerrs << llformat("Texture has non power of two dimension: %dx%d",width,height) << llendl; } if (mTexName) @@ -411,7 +536,12 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents) // llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl; destroyGLTexture(); } - + + // pickmask validity depends on old image size, delete it + delete [] mPickMask; + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; + mWidth = width; mHeight = height; mComponents = ncomponents; @@ -461,8 +591,12 @@ void LLImageGL::dump() } //---------------------------------------------------------------------------- +void LLImageGL::forceUpdateBindStats(void) const +{ + mLastBindTime = sLastFrameTime; +} -void LLImageGL::updateBindStats(void) const +BOOL LLImageGL::updateBindStats(S32 tex_mem) const { if (mTexName != 0) { @@ -474,38 +608,18 @@ void LLImageGL::updateBindStats(void) const { // we haven't accounted for this texture yet this frame sUniqueCount++; - updateBoundTexMem(mTextureMemory); + updateBoundTexMem(tex_mem, mComponents, mCategory); mLastBindTime = sLastFrameTime; - if(LLFastTimer::sMetricLog) - { - updateTestStats() ; - } + return TRUE ; } } + return FALSE ; } -//virtual -void LLImageGL::updateTestStats(void) const -{ -} - -//virtual -bool LLImageGL::bindError(const S32 stage) const -{ - return false; -} - -//virtual -bool LLImageGL::bindDefaultImage(const S32 stage) const -{ - return false; -} - -//virtual -void LLImageGL::forceImmediateUpdate() +F32 LLImageGL::getTimePassedSinceLastBound() { - return ; + return sLastFrameTime - mLastBindTime ; } void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes ) @@ -520,6 +634,8 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for else mFormatType = type_format; mFormatSwapBytes = swap_bytes; + + calcAlphaChannelOffsetAndStride() ; } //---------------------------------------------------------------------------- @@ -535,20 +651,16 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { -// LLFastTimer t1(LLFastTimer::FTM_TEMP1); - llpushcallstacks ; bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { is_compressed = true; } -// LLFastTimer t2(LLFastTimer::FTM_TEMP2); - gGL.getTexUnit(0)->bind(this); + llverify(gGL.getTexUnit(0)->bind(this)); if (mUseMipMaps) { -// LLFastTimer t2(LLFastTimer::FTM_TEMP3); if (data_hasmips) { // NOTE: data_in points to largest image; smaller images @@ -565,14 +677,13 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } if (is_compressed) { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); } else { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); if(mFormatSwapBytes) { @@ -605,7 +716,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); stop_glerror(); { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); if(mFormatSwapBytes) { @@ -665,7 +776,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } llassert(w > 0 && h > 0 && cur_mip_data); { -// LLFastTimer t1(LLFastTimer::FTM_TEMP4); +// LLFastTimer t1(FTM_TEMP4); if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); @@ -748,12 +859,96 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } stop_glerror(); mGLTextureCreated = true; - llpushcallstacks ; } -BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) +{ + if (gGLManager.mIsDisabled) + { + llwarns << "Trying to create a texture while GL is disabled!" << llendl; + return FALSE; + } + llassert(gGLManager.mInited); + stop_glerror(); + + if (discard_level < 0) + { + llassert(mCurrentDiscardLevel >= 0); + discard_level = mCurrentDiscardLevel; + } + discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); + + // Actual image width/height = raw image width/height * 2^discard_level + S32 w = raw_image->getWidth() << discard_level; + S32 h = raw_image->getHeight() << discard_level; + + // setSize may call destroyGLTexture if the size does not match + setSize(w, h, raw_image->getComponents()); + + if( !mHasExplicitFormat ) + { + switch (mComponents) + { + case 1: + // Use luminance alpha (for fonts) + mFormatInternal = GL_LUMINANCE8; + mFormatPrimary = GL_LUMINANCE; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 2: + // Use luminance alpha (for fonts) + mFormatInternal = GL_LUMINANCE8_ALPHA8; + mFormatPrimary = GL_LUMINANCE_ALPHA; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 3: + mFormatInternal = GL_RGB8; + mFormatPrimary = GL_RGB; + mFormatType = GL_UNSIGNED_BYTE; + break; + case 4: + mFormatInternal = GL_RGBA8; + mFormatPrimary = GL_RGBA; + mFormatType = GL_UNSIGNED_BYTE; + break; + default: + llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl; + } + } + + mCurrentDiscardLevel = discard_level; + mDiscardLevelInAtlas = discard_level; + mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ; + mLastBindTime = sLastFrameTime; + mGLTextureCreated = false ; + + glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth()); + stop_glerror(); + + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } + + return TRUE ; +} + +void LLImageGL::postAddToAtlas() +{ + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); + stop_glerror(); +} + +BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) { - llpushcallstacks ; if (!width || !height) { return TRUE; @@ -769,7 +964,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 return FALSE; } - if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) + // HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture. + if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) { setImage(datap, FALSE); } @@ -842,20 +1038,27 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 stop_glerror(); mGLTextureCreated = true; } - llpushcallstacks ; return TRUE; } -BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) { - return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height); + return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update); } // Copy sub image from frame buffer BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height) { - if (gGL.getTexUnit(0)->bind(this, true)) + if (gGL.getTexUnit(0)->bind(this, false, true)) { + if(gGLManager.mDebugGPU) + { + llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ; + checkTexSize(true) ; + llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height << + " : " << (S32)mComponents << llcallstacksendl ; + } + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); mGLTextureCreated = true; stop_glerror(); @@ -876,13 +1079,17 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures) // static void LLImageGL::deleteTextures(S32 numTextures, U32 *textures) { - glDeleteTextures(numTextures, (GLuint*)textures); + for (S32 i = 0; i < numTextures; i++) + { + sDeadTextureList.push_back(textures[i]); + } } // static void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels) { glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels); + stop_glerror(); } //create an empty GL texture: just create a texture name @@ -915,14 +1122,14 @@ BOOL LLImageGL::createGLTexture() return TRUE ; } -BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/) +BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) { - llpushcallstacks ; if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; return FALSE; } + mGLTextureCreated = false ; llassert(gGLManager.mInited); stop_glerror(); @@ -935,8 +1142,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); // Actual image width/height = raw image width/height * 2^discard_level - S32 w = imageraw->getWidth() << discard_level; - S32 h = imageraw->getHeight() << discard_level; + S32 raw_w = imageraw->getWidth() ; + S32 raw_h = imageraw->getHeight() ; + S32 w = raw_w << discard_level; + S32 h = raw_h << discard_level; // setSize may call destroyGLTexture if the size does not match setSize(w, h, imageraw->getComponents()); @@ -970,15 +1179,25 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S default: llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl; } + + calcAlphaChannelOffsetAndStride() ; + } + + if(!to_create) //not create a gl texture + { + destroyGLTexture(); + mCurrentDiscardLevel = discard_level; + mLastBindTime = sLastFrameTime; + return TRUE ; } + setCategory(category) ; const U8* rawdata = imageraw->getData(); return createGLTexture(discard_level, rawdata, FALSE, usename); } BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) { - llpushcallstacks ; llassert(data_in); if (discard_level < 0) @@ -1007,7 +1226,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ LLImageGL::generateTextures(1, &mTexName); stop_glerror(); { -// LLFastTimer t1(LLFastTimer::FTM_TEMP6); llverify(gGL.getTexUnit(0)->bind(this)); glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level); @@ -1046,91 +1264,35 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ if (old_name != 0) { sGlobalTextureMemoryInBytes -= mTextureMemory; + + if(gAuditTexture) + { + decTextureCounter(mTextureMemory, mComponents, mCategory) ; + } + LLImageGL::deleteTextures(1, &old_name); + stop_glerror(); } mTextureMemory = getMipBytes(discard_level); sGlobalTextureMemoryInBytes += mTextureMemory; - setActive() ; + mTexelsInGLTexture = getWidth() * getHeight() ; + if(gAuditTexture) + { + incTextureCounter(mTextureMemory, mComponents, mCategory) ; + } // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; - - llpushcallstacks ; return TRUE; } -BOOL LLImageGL::setDiscardLevel(S32 discard_level) -{ - llassert(discard_level >= 0); - llassert(mCurrentDiscardLevel >= 0); - - discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - - if (mDontDiscard) - { - // don't discard! - return FALSE; - } - else if (discard_level == mCurrentDiscardLevel) - { - // nothing to do - return FALSE; - } - else if (discard_level < mCurrentDiscardLevel) - { - // larger image - dump(); - llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl; - return FALSE; - } - else if (mUseMipMaps) - { - LLPointer<LLImageRaw> imageraw = new LLImageRaw; - while(discard_level > mCurrentDiscardLevel) - { - if (readBackRaw(discard_level, imageraw, false)) - { - break; - } - discard_level--; - } - if (discard_level == mCurrentDiscardLevel) - { - // unable to increase the discard level - return FALSE; - } - return createGLTexture(discard_level, imageraw); - } - else - { -#if !LL_LINUX && !LL_SOLARIS - // *FIX: This should not be skipped for the linux client. - llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl; -#endif - return FALSE; - } -} - -BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) -{ - assert_glerror(); - S32 gl_discard = discard_level - mCurrentDiscardLevel; - LLGLint glwidth = 0; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth); - LLGLint glheight = 0; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_HEIGHT, (GLint*)&glheight); - LLGLint glcomponents = 0 ; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&glcomponents); - assert_glerror(); - - return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ; -} - BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const { - llpushcallstacks ; + llassert_always(sAllowReadBackRaw) ; + //llerrs << "should not call this function!" << llendl ; + if (discard_level < 0) { discard_level = mCurrentDiscardLevel; @@ -1233,37 +1395,53 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return FALSE ; } //----------------------------------------------------------------------------------------------- - llpushcallstacks ; + return TRUE ; } -void LLImageGL::destroyGLTexture() +void LLImageGL::deleteDeadTextures() { - if (mTexName != 0) + while (!sDeadTextureList.empty()) { - stop_glerror(); - + GLuint tex = sDeadTextureList.front(); + sDeadTextureList.pop_front(); for (int i = 0; i < gGLManager.mNumTextureUnits; i++) { - if (sCurrentBoundTextures[i] == mTexName) + if (sCurrentBoundTextures[i] == tex) { gGL.getTexUnit(i)->unbind(LLTexUnit::TT_TEXTURE); stop_glerror(); } } - - sGlobalTextureMemoryInBytes -= mTextureMemory; - mTextureMemory = 0; - - LLImageGL::deleteTextures(1, &mTexName); - mTextureState = DELETED ; + + glDeleteTextures(1, &tex); + stop_glerror(); + } +} + +void LLImageGL::destroyGLTexture() +{ + if (mTexName != 0) + { + if(mTextureMemory) + { + if(gAuditTexture) + { + decTextureCounter(mTextureMemory, mComponents, mCategory) ; + } + sGlobalTextureMemoryInBytes -= mTextureMemory; + mTextureMemory = 0; + } + + LLImageGL::deleteTextures(1, &mTexName); mTexName = 0; mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; - stop_glerror(); } } + + //---------------------------------------------------------------------------- void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) @@ -1289,12 +1467,12 @@ void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) mFilterOption = option; } - if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) { gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); mTexOptionsDirty = false; + stop_glerror(); } - stop_glerror(); } BOOL LLImageGL::getIsResident(BOOL test_now) @@ -1370,6 +1548,11 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const return res; } +BOOL LLImageGL::isJustBound() const +{ + return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f); +} + BOOL LLImageGL::getBoundRecently() const { return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); @@ -1381,137 +1564,222 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b mBindTarget = bind_target; } -void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) +const S8 INVALID_OFFSET = -99 ; +void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) { - if (mFormatType != GL_UNSIGNED_BYTE) + if(mNeedsAlphaAndPickMask != need_mask) { - llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + mNeedsAlphaAndPickMask = need_mask; + + if(mNeedsAlphaAndPickMask) + { + mAlphaOffset = 0 ; + } + else //do not need alpha mask + { + mAlphaOffset = INVALID_OFFSET ; + mIsMask = FALSE; + } + } +} + +void LLImageGL::calcAlphaChannelOffsetAndStride() +{ + if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask + { + return ; } - U32 stride = 0; + mAlphaStride = -1 ; switch (mFormatPrimary) { case GL_LUMINANCE: case GL_ALPHA: - stride = 1; + mAlphaStride = 1; break; case GL_LUMINANCE_ALPHA: - stride = 2; + mAlphaStride = 2; break; case GL_RGB: - //no alpha + mNeedsAlphaAndPickMask = FALSE ; mIsMask = FALSE; - return; + return ; //no alpha channel. case GL_RGBA: - stride = 4; + mAlphaStride = 4; break; case GL_BGRA_EXT: - stride = 4; + mAlphaStride = 4; break; default: - return; + break; } - U32 length = w * h; - const GLubyte* current = ((const GLubyte*) data_in)+stride-1; - - S32 sample[16]; - memset(sample, 0, sizeof(S32)*16); - - for (U32 i = 0; i < length; i++) + mAlphaOffset = -1 ; + if (mFormatType == GL_UNSIGNED_BYTE) { - ++sample[*current/16]; - current += stride; + mAlphaOffset = mAlphaStride - 1 ; } - - U32 total = 0; - for (U32 i = 4; i < 11; i++) + else if(is_little_endian()) { - total += sample[i]; - } - - if (total > length/16) - { - mIsMask = FALSE; + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 0 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 3 ; + } } - else + else //big endian { - mIsMask = TRUE; + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 3 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 0 ; + } } -} -BOOL LLImageGL::isDeleted() -{ - return mTextureState == DELETED ; -} + if( mAlphaStride < 1 || //unsupported format + mAlphaOffset < 0 || //unsupported type + (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation + { + llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; -BOOL LLImageGL::isInactive() -{ - return mTextureState == INACTIVE ; + mNeedsAlphaAndPickMask = FALSE ; + mIsMask = FALSE; + } } -BOOL LLImageGL::isDeletionCandidate() -{ - return mTextureState == DELETION_CANDIDATE ; -} +void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) +{ + if(!mNeedsAlphaAndPickMask) + { + return ; + } -void LLImageGL::setDeletionCandidate() -{ - if(mTexName && (mTextureState == INACTIVE)) + U32 length = w * h; + U32 alphatotal = 0; + + U32 sample[16]; + memset(sample, 0, sizeof(U32)*16); + + // generate histogram of quantized alpha. + // also add-in the histogram of a 2x2 box-sampled version. The idea is + // this will mid-skew the data (and thus increase the chances of not + // being used as a mask) from high-frequency alpha maps which + // suffer the worst from aliasing when used as alpha masks. + if (w >= 2 && h >= 2) + { + llassert(w%2 == 0); + llassert(h%2 == 0); + const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 y = 0; y < h; y+=2) + { + const GLubyte* current = rowstart; + for (U32 x = 0; x < w; x+=2) + { + const U32 s1 = current[0]; + alphatotal += s1; + const U32 s2 = current[w * mAlphaStride]; + alphatotal += s2; + current += mAlphaStride; + const U32 s3 = current[0]; + alphatotal += s3; + const U32 s4 = current[w * mAlphaStride]; + alphatotal += s4; + current += mAlphaStride; + + ++sample[s1/16]; + ++sample[s2/16]; + ++sample[s3/16]; + ++sample[s4/16]; + + const U32 asum = (s1+s2+s3+s4); + alphatotal += asum; + sample[asum/(16*4)] += 4; + } + + rowstart += 2 * w * mAlphaStride; + } + length *= 2; // we sampled everything twice, essentially + } + else { - mTextureState = DELETION_CANDIDATE ; + const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 i = 0; i < length; i++) + { + const U32 s1 = *current; + alphatotal += s1; + ++sample[s1/16]; + current += mAlphaStride; + } } -} + + // if more than 1/16th of alpha samples are mid-range, this + // shouldn't be treated as a 1-bit mask -void LLImageGL::forceActive() -{ - mTextureState = ACTIVE ; -} + // also, if all of the alpha samples are clumped on one half + // of the range (but not at an absolute extreme), then consider + // this to be an intentional effect and don't treat as a mask. -void LLImageGL::setActive() -{ - if(mTextureState != NO_DELETE) + U32 midrangetotal = 0; + for (U32 i = 4; i < 11; i++) { - mTextureState = ACTIVE ; + midrangetotal += sample[i]; } -} - -//set the texture inactive -void LLImageGL::setInactive() -{ - if(mTexName && (mTextureState == ACTIVE) && !getBoundRecently()) + U32 lowerhalftotal = 0; + for (U32 i = 0; i < 8; i++) { - mTextureState = INACTIVE ; + lowerhalftotal += sample[i]; + } + U32 upperhalftotal = 0; + for (U32 i = 8; i < 16; i++) + { + upperhalftotal += sample[i]; } -} -//set the texture to stay in memory -void LLImageGL::setNoDelete() -{ - mTextureState = NO_DELETE ; + if (midrangetotal > length/16 || // lots of midrange, or + (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or + (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque + { + mIsMask = FALSE; // not suitable for masking + } + else + { + mIsMask = TRUE; + } } //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { + if(!mNeedsAlphaAndPickMask) + { + return ; + } + + delete [] mPickMask; + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; + if (mFormatType != GL_UNSIGNED_BYTE || - mFormatPrimary != GL_RGBA) + mFormatPrimary != GL_RGBA) { //cannot generate a pick mask for this texture - delete [] mPickMask; - mPickMask = NULL; return; } - U32 pick_width = width/2; - U32 pick_height = height/2; - - U32 size = llmax(pick_width, (U32) 1) * llmax(pick_height, (U32) 1); + U32 pick_width = width/2 + 1; + U32 pick_height = height/2 + 1; - size = size/8 + 1; - - delete[] mPickMask; + U32 size = pick_width * pick_height; + size = (size + 7) / 8; // pixelcount-to-bits mPickMask = new U8[size]; + mPickMaskWidth = pick_width - 1; + mPickMaskHeight = pick_height - 1; memset(mPickMask, 0, sizeof(U8) * size); @@ -1527,10 +1795,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { U32 pick_idx = pick_bit/8; U32 pick_offset = pick_bit%8; - if (pick_idx >= size) - { - llerrs << "WTF?" << llendl; - } + llassert(pick_idx < size); mPickMask[pick_idx] |= 1 << pick_offset; } @@ -1546,22 +1811,44 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) if (mPickMask) { - S32 width = getWidth()/2; - S32 height = getHeight()/2; + F32 u,v; + if (LL_LIKELY(tc.isFinite())) + { + u = tc.mV[0] - floorf(tc.mV[0]); + v = tc.mV[1] - floorf(tc.mV[1]); + } + else + { + LL_WARNS_ONCE("render") << "Ugh, non-finite u/v in mask pick" << LL_ENDL; + u = v = 0.f; + // removing assert per EXT-4388 + // llassert(false); + } + + if (LL_UNLIKELY(u < 0.f || u > 1.f || + v < 0.f || v > 1.f)) + { + LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; + u = v = 0.f; + // removing assert per EXT-4388 + // llassert(false); + } - F32 u = tc.mV[0] - floorf(tc.mV[0]); - F32 v = tc.mV[1] - floorf(tc.mV[1]); + S32 x = llfloor(u * mPickMaskWidth); + S32 y = llfloor(v * mPickMaskHeight); - if (u < 0.f || u > 1.f || - v < 0.f || v > 1.f) + if (LL_UNLIKELY(x > mPickMaskWidth)) { - llerrs << "WTF?" << llendl; + LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; + x = llmax((U16)0, mPickMaskWidth); + } + if (LL_UNLIKELY(y > mPickMaskHeight)) + { + LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; + y = llmax((U16)0, mPickMaskHeight); } - - S32 x = (S32)(u * width); - S32 y = (S32)(v * height); - S32 idx = y*width+x; + S32 idx = y*mPickMaskWidth+x; S32 offset = idx%8; res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; @@ -1570,6 +1857,88 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) return res; } +void LLImageGL::setCategory(S32 category) +{ + if(!gAuditTexture) + { + return ; + } + if(mCategory != category) + { + if(mCategory > -1) + { + sTextureMemByCategory[mCategory] -= mTextureMemory ; + } + if(category > -1 && category < sMaxCatagories) + { + sTextureMemByCategory[category] += mTextureMemory ; + mCategory = category; + } + else + { + mCategory = -1 ; + } + } +} + +//for debug use +//val is a "power of two" number +S32 LLImageGL::getTextureCounterIndex(U32 val) +{ + //index range is [0, MAX_TEXTURE_LOG_SIZE]. + if(val < 2) + { + return 0 ; + } + else if(val >= (1 << MAX_TEXTURE_LOG_SIZE)) + { + return MAX_TEXTURE_LOG_SIZE ; + } + else + { + S32 ret = 0 ; + while(val >>= 1) + { + ++ret; + } + return ret ; + } +} + +//static +void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category) +{ + sTextureLoadedCounter[getTextureCounterIndex(val)]++ ; + sTextureMemByCategory[category] += (S32)val * ncomponents ; +} + +//static +void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category) +{ + sTextureLoadedCounter[getTextureCounterIndex(val)]-- ; + sTextureMemByCategory[category] += (S32)val * ncomponents ; +} + +void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size) +{ + sCurTexSizeBar = index ; + + if(set_pick_size) + { + sCurTexPickSize = (1 << index) ; + } + else + { + sCurTexPickSize = -1 ; + } +} +void LLImageGL::resetCurTexSizebar() +{ + sCurTexSizeBar = -1 ; + sCurTexPickSize = -1 ; +} +//---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 1775ae7de9..87a835cdcc 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -2,31 +2,25 @@ * @file llimagegl.h * @brief Object for managing images and their textures * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,23 +36,27 @@ #include "v2math.h" #include "llrender.h" - +class LLTextureAtlas ; #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20) #define MEGA_BYTES_TO_BYTES(x) ((x) << 20) //============================================================================ - class LLImageGL : public LLRefCount { friend class LLTexUnit; public: + static std::list<U32> sDeadTextureList; + + static void deleteDeadTextures(); + // Size calculation static S32 dataFormatBits(S32 dataformat); static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height); static S32 dataFormatComponents(S32 dataformat); - void updateBindStats(void) const; - virtual void updateTestStats(void) const; + BOOL updateBindStats(S32 tex_mem) const ; + F32 getTimePassedSinceLastBound(); + void forceUpdateBindStats(void) const; // needs to be called every frame static void updateStats(F32 current_time); @@ -67,17 +65,18 @@ public: static void destroyGL(BOOL save_state = TRUE); static void restoreGL(); - // Sometimes called externally for textures not using LLImageGL (should go away...) - static S32 updateBoundTexMem(const S32 delta); - - static bool checkSize(S32 width, S32 height); + // Sometimes called externally for textures not using LLImageGL (should go away...) + static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ; + static bool checkSize(S32 width, S32 height); + + //for server side use only. // Not currently necessary for LLImageGL, but required in some derived classes, // so include for compatability static BOOL create(LLPointer<LLImageGL>& dest, BOOL usemipmaps = TRUE); static BOOL create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); static BOOL create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); - + public: LLImageGL(BOOL usemipmaps = TRUE); LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); @@ -86,15 +85,14 @@ public: protected: virtual ~LLImageGL(); - void analyzeAlpha(const void* data_in, S32 w, S32 h); + void analyzeAlpha(const void* data_in, U32 w, U32 h); + void calcAlphaChannelOffsetAndStride(); public: virtual void dump(); // debugging info to llinfos - virtual bool bindError(const S32 stage = 0) const; - virtual bool bindDefaultImage(const S32 stage = 0) const; - virtual void forceImmediateUpdate() ; - + void setSize(S32 width, S32 height, S32 ncomponents); + void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() // for tracking purposes and will be deprecated in the future @@ -103,20 +101,21 @@ public: static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels); BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0); + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, + S32 category = sMaxCatagories - 1); BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); void setImage(const LLImageRaw* imageraw); void setImage(const U8* data_in, BOOL data_hasmips = FALSE); - BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); - BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); - BOOL setDiscardLevel(S32 discard_level); + // Read back a raw image for this discard level, if it exists BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; void destroyGLTexture(); void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); - void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } + void setComponents(S8 ncomponents) { mComponents = ncomponents; } S32 getDiscardLevel() const { return mCurrentDiscardLevel; } S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } @@ -129,7 +128,9 @@ public: S32 getBytes(S32 discard_level = -1) const; S32 getMipBytes(S32 discard_level = -1) const; BOOL getBoundRecently() const; + BOOL isJustBound() const; LLGLenum getPrimaryFormat() const { return mFormatPrimary; } + LLGLenum getFormatType() const { return mFormatType; } BOOL getHasGLTexture() const { return mTexName != 0; } LLGLuint getTexName() const { return mTexName; } @@ -145,16 +146,12 @@ public: void setGLTextureCreated (bool initialized) { mGLTextureCreated = initialized; } BOOL getUseMipMaps() const { return mUseMipMaps; } - void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } - BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; } - BOOL getDontDiscard() const { return mDontDiscard; } - - BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ; + void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } void updatePickMask(S32 width, S32 height, const U8* data_in); BOOL getMask(const LLVector2 &tc); - void checkTexSize() const ; + void checkTexSize(bool forced = false) const ; // Sets the addressing mode used to sample the texture // (such as wrapping, mirrored wrapping, and clamp) @@ -168,38 +165,48 @@ public: void setFilteringOption(LLTexUnit::eTextureFilterOptions option); LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } - BOOL isDeleted() ; - BOOL isInactive() ; - BOOL isDeletionCandidate(); - void setDeletionCandidate() ; - void setInactive() ; - void setActive() ; - void forceActive() ; - void setNoDelete() ; + LLGLenum getTexTarget()const { return mTarget ;} + S8 getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;} + U32 getTexelsInAtlas()const { return mTexelsInAtlas ;} + U32 getTexelsInGLTexture()const {return mTexelsInGLTexture;} -protected: + void init(BOOL usemipmaps); virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors + void setNeedsAlphaAndPickMask(BOOL need_mask); + + BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image); + void postAddToAtlas() ; + public: // Various GL/Rendering options S32 mTextureMemory; mutable F32 mLastBindTime; // last time this was bound, by discard level - + private: LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel + U16 mPickMaskWidth; + U16 mPickMaskHeight; S8 mUseMipMaps; S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents) S8 mAutoGenMips; BOOL mIsMask; - + BOOL mNeedsAlphaAndPickMask; + S8 mAlphaStride ; + S8 mAlphaOffset ; + bool mGLTextureCreated ; LLGLuint mTexName; U16 mWidth; U16 mHeight; S8 mCurrentDiscardLevel; + + S8 mDiscardLevelInAtlas; + U32 mTexelsInAtlas ; + U32 mTexelsInGLTexture; protected: LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) @@ -210,28 +217,15 @@ protected: S8 mComponents; S8 mMaxDiscardLevel; - S8 mDontDiscard; // Keep full res version of this image (for UI, etc) - + bool mTexOptionsDirty; LLTexUnit::eTextureAddressMode mAddressMode; // Defaults to TAM_WRAP - LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_TRILINEAR - + LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_ANISOTROPIC LLGLint mFormatInternal; // = GL internalformat LLGLenum mFormatPrimary; // = GL format (pixel data format) LLGLenum mFormatType; BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1) - -protected: - typedef enum - { - DELETED = 0, //removed from memory - DELETION_CANDIDATE, //ready to be removed from memory - INACTIVE, //not be used for the last certain period (i.e., 30 seconds). - ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). - NO_DELETE = 99 //stay in memory, can not be removed. - } LLGLTexureState; - LLGLTexureState mTextureState ; // STATICS public: @@ -239,7 +233,7 @@ public: static S32 sCount; static F32 sLastFrameTime; - + static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID // Global memory statistics @@ -249,6 +243,8 @@ public: static U32 sBindCount; // Tracks number of texture binds for current frame static U32 sUniqueCount; // Tracks number of unique texture binds for current frame static BOOL sGlobalUseAnisotropic; + static LLImageGL* sDefaultGLTexture ; + static BOOL sAutomatedTest; #if DEBUG_MISS BOOL mMissed; // Missed on last bind? @@ -256,6 +252,55 @@ public: #else BOOL getMissed() const { return FALSE; }; #endif + +public: + static void initClass(S32 num_catagories) ; + static void cleanupClass() ; +private: + static S32 sMaxCatagories ; + + //the flag to allow to call readBackRaw(...). + //can be removed if we do not use that function at all. + static BOOL sAllowReadBackRaw ; +// +//**************************************************************************************************** +//The below for texture auditing use only +//**************************************************************************************************** +private: + S32 mCategory ; +public: + void setCategory(S32 category) ; + S32 getCategory()const {return mCategory ;} + + //for debug use: show texture size distribution + //---------------------------------------- + static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures + static std::vector<S32> sTextureLoadedCounter ; + static std::vector<S32> sTextureBoundCounter ; + static std::vector<S32> sTextureCurBoundCounter ; + static S32 sCurTexSizeBar ; + static S32 sCurTexPickSize ; + + static void setHighlightTexture(S32 category) ; + static S32 getTextureCounterIndex(U32 val) ; + static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ; + static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ; + static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ; + static void resetCurTexSizebar(); + //---------------------------------------- + + //for debug use: show texture category distribution + //---------------------------------------- + + static std::vector<S32> sTextureMemByCategory; + static std::vector<S32> sTextureMemByCategoryBound ; + static std::vector<S32> sTextureCurMemByCategoryBound ; + //---------------------------------------- +//**************************************************************************************************** +//End of definitions for texture auditing use only +//**************************************************************************************************** + }; +extern BOOL gAuditTexture; #endif // LL_LLIMAGEGL_H diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 7f4be6a866..d76b2d9004 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -2,31 +2,25 @@ * @file llpostprocess.cpp * @brief LLPostProcess class implementation * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,6 +53,8 @@ LLPostProcess::LLPostProcess(void) : mSceneRenderTexture = NULL ; mNoiseTexture = NULL ; mTempBloomTexture = NULL ; + + noiseTextureScale = 1.0f; /* 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)); diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index 009e4bd415..e19de44c60 100644 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -2,31 +2,25 @@ * @file llpostprocess.h * @brief LLPostProcess class definition * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index d3a230b37b..e26acd53a3 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -2,31 +2,25 @@ * @file llrender.cpp * @brief LLRender implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,16 +32,21 @@ #include "llcubemap.h" #include "llimagegl.h" #include "llrendertarget.h" +#include "lltexture.h" LLRender gGL; // Handy copies of last good GL matrices F64 gGLModelView[16]; F64 gGLLastModelView[16]; +F64 gGLLastProjection[16]; F64 gGLProjection[16]; S32 gGLViewport[4]; -static const U32 LL_NUM_TEXTURE_LAYERS = 8; +U32 LLRender::sUICalls = 0; +U32 LLRender::sUIVerts = 0; + +static const U32 LL_NUM_TEXTURE_LAYERS = 16; static GLenum sGLTextureType[] = { @@ -88,7 +87,9 @@ static GLenum sGLBlendFactor[] = GL_DST_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, - GL_ONE_MINUS_SRC_ALPHA + GL_ONE_MINUS_SRC_ALPHA, + + GL_ZERO // 'BF_UNDEF' }; LLTexUnit::LLTexUnit(S32 index) @@ -114,6 +115,8 @@ void LLTexUnit::refreshState(void) // We set dirty to true so that the tex unit knows to ignore caching // and we reset the cached tex unit state + gGL.flush(); + glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); if (mCurrTexType != TT_NONE) { @@ -143,6 +146,7 @@ void LLTexUnit::activate(void) if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) { + gGL.flush(); glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); gGL.mCurrTextureUnitIndex = mIndex; } @@ -160,6 +164,8 @@ void LLTexUnit::enable(eTextureType type) disable(); // Force a disable of a previous texture type if it's enabled. } mCurrTexType = type; + + gGL.flush(); glEnable(sGLTextureType[type]); } } @@ -172,40 +178,94 @@ void LLTexUnit::disable(void) { activate(); unbind(mCurrTexType); + gGL.flush(); glDisable(sGLTextureType[mCurrTexType]); mCurrTexType = TT_NONE; } } -bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) +bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) { stop_glerror(); if (mIndex < 0) return false; gGL.flush(); - if (texture == NULL) + LLImageGL* gl_tex = NULL ; + if (texture == NULL || !(gl_tex = texture->getGLTexture())) { llwarns << "NULL LLTexUnit::bind texture" << llendl; return false; } - if (!texture->getTexName()) //if texture does not exist + if (!gl_tex->getTexName()) //if texture does not exist { //if deleted, will re-generate it immediately texture->forceImmediateUpdate() ; + gl_tex->forceUpdateBindStats() ; return texture->bindDefaultImage(mIndex); } + //in audit, replace the selected texture by the default one. + if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0) + { + if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize) + { + gl_tex->updateBindStats(gl_tex->mTextureMemory); + return bind(LLImageGL::sHighlightTexturep.get()); + } + } + if ((mCurrTexture != gl_tex->getTexName()) || forceBind) + { + activate(); + enable(gl_tex->getTarget()); + mCurrTexture = gl_tex->getTexName(); + glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); + if(gl_tex->updateBindStats(gl_tex->mTextureMemory)) + { + texture->setActive() ; + texture->updateBindStatsForTester() ; + } + mHasMipMaps = gl_tex->mHasMipMaps; + if (gl_tex->mTexOptionsDirty) + { + gl_tex->mTexOptionsDirty = false; + setTextureAddressMode(gl_tex->mAddressMode); + setTextureFilteringOption(gl_tex->mFilterOption); + } + } + return true; +} + +bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) +{ + stop_glerror(); + if (mIndex < 0) return false; + + if(!texture) + { + llwarns << "NULL LLTexUnit::bind texture" << llendl; + return false; + } + + if(!texture->getTexName()) + { + if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName()) + { + return bind(LLImageGL::sDefaultGLTexture) ; + } + return false ; + } + if ((mCurrTexture != texture->getTexName()) || forceBind) { + gGL.flush(); activate(); enable(texture->getTarget()); mCurrTexture = texture->getTexName(); glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); - texture->updateBindStats(); - texture->setActive() ; + texture->updateBindStats(texture->mTextureMemory); mHasMipMaps = texture->mHasMipMaps; if (texture->mTexOptionsDirty) { @@ -214,6 +274,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) setTextureFilteringOption(texture->mFilterOption); } } + return true; } @@ -238,7 +299,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) mCurrTexture = cubeMap->mImages[0]->getTexName(); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture); mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; - cubeMap->mImages[0]->updateBindStats(); + cubeMap->mImages[0]->updateBindStats(cubeMap->mImages[0]->mTextureMemory); if (cubeMap->mImages[0]->mTexOptionsDirty) { cubeMap->mImages[0]->mTexOptionsDirty = false; @@ -266,6 +327,11 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) if (bindDepth) { + if (renderTarget->hasStencil()) + { + llerrs << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl; + } + bindManual(renderTarget->getUsage(), renderTarget->getDepth()); } else @@ -279,15 +345,21 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) { - if (mIndex < 0 || mCurrTexture == texture) return false; - - gGL.flush(); + if (mIndex < 0) + { + return false; + } - activate(); - enable(type); - mCurrTexture = texture; - glBindTexture(sGLTextureType[type], texture); - mHasMipMaps = hasMips; + if(mCurrTexture != texture) + { + gGL.flush(); + + activate(); + enable(type); + mCurrTexture = texture; + glBindTexture(sGLTextureType[type], texture); + mHasMipMaps = hasMips; + } return true; } @@ -312,6 +384,8 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode) { if (mIndex < 0 || mCurrTexture == 0) return; + gGL.flush(); + activate(); glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); @@ -326,6 +400,8 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio { if (mIndex < 0 || mCurrTexture == 0) return; + gGL.flush(); + if (option == TFO_POINT) { glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -375,6 +451,8 @@ void LLTexUnit::setTextureBlendType(eTextureBlendType type) return; } + gGL.flush(); + activate(); mCurrBlendType = type; S32 scale_amount = 1; @@ -491,6 +569,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT if (mCurrBlendType != TB_COMBINE || gGL.mDirty) { mCurrBlendType = TB_COMBINE; + gGL.flush(); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); } @@ -501,6 +580,8 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT return; } + gGL.flush(); + // Get the gl source enums according to the eTextureBlendSrc sources passed in GLint source1 = getTextureSource(src1); GLint source2 = getTextureSource(src2); @@ -633,6 +714,7 @@ void LLTexUnit::setColorScale(S32 scale) if (mCurrColorScale != scale || gGL.mDirty) { mCurrColorScale = scale; + gGL.flush(); glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale ); } } @@ -642,6 +724,7 @@ void LLTexUnit::setAlphaScale(S32 scale) if (mCurrAlphaScale != scale || gGL.mDirty) { mCurrAlphaScale = scale; + gGL.flush(); glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale ); } } @@ -663,8 +746,11 @@ void LLTexUnit::debugTextureUnit(void) LLRender::LLRender() -: mDirty(false), mCount(0), mMode(LLRender::TRIANGLES), - mMaxAnisotropy(0.f) + : mDirty(false), + mCount(0), + mMode(LLRender::TRIANGLES), + mCurrTextureUnitIndex(0), + mMaxAnisotropy(0.f) { mBuffer = new LLVertexBuffer(immediate_mask, 0); mBuffer->allocateBuffer(4096, 0, TRUE); @@ -686,6 +772,10 @@ LLRender::LLRender() mCurrAlphaFunc = CF_DEFAULT; mCurrAlphaFuncVal = 0.01f; + mCurrBlendColorSFactor = BF_UNDEF; + mCurrBlendAlphaSFactor = BF_UNDEF; + mCurrBlendColorDFactor = BF_UNDEF; + mCurrBlendAlphaDFactor = BF_UNDEF; } LLRender::~LLRender() @@ -748,6 +838,88 @@ void LLRender::popMatrix() glPopMatrix(); } +void LLRender::translateUI(F32 x, F32 y, F32 z) +{ + if (mUIOffset.empty()) + { + llerrs << "Need to push a UI translation frame before offsetting" << llendl; + } + + mUIOffset.back().mV[0] += x; + mUIOffset.back().mV[1] += y; + mUIOffset.back().mV[2] += z; +} + +void LLRender::scaleUI(F32 x, F32 y, F32 z) +{ + if (mUIScale.empty()) + { + llerrs << "Need to push a UI transformation frame before scaling." << llendl; + } + + mUIScale.back().scaleVec(LLVector3(x,y,z)); +} + +void LLRender::pushUIMatrix() +{ + if (mUIOffset.empty()) + { + mUIOffset.push_back(LLVector3(0,0,0)); + } + else + { + mUIOffset.push_back(mUIOffset.back()); + } + + if (mUIScale.empty()) + { + mUIScale.push_back(LLVector3(1,1,1)); + } + else + { + mUIScale.push_back(mUIScale.back()); + } +} + +void LLRender::popUIMatrix() +{ + if (mUIOffset.empty()) + { + llerrs << "UI offset stack blown." << llendl; + } + mUIOffset.pop_back(); + mUIScale.pop_back(); +} + +LLVector3 LLRender::getUITranslation() +{ + if (mUIOffset.empty()) + { + return LLVector3::zero; + } + return mUIOffset.back(); +} + +LLVector3 LLRender::getUIScale() +{ + if (mUIScale.empty()) + { + return LLVector3(1.f, 1.f, 1.f); + } + return mUIScale.back(); +} + + +void LLRender::loadUIIdentity() +{ + if (mUIOffset.empty()) + { + llerrs << "Need to push UI translation frame before clearing offset." << llendl; + } + mUIOffset.back().setVec(0,0,0); + mUIScale.back().setVec(1,1,1); +} + void LLRender::setColorMask(bool writeColor, bool writeAlpha) { setColorMask(writeColor, writeColor, writeColor, writeAlpha); @@ -770,29 +942,28 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB void LLRender::setSceneBlendType(eBlendType type) { - flush(); switch (type) { case BT_ALPHA: - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blendFunc(BF_SOURCE_ALPHA, BF_ONE_MINUS_SOURCE_ALPHA); break; case BT_ADD: - glBlendFunc(GL_ONE, GL_ONE); + blendFunc(BF_ONE, BF_ONE); break; case BT_ADD_WITH_ALPHA: - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + blendFunc(BF_SOURCE_ALPHA, BF_ONE); break; case BT_MULT: - glBlendFunc(GL_DST_COLOR, GL_ZERO); + blendFunc(BF_DEST_COLOR, BF_ZERO); break; case BT_MULT_ALPHA: - glBlendFunc(GL_DST_ALPHA, GL_ZERO); + blendFunc(BF_DEST_ALPHA, BF_ZERO); break; case BT_MULT_X2: - glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); + blendFunc(BF_DEST_COLOR, BF_SOURCE_COLOR); break; case BT_REPLACE: - glBlendFunc(GL_ONE, GL_ZERO); + blendFunc(BF_ONE, BF_ZERO); break; default: llerrs << "Unknown Scene Blend Type: " << type << llendl; @@ -818,8 +989,44 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) { - flush(); - glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + llassert(sfactor < BF_UNDEF); + llassert(dfactor < BF_UNDEF); + if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor || + mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor) + { + mCurrBlendColorSFactor = sfactor; + mCurrBlendAlphaSFactor = sfactor; + mCurrBlendColorDFactor = dfactor; + mCurrBlendAlphaDFactor = dfactor; + flush(); + glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + } +} + +void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor) +{ + llassert(color_sfactor < BF_UNDEF); + llassert(color_dfactor < BF_UNDEF); + llassert(alpha_sfactor < BF_UNDEF); + llassert(alpha_dfactor < BF_UNDEF); + if (!gGLManager.mHasBlendFuncSeparate) + { + LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << llendl; + blendFunc(color_sfactor, color_dfactor); + return; + } + if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor || + mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor) + { + mCurrBlendColorSFactor = color_sfactor; + mCurrBlendAlphaSFactor = alpha_sfactor; + mCurrBlendColorDFactor = color_dfactor; + mCurrBlendAlphaDFactor = alpha_dfactor; + flush(); + glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor], + sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]); + } } LLTexUnit* LLRender::getTexUnit(U32 index) @@ -939,6 +1146,39 @@ void LLRender::flush() } #endif + if (!mUIOffset.empty()) + { + sUICalls++; + sUIVerts += mCount; + } + + if (gDebugGL) + { + if (mMode == LLRender::QUADS) + { + if (mCount%4 != 0) + { + llerrs << "Incomplete quad rendered." << llendl; + } + } + + if (mMode == LLRender::TRIANGLES) + { + if (mCount%3 != 0) + { + llerrs << "Incomplete triangle rendered." << llendl; + } + } + + if (mMode == LLRender::LINES) + { + if (mCount%2 != 0) + { + llerrs << "Incomplete line rendered." << llendl; + } + } + } + mBuffer->setBuffer(immediate_mask); mBuffer->drawArrays(mMode, 0, mCount); @@ -958,15 +1198,85 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) return; } - mVerticesp[mCount] = LLVector3(x,y,z); + if (mUIOffset.empty()) + { + mVerticesp[mCount] = LLVector3(x,y,z); + } + else + { + LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back()); + mVerticesp[mCount] = vert; + } + mCount++; - if (mCount < 4096) + mVerticesp[mCount] = mVerticesp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +} + +void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count) +{ + if (mCount + vert_count > 4094) { - mVerticesp[mCount] = mVerticesp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; + // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + return; + } + + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + + mCount++; mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; } + + mVerticesp[mCount] = mVerticesp[mCount-1]; } + +void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count) +{ + if (mCount + vert_count > 4094) + { + // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + return; + } + + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + + mCount++; + mColorsp[mCount] = mColorsp[mCount-1]; + } + + mVerticesp[mCount] = mVerticesp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +} + +void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count) +{ + if (mCount + vert_count > 4094) + { + // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + return; + } + + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount] = colors[i]; + + mCount++; + } + + mVerticesp[mCount] = mVerticesp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; +} + void LLRender::vertex2i(const GLint& x, const GLint& y) { vertex3f((GLfloat) x, (GLfloat) y, 0); diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 31083d8286..2767aa64a8 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -7,31 +7,25 @@ * code, to define an interface for a multiple rendering API abstraction of the UI * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,6 +45,7 @@ class LLVertexBuffer; class LLCubeMap; class LLImageGL; class LLRenderTarget; +class LLTexture ; class LLTexUnit { @@ -148,7 +143,8 @@ public: // Binds the LLImageGL to this texture unit // (automatically enables the unit for the LLImageGL's texture type) - bool bind(LLImageGL* texture, bool forceBind = false); + bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false); + bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false); // Binds a cubemap to this texture unit // (automatically enables the texture unit for cubemaps) @@ -268,7 +264,9 @@ public: BF_DEST_ALPHA, BF_SOURCE_ALPHA, BF_ONE_MINUS_DEST_ALPHA, - BF_ONE_MINUS_SOURCE_ALPHA + BF_ONE_MINUS_SOURCE_ALPHA, + + BF_UNDEF } eBlendFactor; LLRender(); @@ -284,6 +282,14 @@ public: void pushMatrix(); void popMatrix(); + void translateUI(F32 x, F32 y, F32 z); + void scaleUI(F32 x, F32 y, F32 z); + void pushUIMatrix(); + void popUIMatrix(); + void loadUIIdentity(); + LLVector3 getUITranslation(); + LLVector3 getUIScale(); + void flush(); void begin(const GLuint& mode); @@ -305,13 +311,21 @@ public: void color3fv(const GLfloat* c); void color4ubv(const GLubyte* c); + void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count); + void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count); + void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); + void setColorMask(bool writeColor, bool writeAlpha); void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); void setSceneBlendType(eBlendType type); void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f); + // applies blend func to both color and alpha void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor); + // applies separate blend functions to color and alpha + void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); LLTexUnit* getTexUnit(U32 index); @@ -331,7 +345,9 @@ public: }; public: - + static U32 sUICalls; + static U32 sUIVerts; + private: bool mDirty; U32 mCount; @@ -348,11 +364,21 @@ private: std::vector<LLTexUnit*> mTexUnits; LLTexUnit* mDummyTexUnit; + eBlendFactor mCurrBlendColorSFactor; + eBlendFactor mCurrBlendColorDFactor; + eBlendFactor mCurrBlendAlphaSFactor; + eBlendFactor mCurrBlendAlphaDFactor; + F32 mMaxAnisotropy; + + std::vector<LLVector3> mUIOffset; + std::vector<LLVector3> mUIScale; + }; extern F64 gGLModelView[16]; extern F64 gGLLastModelView[16]; +extern F64 gGLLastProjection[16]; extern F64 gGLProjection[16]; extern S32 gGLViewport[4]; diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp index e22b753923..a5cd70445f 100644 --- a/indra/llrender/llrendersphere.cpp +++ b/indra/llrender/llrendersphere.cpp @@ -2,31 +2,25 @@ * @file llrendersphere.cpp * @brief implementation of the LLRenderSphere class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -68,45 +62,6 @@ void drawSolidSphere(GLdouble radius, GLint slices, GLint 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 @@ -181,3 +136,50 @@ void LLRenderSphere::render() { glCallList(mDList[0]); } + +inline LLVector3 polar_to_cart(F32 latitude, F32 longitude) +{ + return LLVector3(sin(F_TWO_PI * latitude) * cos(F_TWO_PI * longitude), + sin(F_TWO_PI * latitude) * sin(F_TWO_PI * longitude), + cos(F_TWO_PI * latitude)); +} + + +void LLRenderSphere::renderGGL() +{ + S32 const LATITUDE_SLICES = 20; + S32 const LONGITUDE_SLICES = 30; + + if (mSpherePoints.empty()) + { + mSpherePoints.resize(LATITUDE_SLICES + 1); + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++) + { + mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1); + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES + 1; lon_i++) + { + F32 lat = (F32)lat_i / LATITUDE_SLICES; + F32 lon = (F32)lon_i / LONGITUDE_SLICES; + + mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon); + } + } + } + + gGL.begin(LLRender::TRIANGLES); + + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) + { + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) + { + gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV); + } + } + gGL.end(); +} diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h index 617ee3e12e..96a6bec80c 100644 --- a/indra/llrender/llrendersphere.h +++ b/indra/llrender/llrendersphere.h @@ -2,31 +2,25 @@ * @file llrendersphere.h * @brief interface for the LLRenderSphere class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -52,6 +46,10 @@ public: void cleanupGL(); void render(F32 pixel_area); // of a box of size 1.0 at that position void render(); // render at highest LOD + void renderGGL(); // render using LLRender + +private: + std::vector< std::vector<LLVector3> > mSpherePoints; }; extern LLRenderSphere gSphere; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index dc052851ca..890230bbe5 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -2,31 +2,25 @@ * @file llrendertarget.cpp * @brief LLRenderTarget implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -140,7 +134,7 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt) U32 offset = mTex.size(); if (offset >= 4 || - offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)) + (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers))) { llerrs << "Too many color attachments!" << llendl; } @@ -204,7 +198,7 @@ void LLRenderTarget::allocateDepth() gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8_EXT, mResX, mResY, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32_ARB, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } } @@ -382,7 +376,7 @@ void LLRenderTarget::flush(BOOL fetch_depth) allocateDepth(); } - gGL.getTexUnit(0)->bind(this, true); + gGL.getTexUnit(0)->bind(this); glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0); } @@ -392,7 +386,11 @@ void LLRenderTarget::flush(BOOL fetch_depth) { #if !LL_DARWIN + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + stop_glerror(); if (mSampleBuffer) { @@ -434,7 +432,6 @@ void LLRenderTarget::flush(BOOL fetch_depth) #endif glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glFlush(); } } @@ -442,6 +439,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) { #if !LL_DARWIN + gGL.flush(); if (!source.mFBO || !mFBO) { llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl; @@ -453,12 +451,55 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, } else { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO); + if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil) + { + stop_glerror(); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, source.mFBO); + gGL.getTexUnit(0)->bind(this, true); + stop_glerror(); + glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1); + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); + } + else + { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); + stop_glerror(); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO); + stop_glerror(); + check_framebuffer_status(); + stop_glerror(); + glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + stop_glerror(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); + } + } +#endif +} +//static +void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, + S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) +{ +#if !LL_DARWIN + if (!source.mFBO) + { + llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl; + } + { + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO); + stop_glerror(); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); + stop_glerror(); + check_framebuffer_status(); + stop_glerror(); glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - + stop_glerror(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + stop_glerror(); } #endif } @@ -613,7 +654,7 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt) U32 offset = mTex.size(); if (offset >= 4 || - offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)) + (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers))) { llerrs << "Too many color attachments!" << llendl; } diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 98b608f834..ae8613d9be 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -2,31 +2,25 @@ * @file llrendertarget.h * @brief Off screen render target abstraction. Loose wrapper for GL_EXT_framebuffer_objects. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -121,6 +115,7 @@ public: U32 getTexture(U32 attachment = 0) const; U32 getDepth(void) const { return mDepth; } + BOOL hasStencil() const { return mStencil; } void bindTexture(U32 index, S32 channel); @@ -135,6 +130,9 @@ public: void copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter); + static void copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, + S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter); + //Returns TRUE if target is ready to be rendered into. //That is, if the target has been allocated with at least //one renderable attachment (i.e. color buffer, depth buffer). diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 1286e91e49..c859d41e17 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -2,31 +2,25 @@ * @file llshadermgr.cpp * @brief Shader manager implementation. * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 2488c7ab00..c54c4608d7 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -2,31 +2,25 @@ * @file llshadermgr.h * @brief Shader Manager * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llrender/lltexture.cpp b/indra/llrender/lltexture.cpp new file mode 100644 index 0000000000..90fbcec2be --- /dev/null +++ b/indra/llrender/lltexture.cpp @@ -0,0 +1,31 @@ +/** + * @file lltexture.cpp + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "linden_common.h" +#include "lltexture.h" + +//virtual +LLTexture::~LLTexture() +{ +} diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h new file mode 100644 index 0000000000..569a65c2e0 --- /dev/null +++ b/indra/llrender/lltexture.h @@ -0,0 +1,73 @@ +/** + * @file lltexture.h + * @brief LLTexture definition + * + * This class acts as a wrapper for OpenGL calls. + * The goal of this class is to minimize the number of api calls due to legacy rendering + * code, to define an interface for a multiple rendering API abstraction of the UI + * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_TEXTURE_H +#define LL_TEXTURE_H + +#include "llrefcount.h" +class LLImageGL ; +class LLTexUnit ; +class LLFontGL ; + +// +//this is an abstract class as the parent for the class LLViewerTexture +//through the following virtual functions, the class LLViewerTexture can be reached from /llrender. +// +class LLTexture : public LLRefCount +{ + friend class LLTexUnit ; + friend class LLFontGL ; + +protected: + virtual ~LLTexture(); + +public: + LLTexture(){} + + // + //interfaces to access LLViewerTexture + // + virtual S8 getType() const = 0 ; + virtual void setKnownDrawSize(S32 width, S32 height) = 0 ; + virtual bool bindDefaultImage(const S32 stage = 0) = 0 ; + virtual void forceImmediateUpdate() = 0 ; + virtual void setActive() = 0 ; + virtual S32 getWidth(S32 discard_level = -1) const = 0 ; + virtual S32 getHeight(S32 discard_level = -1) const = 0 ; + +private: + //note: do not make this function public. + virtual LLImageGL* getGLTexture() const = 0 ; + + virtual void updateBindStatsForTester() = 0 ; +}; +#endif + diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index db4189dfea..de4501dd0f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -2,31 +2,25 @@ * @file llvertexbuffer.cpp * @brief LLVertexBuffer implementation * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -61,6 +55,7 @@ BOOL LLVertexBuffer::sVBOActive = FALSE; BOOL LLVertexBuffer::sIBOActive = FALSE; U32 LLVertexBuffer::sAllocatedBytes = 0; BOOL LLVertexBuffer::sMapped = FALSE; +BOOL LLVertexBuffer::sUseStreamDraw = TRUE; std::vector<U32> LLVertexBuffer::sDeleteList; @@ -215,14 +210,18 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const { + llassert(mRequestedNumVerts >= 0); + if (start >= (U32) mRequestedNumVerts || - end >= (U32) mRequestedNumVerts) + end >= (U32) mRequestedNumVerts) { llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "]" << llendl; } + llassert(mRequestedNumIndices >= 0); + if (indices_offset >= (U32) mRequestedNumIndices || - indices_offset + count > (U32) mRequestedNumIndices) + indices_offset + count > (U32) mRequestedNumIndices) { llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } @@ -237,7 +236,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi llerrs << "Wrong vertex buffer bound." << llendl; } - if (mode > LLRender::NUM_MODES) + if (mode >= LLRender::NUM_MODES) { llerrs << "Invalid draw mode: " << mode << llendl; return; @@ -251,8 +250,9 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { + llassert(mRequestedNumIndices >= 0); if (indices_offset >= (U32) mRequestedNumIndices || - indices_offset + count > (U32) mRequestedNumIndices) + indices_offset + count > (U32) mRequestedNumIndices) { llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; } @@ -267,7 +267,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const llerrs << "Wrong vertex buffer bound." << llendl; } - if (mode > LLRender::NUM_MODES) + if (mode >= LLRender::NUM_MODES) { llerrs << "Invalid draw mode: " << mode << llendl; return; @@ -281,8 +281,9 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { + llassert(mRequestedNumVerts >= 0); if (first >= (U32) mRequestedNumVerts || - first + count > (U32) mRequestedNumVerts) + first + count > (U32) mRequestedNumVerts) { llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; } @@ -292,7 +293,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const llerrs << "Wrong vertex buffer bound." << llendl; } - if (mode > LLRender::NUM_MODES) + if (mode >= LLRender::NUM_MODES) { llerrs << "Invalid draw mode: " << mode << llendl; return; @@ -354,7 +355,14 @@ void LLVertexBuffer::clientCopy(F64 max_time) LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : LLRefCount(), - mNumVerts(0), mNumIndices(0), mUsage(usage), mGLBuffer(0), mGLIndices(0), + + mNumVerts(0), + mNumIndices(0), + mRequestedNumVerts(-1), + mRequestedNumIndices(-1), + mUsage(usage), + mGLBuffer(0), + mGLIndices(0), mMappedData(NULL), mMappedIndexData(NULL), mLocked(FALSE), mFinal(FALSE), @@ -368,7 +376,17 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : { mUsage = 0 ; } + + if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) + { + mUsage = 0; + } + if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) + { + mUsage = 0; + } + S32 stride = calcStride(typemask, mOffsets); mTypeMask = typemask; @@ -600,6 +618,8 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) { LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS); + llassert(nverts >= 0); + if (nverts >= 65535) { llwarns << "Vertex buffer overflow!" << llendl; @@ -628,6 +648,9 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) void LLVertexBuffer::updateNumIndices(S32 nindices) { LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES); + + llassert(nindices >= 0); + mRequestedNumIndices = nindices; if (!mDynamicSize) { @@ -668,6 +691,9 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { + llassert(newnverts >= 0); + llassert(newnindices >= 0); + mRequestedNumVerts = newnverts; mRequestedNumIndices = newnindices; @@ -792,7 +818,7 @@ BOOL LLVertexBuffer::useVBOs() const return FALSE; } #endif - return sEnableVBOs; + return TRUE; } //---------------------------------------------------------------------------- @@ -1061,17 +1087,20 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) + if (mGLIndices) { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; - } - else + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; + } + else + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } } @@ -1095,17 +1124,20 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) + if (mGLIndices != 0) { - if (gDebugSession) + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); + if ((GLuint)buff != mGLIndices) { - error = TRUE; - gFailLog << "Invalid GL index buffer bound: "<< std::endl; - } - else - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL index buffer bound: "<< std::endl; + } + else + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } } @@ -1150,7 +1182,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) { if (mGLBuffer) { - if (sEnableVBOs && sVBOActive) + if (sVBOActive) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); sBindCount++; @@ -1162,7 +1194,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) setup = TRUE; // ... or a client memory pointer changed } } - if (sEnableVBOs && mGLIndices && sIBOActive) + if (mGLIndices && sIBOActive) { /*if (sMapped) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index b785a22976..94fa790957 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -2,31 +2,25 @@ * @file llvertexbuffer.h * @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -84,6 +78,8 @@ public: static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + static BOOL sUseStreamDraw; + static void initClass(bool use_vbo); static void cleanupClass(); static void setupClientArrays(U32 data_mask); |