llimagegl.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:46k
- /**
- * @file llimagegl.cpp
- * @brief Generic GL image handler
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- // TODO: create 2 classes for images w/ and w/o discard levels?
- #include "linden_common.h"
- #include "llimagegl.h"
- #include "llerror.h"
- #include "llimage.h"
- #include "llmath.h"
- #include "llgl.h"
- #include "llrender.h"
- //----------------------------------------------------------------------------
- const F32 MIN_TEXTURE_LIFETIME = 10.f;
- //statics
- LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
- U32 LLImageGL::sUniqueCount = 0;
- U32 LLImageGL::sBindCount = 0;
- 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.
- void check_all_images()
- {
- for (std::set<LLImageGL*>::iterator iter = LLImageGL::sImageList.begin();
- iter != LLImageGL::sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if (glimage->getTexName() && glimage->isGLTextureCreated())
- {
- gGL.getTexUnit(0)->bind(glimage) ;
- glimage->checkTexSize() ;
- gGL.getTexUnit(0)->unbind(glimage->getTarget()) ;
- }
- }
- }
- void LLImageGL::checkTexSize() const
- {
- if (gDebugGL && mTarget == GL_TEXTURE_2D)
- {
- GLint texname;
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname);
- BOOL error = FALSE;
- if (texname != mTexName)
- {
- error = TRUE;
- if (gDebugSession)
- {
- gFailLog << "Invalid texture bound!" << std::endl;
- }
- else
- {
- llerrs << "Invalid texture bound!" << llendl;
- }
- }
- stop_glerror() ;
- LLGLint x = 0, y = 0 ;
- glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_WIDTH, (GLint*)&x);
- glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_HEIGHT, (GLint*)&y) ;
- stop_glerror() ;
- if(!x || !y)
- {
- return ;
- }
- if(x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel))
- {
- error = TRUE;
- if (gDebugSession)
- {
- gFailLog << "wrong texture size and discard level!" << std::endl;
- }
- else
- {
- llerrs << "wrong texture size and discard level!" << llendl ;
- }
- }
- if (error)
- {
- ll_fail("LLImageGL::checkTexSize failed.");
- }
- }
- }
- //end of debug functions
- //**************************************************************************************
- //----------------------------------------------------------------------------
- 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)
- {
- switch (dataformat)
- {
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4;
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8;
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8;
- case GL_LUMINANCE: return 8;
- case GL_ALPHA: return 8;
- case GL_COLOR_INDEX: return 8;
- case GL_LUMINANCE_ALPHA: return 16;
- case GL_RGB: return 24;
- case GL_RGB8: return 24;
- case GL_RGBA: return 32;
- case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac
- default:
- llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
- return 0;
- }
- }
- //static
- S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
- {
- if (dataformat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
- dataformat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
- {
- if (width < 4) width = 4;
- if (height < 4) height = 4;
- }
- S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3);
- S32 aligned = (bytes+3)&~3;
- return aligned;
- }
- //static
- S32 LLImageGL::dataFormatComponents(S32 dataformat)
- {
- switch (dataformat)
- {
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3;
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4;
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4;
- case GL_LUMINANCE: return 1;
- case GL_ALPHA: return 1;
- case GL_COLOR_INDEX: return 1;
- case GL_LUMINANCE_ALPHA: return 2;
- case GL_RGB: return 3;
- case GL_RGBA: return 4;
- case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac
- default:
- llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
- return 0;
- }
- }
- //----------------------------------------------------------------------------
- // static
- 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 mem, const S32 ncomponents, S32 category)
- {
- if(gAuditTexture && ncomponents > 0 && category > -1)
- {
- sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ;
- sTextureCurMemByCategoryBound[category] += mem ;
- }
-
- LLImageGL::sCurBoundTextureMemory += mem ;
- return LLImageGL::sCurBoundTextureMemory;
- }
- //----------------------------------------------------------------------------
- //static
- void LLImageGL::destroyGL(BOOL save_state)
- {
- for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++)
- {
- gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE);
- }
-
- sAllowReadBackRaw = true ;
- for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if (glimage->mTexName)
- {
- if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
- {
- glimage->mSaveData = new LLImageRaw;
- if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
- {
- glimage->mSaveData = NULL ;
- }
- }
- glimage->destroyGLTexture();
- stop_glerror();
- }
- }
- sAllowReadBackRaw = false ;
- }
- //static
- void LLImageGL::restoreGL()
- {
- for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
- iter != sImageList.end(); iter++)
- {
- LLImageGL* glimage = *iter;
- if(glimage->getTexName())
- {
- llerrs << "tex name is not 0." << llendl ;
- }
- if (glimage->mSaveData.notNull())
- {
- if (glimage->getComponents() && glimage->mSaveData->getComponents())
- {
- glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory());
- stop_glerror();
- }
- glimage->mSaveData = NULL; // deletes data
- }
- }
- }
- //----------------------------------------------------------------------------
- //for server side use only.
- //static
- BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps)
- {
- dest = new LLImageGL(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);
- return TRUE;
- }
- //----------------------------------------------------------------------------
- LLImageGL::LLImageGL(BOOL usemipmaps)
- : mSaveData(0)
- {
- init(usemipmaps);
- setSize(0, 0, 0);
- sImageList.insert(this);
- sCount++;
- }
- LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
- : mSaveData(0)
- {
- llassert( components <= 4 );
- init(usemipmaps);
- setSize(width, height, components);
- sImageList.insert(this);
- sCount++;
- }
- LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
- : mSaveData(0)
- {
- init(usemipmaps);
- setSize(0, 0, 0);
- sImageList.insert(this);
- sCount++;
- createGLTexture(0, imageraw);
- }
- LLImageGL::~LLImageGL()
- {
- LLImageGL::cleanup();
- sImageList.erase(this);
- delete [] mPickMask;
- mPickMask = NULL;
- sCount--;
- }
- void LLImageGL::init(BOOL usemipmaps)
- {
- // 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;
- 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;
- mComponents = 0;
- mMaxDiscardLevel = MAX_DISCARD_LEVEL;
- mTexOptionsDirty = true;
- mAddressMode = LLTexUnit::TAM_WRAP;
- mFilterOption = LLTexUnit::TFO_ANISOTROPIC;
-
- mFormatInternal = -1;
- mFormatPrimary = (LLGLenum) 0;
- mFormatType = GL_UNSIGNED_BYTE;
- mFormatSwapBytes = FALSE;
- #ifdef DEBUG_MISS
- mMissed = FALSE;
- #endif
- mCategory = -1;
- }
- void LLImageGL::cleanup()
- {
- if (!gGLManager.mIsDisabled)
- {
- destroyGLTexture();
- }
- mSaveData = NULL; // deletes data
- }
- //----------------------------------------------------------------------------
- //this function is used to check the size of a texture image.
- //so dim should be a positive number
- static bool check_power_of_two(S32 dim)
- {
- if(dim < 0)
- {
- return false ;
- }
- if(!dim)//0 is a power-of-two number
- {
- return true ;
- }
- return !(dim & (dim - 1)) ;
- }
- //static
- bool LLImageGL::checkSize(S32 width, S32 height)
- {
- return check_power_of_two(width) && check_power_of_two(height);
- }
- void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)
- {
- if (width != mWidth || height != mHeight || ncomponents != mComponents)
- {
- // Check if dimensions are a power of two!
- if (!checkSize(width,height))
- {
- llerrs << llformat("Texture has non power of two dimension: %dx%d",width,height) << llendl;
- }
-
- if (mTexName)
- {
- // 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;
- if (ncomponents > 0)
- {
- mMaxDiscardLevel = 0;
- while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL)
- {
- mMaxDiscardLevel++;
- width >>= 1;
- height >>= 1;
- }
- }
- else
- {
- mMaxDiscardLevel = MAX_DISCARD_LEVEL;
- }
- }
- }
- //----------------------------------------------------------------------------
- // virtual
- void LLImageGL::dump()
- {
- llinfos << "mMaxDiscardLevel " << S32(mMaxDiscardLevel)
- << " mLastBindTime " << mLastBindTime
- << " mTarget " << S32(mTarget)
- << " mBindTarget " << S32(mBindTarget)
- << " mUseMipMaps " << S32(mUseMipMaps)
- << " mHasMipMaps " << S32(mHasMipMaps)
- << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel)
- << " mFormatInternal " << S32(mFormatInternal)
- << " mFormatPrimary " << S32(mFormatPrimary)
- << " mFormatType " << S32(mFormatType)
- << " mFormatSwapBytes " << S32(mFormatSwapBytes)
- << " mHasExplicitFormat " << S32(mHasExplicitFormat)
- #if DEBUG_MISS
- << " mMissed " << mMissed
- #endif
- << llendl;
- llinfos << " mTextureMemory " << mTextureMemory
- << " mTexNames " << mTexName
- << " mIsResident " << S32(mIsResident)
- << llendl;
- }
- //----------------------------------------------------------------------------
- void LLImageGL::forceUpdateBindStats(void) const
- {
- mLastBindTime = sLastFrameTime;
- }
- BOOL LLImageGL::updateBindStats(S32 tex_mem) const
- {
- if (mTexName != 0)
- {
- #ifdef DEBUG_MISS
- mMissed = ! getIsResident(TRUE);
- #endif
- sBindCount++;
- if (mLastBindTime != sLastFrameTime)
- {
- // we haven't accounted for this texture yet this frame
- sUniqueCount++;
- updateBoundTexMem(tex_mem, mComponents, mCategory);
- mLastBindTime = sLastFrameTime;
- return TRUE ;
- }
- }
- return FALSE ;
- }
- F32 LLImageGL::getTimePassedSinceLastBound()
- {
- return sLastFrameTime - mLastBindTime ;
- }
- void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes )
- {
- // Note: must be called before createTexture()
- // Note: it's up to the caller to ensure that the format matches the number of components.
- mHasExplicitFormat = TRUE;
- mFormatInternal = internal_format;
- mFormatPrimary = primary_format;
- if(type_format == 0)
- mFormatType = GL_UNSIGNED_BYTE;
- else
- mFormatType = type_format;
- mFormatSwapBytes = swap_bytes;
- calcAlphaChannelOffsetAndStride() ;
- }
- //----------------------------------------------------------------------------
- void LLImageGL::setImage(const LLImageRaw* imageraw)
- {
- llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
- (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
- (imageraw->getComponents() == getComponents()));
- const U8* rawdata = imageraw->getData();
- setImage(rawdata, FALSE);
- }
- void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
- {
- bool is_compressed = false;
- if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
- {
- is_compressed = true;
- }
- llverify(gGL.getTexUnit(0)->bind(this));
-
- if (mUseMipMaps)
- {
- if (data_hasmips)
- {
- // NOTE: data_in points to largest image; smaller images
- // are stored BEFORE the largest image
- for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++)
- {
-
- S32 w = getWidth(d);
- S32 h = getHeight(d);
- S32 gl_level = d-mCurrentDiscardLevel;
- if (d > mCurrentDiscardLevel)
- {
- data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
- }
- if (is_compressed)
- {
- 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(FTM_TEMP4);
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
-
- LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
- if (gl_level == 0)
- {
- analyzeAlpha(data_in, w, h);
- }
- updatePickMask(w, h, data_in);
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
-
- stop_glerror();
- }
- stop_glerror();
- }
- }
- else if (!is_compressed)
- {
- if (mAutoGenMips)
- {
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
- stop_glerror();
- {
- // LLFastTimer t2(FTM_TEMP4);
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
- S32 w = getWidth(mCurrentDiscardLevel);
- S32 h = getHeight(mCurrentDiscardLevel);
- LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
- w, h,
- mFormatPrimary, mFormatType,
- data_in);
- analyzeAlpha(data_in, w, h);
- stop_glerror();
- updatePickMask(w, h, data_in);
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
- }
- }
- else
- {
- // Create mips by hand
- // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
- // ~4x faster than gluBuild2DMipmaps
- S32 width = getWidth(mCurrentDiscardLevel);
- S32 height = getHeight(mCurrentDiscardLevel);
- S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1;
- S32 w = width, h = height;
- const U8* prev_mip_data = 0;
- const U8* cur_mip_data = 0;
- S32 prev_mip_size = 0;
- S32 cur_mip_size = 0;
- for (int m=0; m<nummips; m++)
- {
- if (m==0)
- {
- cur_mip_data = data_in;
- cur_mip_size = width * height * mComponents;
- }
- else
- {
- S32 bytes = w * h * mComponents;
- llassert(prev_mip_data);
- llassert(prev_mip_size == bytes*4);
- U8* new_data = new U8[bytes];
- llassert_always(new_data);
- LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
- cur_mip_data = new_data;
- cur_mip_size = bytes;
- }
- llassert(w > 0 && h > 0 && cur_mip_data);
- {
- // LLFastTimer t1(FTM_TEMP4);
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
- LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
- if (m == 0)
- {
- analyzeAlpha(data_in, w, h);
- }
- stop_glerror();
- if (m == 0)
- {
- updatePickMask(w, h, cur_mip_data);
- }
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
- }
- if (prev_mip_data && prev_mip_data != data_in)
- {
- delete[] prev_mip_data;
- }
- prev_mip_data = cur_mip_data;
- prev_mip_size = cur_mip_size;
- w >>= 1;
- h >>= 1;
- }
- if (prev_mip_data && prev_mip_data != data_in)
- {
- delete[] prev_mip_data;
- prev_mip_data = NULL;
- }
- }
- }
- else
- {
- llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
- }
- mHasMipMaps = true;
- }
- else
- {
- S32 w = getWidth();
- S32 h = getHeight();
- if (is_compressed)
- {
- S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
- glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
- stop_glerror();
- }
- else
- {
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
- LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h,
- mFormatPrimary, mFormatType, (GLvoid *)data_in);
- analyzeAlpha(data_in, w, h);
-
- updatePickMask(w, h, data_in);
- stop_glerror();
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
- }
- mHasMipMaps = false;
- }
- stop_glerror();
- mGLTextureCreated = true;
- }
- 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)
- {
- if (!width || !height)
- {
- return TRUE;
- }
- if (mTexName == 0)
- {
- llwarns << "Setting subimage on image without GL texture" << llendl;
- return FALSE;
- }
- if (datap == NULL)
- {
- llwarns << "Setting subimage on image with NULL datap" << llendl;
- return FALSE;
- }
-
- // 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);
- }
- else
- {
- if (mUseMipMaps)
- {
- dump();
- llerrs << "setSubImage called with mipmapped image (not supported)" << llendl;
- }
- llassert_always(mCurrentDiscardLevel == 0);
- llassert_always(x_pos >= 0 && y_pos >= 0);
-
- if (((x_pos + width) > getWidth()) ||
- (y_pos + height) > getHeight())
- {
- dump();
- llerrs << "Subimage not wholly in target image!"
- << " x_pos " << x_pos
- << " y_pos " << y_pos
- << " width " << width
- << " height " << height
- << " getWidth() " << getWidth()
- << " getHeight() " << getHeight()
- << llendl;
- }
- if ((x_pos + width) > data_width ||
- (y_pos + height) > data_height)
- {
- dump();
- llerrs << "Subimage not wholly in source image!"
- << " x_pos " << x_pos
- << " y_pos " << y_pos
- << " width " << width
- << " height " << height
- << " source_width " << data_width
- << " source_height " << data_height
- << llendl;
- }
- glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width);
- stop_glerror();
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- stop_glerror();
- }
- datap += (y_pos * data_width + x_pos) * getComponents();
- // Update the GL texture
- BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName);
- if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl;
- stop_glerror();
- glTexSubImage2D(mTarget, 0, x_pos, y_pos,
- width, height, mFormatPrimary, mFormatType, datap);
- gGL.getTexUnit(0)->disable();
- stop_glerror();
- if(mFormatSwapBytes)
- {
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
- stop_glerror();
- }
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- stop_glerror();
- mGLTextureCreated = true;
- }
- return TRUE;
- }
- 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, 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, false, true))
- {
- //checkTexSize() ;
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
- mGLTextureCreated = true;
- stop_glerror();
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- // static
- void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
- {
- glGenTextures(numTextures, (GLuint*)textures);
- }
- // static
- void LLImageGL::deleteTextures(S32 numTextures, U32 *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
- //the texture is assiciate with some image by calling glTexImage outside LLImageGL
- BOOL LLImageGL::createGLTexture()
- {
- if (gGLManager.mIsDisabled)
- {
- llwarns << "Trying to create a texture while GL is disabled!" << llendl;
- return FALSE;
- }
-
- mGLTextureCreated = false ; //do not save this texture when gl is destroyed.
- llassert(gGLManager.mInited);
- stop_glerror();
- if(mTexName)
- {
- glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
- }
-
- glGenTextures(1, (GLuint*)&mTexName);
- stop_glerror();
- if (!mTexName)
- {
- llerrs << "LLImageGL::createGLTexture failed to make an empty texture" << llendl;
- }
- return TRUE ;
- }
- BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
- {
- if (gGLManager.mIsDisabled)
- {
- llwarns << "Trying to create a texture while GL is disabled!" << llendl;
- return FALSE;
- }
- mGLTextureCreated = 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 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());
- 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;
- }
- 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)
- {
- llassert(data_in);
- if (discard_level < 0)
- {
- llassert(mCurrentDiscardLevel >= 0);
- discard_level = mCurrentDiscardLevel;
- }
- discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
- if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
- {
- // This will only be true if the size has not changed
- setImage(data_in, data_hasmips);
- return TRUE;
- }
-
- U32 old_name = mTexName;
- // S32 old_discard = mCurrentDiscardLevel;
-
- if (usename != 0)
- {
- mTexName = usename;
- }
- else
- {
- LLImageGL::generateTextures(1, &mTexName);
- stop_glerror();
- {
- 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);
- }
- }
- if (!mTexName)
- {
- llerrs << "LLImageGL::createGLTexture failed to make texture" << llendl;
- }
- if (mUseMipMaps)
- {
- mAutoGenMips = gGLManager.mHasMipMapGeneration;
- #if LL_DARWIN
- // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
- if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
- {
- mAutoGenMips = FALSE;
- }
- #endif
- }
- mCurrentDiscardLevel = discard_level;
- setImage(data_in, data_hasmips);
- // Set texture options to our defaults.
- gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
- gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
- gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
- // things will break if we don't unbind after creation
- gGL.getTexUnit(0)->unbind(mBindTarget);
- stop_glerror();
- 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;
- 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;
- return TRUE;
- }
- BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
- {
- llassert_always(sAllowReadBackRaw) ;
- //llerrs << "should not call this function!" << llendl ;
-
- if (discard_level < 0)
- {
- discard_level = mCurrentDiscardLevel;
- }
-
- if (mTexName == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel )
- {
- return FALSE;
- }
- S32 gl_discard = discard_level - mCurrentDiscardLevel;
- //explicitly unbind texture
- gGL.getTexUnit(0)->unbind(mBindTarget);
- llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName));
- //debug code, leave it there commented.
- //checkTexSize() ;
- LLGLint glwidth = 0;
- glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
- if (glwidth == 0)
- {
- // No mip data smaller than current discard level
- return FALSE;
- }
-
- S32 width = getWidth(discard_level);
- S32 height = getHeight(discard_level);
- S32 ncomponents = getComponents();
- if (ncomponents == 0)
- {
- return FALSE;
- }
- if(width < glwidth)
- {
- llwarns << "texture size is smaller than it should be." << llendl ;
- llwarns << "width: " << width << " glwidth: " << glwidth << " mWidth: " << mWidth <<
- " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << llendl ;
- return FALSE ;
- }
- if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4)
- {
- llerrs << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << llendl;
- }
-
- LLGLint is_compressed = 0;
- if (compressed_ok)
- {
- glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
- }
-
- //-----------------------------------------------------------------------------------------------
- GLenum error ;
- while((error = glGetError()) != GL_NO_ERROR)
- {
- llwarns << "GL Error happens before reading back texture. Error code: " << error << llendl ;
- }
- //-----------------------------------------------------------------------------------------------
- if (is_compressed)
- {
- LLGLint glbytes;
- glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes);
- if(!imageraw->allocateDataSize(width, height, ncomponents, glbytes))
- {
- llwarns << "Memory allocation failed for reading back texture. Size is: " << glbytes << llendl ;
- llwarns << "width: " << width << "height: " << height << "components: " << ncomponents << llendl ;
- return FALSE ;
- }
- glGetCompressedTexImageARB(mTarget, gl_discard, (GLvoid*)(imageraw->getData()));
- //stop_glerror();
- }
- else
- {
- if(!imageraw->allocateDataSize(width, height, ncomponents))
- {
- llwarns << "Memory allocation failed for reading back texture." << llendl ;
- llwarns << "width: " << width << "height: " << height << "components: " << ncomponents << llendl ;
- return FALSE ;
- }
-
- glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData()));
- //stop_glerror();
- }
-
- //-----------------------------------------------------------------------------------------------
- if((error = glGetError()) != GL_NO_ERROR)
- {
- llwarns << "GL Error happens after reading back texture. Error code: " << error << llendl ;
- imageraw->deleteData() ;
- while((error = glGetError()) != GL_NO_ERROR)
- {
- llwarns << "GL Error happens after reading back texture. Error code: " << error << llendl ;
- }
- return FALSE ;
- }
- //-----------------------------------------------------------------------------------------------
- return TRUE ;
- }
- void LLImageGL::deleteDeadTextures()
- {
- while (!sDeadTextureList.empty())
- {
- GLuint tex = sDeadTextureList.front();
- sDeadTextureList.pop_front();
- for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
- {
- if (sCurrentBoundTextures[i] == tex)
- {
- gGL.getTexUnit(i)->unbind(LLTexUnit::TT_TEXTURE);
- stop_glerror();
- }
- }
-
- 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 ;
- }
- }
- //----------------------------------------------------------------------------
- void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode)
- {
- if (mAddressMode != mode)
- {
- mTexOptionsDirty = true;
- mAddressMode = mode;
- }
- if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName)
- {
- gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode);
- mTexOptionsDirty = false;
- }
- }
- void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option)
- {
- if (mFilterOption != option)
- {
- mTexOptionsDirty = true;
- mFilterOption = option;
- }
- if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName)
- {
- gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option);
- mTexOptionsDirty = false;
- stop_glerror();
- }
- }
- BOOL LLImageGL::getIsResident(BOOL test_now)
- {
- if (test_now)
- {
- if (mTexName != 0)
- {
- glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident);
- }
- else
- {
- mIsResident = FALSE;
- }
- }
- return mIsResident;
- }
- S32 LLImageGL::getHeight(S32 discard_level) const
- {
- if (discard_level < 0)
- {
- discard_level = mCurrentDiscardLevel;
- }
- S32 height = mHeight >> discard_level;
- if (height < 1) height = 1;
- return height;
- }
- S32 LLImageGL::getWidth(S32 discard_level) const
- {
- if (discard_level < 0)
- {
- discard_level = mCurrentDiscardLevel;
- }
- S32 width = mWidth >> discard_level;
- if (width < 1) width = 1;
- return width;
- }
- S32 LLImageGL::getBytes(S32 discard_level) const
- {
- if (discard_level < 0)
- {
- discard_level = mCurrentDiscardLevel;
- }
- S32 w = mWidth>>discard_level;
- S32 h = mHeight>>discard_level;
- if (w == 0) w = 1;
- if (h == 0) h = 1;
- return dataFormatBytes(mFormatPrimary, w, h);
- }
- S32 LLImageGL::getMipBytes(S32 discard_level) const
- {
- if (discard_level < 0)
- {
- discard_level = mCurrentDiscardLevel;
- }
- S32 w = mWidth>>discard_level;
- S32 h = mHeight>>discard_level;
- S32 res = dataFormatBytes(mFormatPrimary, w, h);
- if (mUseMipMaps)
- {
- while (w > 1 && h > 1)
- {
- w >>= 1; if (w == 0) w = 1;
- h >>= 1; if (h == 0) h = 1;
- res += dataFormatBytes(mFormatPrimary, w, h);
- }
- }
- return res;
- }
- BOOL LLImageGL::isJustBound() const
- {
- return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f);
- }
- BOOL LLImageGL::getBoundRecently() const
- {
- return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
- }
- void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target)
- {
- mTarget = target;
- mBindTarget = bind_target;
- }
- const S8 INVALID_OFFSET = -99 ;
- void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask)
- {
- if(mNeedsAlphaAndPickMask != need_mask)
- {
- 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 ;
- }
- mAlphaStride = -1 ;
- switch (mFormatPrimary)
- {
- case GL_LUMINANCE:
- case GL_ALPHA:
- mAlphaStride = 1;
- break;
- case GL_LUMINANCE_ALPHA:
- mAlphaStride = 2;
- break;
- case GL_RGB:
- mNeedsAlphaAndPickMask = FALSE ;
- mIsMask = FALSE;
- return ; //no alpha channel.
- case GL_RGBA:
- mAlphaStride = 4;
- break;
- case GL_BGRA_EXT:
- mAlphaStride = 4;
- break;
- default:
- break;
- }
- mAlphaOffset = -1 ;
- if (mFormatType == GL_UNSIGNED_BYTE)
- {
- mAlphaOffset = mAlphaStride - 1 ;
- }
- else if(is_little_endian())
- {
- 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 //big endian
- {
- if (mFormatType == GL_UNSIGNED_INT_8_8_8_8)
- {
- mAlphaOffset = 3 ;
- }
- else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV)
- {
- mAlphaOffset = 0 ;
- }
- }
- 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;
- mNeedsAlphaAndPickMask = FALSE ;
- mIsMask = FALSE;
- }
- }
- void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
- {
- if(!mNeedsAlphaAndPickMask)
- {
- return ;
- }
- U32 length = w * h;
- const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset ;
-
- S32 sample[16];
- memset(sample, 0, sizeof(S32)*16);
- for (U32 i = 0; i < length; i++)
- {
- ++sample[*current/16];
- current += mAlphaStride ;
- }
- U32 total = 0;
- for (U32 i = 4; i < 11; i++)
- {
- total += sample[i];
- }
- if (total > length/16)
- {
- mIsMask = FALSE;
- }
- 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)
- {
- //cannot generate a pick mask for this texture
- return;
- }
- U32 pick_width = width/2 + 1;
- U32 pick_height = height/2 + 1;
- U32 size = pick_width * pick_height;
- size = (size + 7) / 8; // pixelcount-to-bits
- mPickMask = new U8[size];
- mPickMaskWidth = pick_width;
- mPickMaskHeight = pick_height;
- memset(mPickMask, 0, sizeof(U8) * size);
- U32 pick_bit = 0;
-
- for (S32 y = 0; y < height; y += 2)
- {
- for (S32 x = 0; x < width; x += 2)
- {
- U8 alpha = data_in[(y*width+x)*4+3];
- if (alpha > 32)
- {
- U32 pick_idx = pick_bit/8;
- U32 pick_offset = pick_bit%8;
- llassert(pick_idx < size);
- mPickMask[pick_idx] |= 1 << pick_offset;
- }
-
- ++pick_bit;
- }
- }
- }
- BOOL LLImageGL::getMask(const LLVector2 &tc)
- {
- BOOL res = TRUE;
- if (mPickMask)
- {
- F32 u = tc.mV[0] - floorf(tc.mV[0]);
- F32 v = tc.mV[1] - floorf(tc.mV[1]);
- 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;
- llassert(false);
- }
- llassert(mPickMaskWidth > 0 && mPickMaskHeight > 0);
-
- S32 x = llfloor(u * mPickMaskWidth);
- S32 y = llfloor(v * mPickMaskHeight);
- if (LL_UNLIKELY(x >= mPickMaskWidth))
- {
- LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL;
- x = llmax(0, mPickMaskWidth-1);
- }
- if (LL_UNLIKELY(y >= mPickMaskHeight))
- {
- LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL;
- y = llmax(0, mPickMaskHeight-1);
- }
- S32 idx = y*mPickMaskWidth+x;
- S32 offset = idx%8;
- res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE;
- }
-
- 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 ;
- }
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Manual Mip Generation
- /*
- S32 width = getWidth(discard_level);
- S32 height = getHeight(discard_level);
- S32 w = width, h = height;
- S32 nummips = 1;
- while (w > 4 && h > 4)
- {
- w >>= 1; h >>= 1;
- nummips++;
- }
- stop_glerror();
- w = width, h = height;
- const U8* prev_mip_data = 0;
- const U8* cur_mip_data = 0;
- for (int m=0; m<nummips; m++)
- {
- if (m==0)
- {
- cur_mip_data = rawdata;
- }
- else
- {
- S32 bytes = w * h * mComponents;
- U8* new_data = new U8[bytes];
- LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
- cur_mip_data = new_data;
- }
- llassert(w > 0 && h > 0 && cur_mip_data);
- U8 test = cur_mip_data[w*h*mComponents-1];
- {
- LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data);
- stop_glerror();
- }
- if (prev_mip_data && prev_mip_data != rawdata)
- {
- delete prev_mip_data;
- }
- prev_mip_data = cur_mip_data;
- w >>= 1;
- h >>= 1;
- }
- if (prev_mip_data && prev_mip_data != rawdata)
- {
- delete prev_mip_data;
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips);
- */