diff options
Diffstat (limited to 'indra/llrender/llimagegl.cpp')
-rw-r--r-- | indra/llrender/llimagegl.cpp | 370 |
1 files changed, 256 insertions, 114 deletions
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index d1efb119c6..dd64d753c7 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -44,9 +44,7 @@ #include "llgl.h" #include "llrender.h" - //---------------------------------------------------------------------------- - const F32 MIN_TEXTURE_LIFETIME = 10.f; //statics @@ -58,11 +56,25 @@ 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; - +LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; std::set<LLImageGL*> LLImageGL::sImageList; + +#if !LL_RELEASE_FOR_DOWNLOAD +//----------------------- +//debug use +#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::sDefaultTexturep = NULL; +//------------------------ +#endif //************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. @@ -87,9 +99,18 @@ void LLImageGL::checkTexSize() const { GLint texname; glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); + BOOL error = FALSE; if (texname != mTexName) { - llerrs << "Invalid texture bound!" << llendl; + error = TRUE; + if (gDebugSession) + { + gFailLog << "Invalid texture bound!" << std::endl; + } + else + { + llerrs << "Invalid texture bound!" << llendl; + } } stop_glerror() ; LLGLint x = 0, y = 0 ; @@ -102,7 +123,20 @@ void LLImageGL::checkTexSize() const } if(x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel)) { - llerrs << "wrong texture size and discard level!" << llendl ; + 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."); } } } @@ -176,6 +210,14 @@ void LLImageGL::updateStats(F32 current_time) sLastFrameTime = current_time; sBoundTextureMemoryInBytes = sCurBoundTextureMemory; sCurBoundTextureMemory = 0; + +#if !LL_RELEASE_FOR_DOWNLOAD + for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++) + { + sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ; + sTextureCurBoundCounter[i] = 0 ; + } +#endif } //static @@ -241,6 +283,7 @@ void LLImageGL::restoreGL() //---------------------------------------------------------------------------- +//for server side use only. //static BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps) { @@ -248,12 +291,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); @@ -308,7 +353,6 @@ void LLImageGL::init(BOOL usemipmaps) #endif mPickMask = NULL; - mTextureState = NO_DELETE ; mTextureMemory = 0; mLastBindTime = 0.f; @@ -328,8 +372,7 @@ void LLImageGL::init(BOOL usemipmaps) mComponents = 0; mMaxDiscardLevel = MAX_DISCARD_LEVEL; - mCurrentDiscardLevel = -1; - mDontDiscard = FALSE; + mCurrentDiscardLevel = -1; mFormatInternal = -1; mFormatPrimary = (LLGLenum) 0; @@ -339,6 +382,11 @@ void LLImageGL::init(BOOL usemipmaps) mGLTextureCreated = FALSE ; mIsMask = FALSE; + mNeedsAlphaAndPickMask = TRUE ; + + mDiscardLevelInAtlas = -1 ; + mTexelsInAtlas = 0 ; + mTexelsInGLTexture = 0 ; } void LLImageGL::cleanup() @@ -439,7 +487,7 @@ void LLImageGL::dump() //---------------------------------------------------------------------------- -void LLImageGL::updateBindStats(void) const +BOOL LLImageGL::updateBindStats(S32 tex_mem) const { if (mTexName != 0) { @@ -451,28 +499,18 @@ void LLImageGL::updateBindStats(void) const { // we haven't accounted for this texture yet this frame sUniqueCount++; - updateBoundTexMem(mTextureMemory); + updateBoundTexMem(tex_mem); mLastBindTime = sLastFrameTime; + + return TRUE ; } } + return FALSE ; } -//virtual -bool LLImageGL::bindError(const S32 stage) const +F32 LLImageGL::getTimePassedSinceLastBound() { - return false; -} - -//virtual -bool LLImageGL::bindDefaultImage(const S32 stage) const -{ - return false; -} - -//virtual -void LLImageGL::forceImmediateUpdate() -{ - return ; + return sLastFrameTime - mLastBindTime ; } void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes ) @@ -502,7 +540,6 @@ 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) @@ -510,12 +547,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) 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 @@ -532,14 +567,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) { @@ -572,7 +606,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) { @@ -632,7 +666,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); @@ -680,7 +714,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } else { -// LLFastTimer t2(LLFastTimer::FTM_TEMP5); S32 w = getWidth(); S32 h = getHeight(); if (is_compressed) @@ -719,7 +752,93 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) 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) @@ -737,7 +856,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); } @@ -814,15 +934,15 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 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)) { glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); mGLTextureCreated = true; @@ -844,13 +964,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 @@ -885,12 +1009,12 @@ BOOL LLImageGL::createGLTexture() BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/) { - llpushcallstacks ; if (gGLManager.mIsDisabled) { llwarns << "Trying to create a texture while GL is disabled!" << llendl; return FALSE; } + mGLTextureCreated = false ; llassert(gGLManager.mInited); stop_glerror(); @@ -975,7 +1099,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); @@ -1014,13 +1137,21 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ if (old_name != 0) { sGlobalTextureMemoryInBytes -= mTextureMemory; +#if !LL_RELEASE_FOR_DOWNLOAD + decTextureCounter(mTextureMemory / mComponents) ; +#endif + LLImageGL::deleteTextures(1, &old_name); stop_glerror(); } mTextureMemory = getMipBytes(discard_level); sGlobalTextureMemoryInBytes += mTextureMemory; - setActive() ; + mTexelsInGLTexture = getWidth() * getHeight() ; + +#if !LL_RELEASE_FOR_DOWNLOAD + incTextureCounter(mTextureMemory / mComponents) ; +#endif // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; @@ -1036,12 +1167,7 @@ BOOL LLImageGL::setDiscardLevel(S32 discard_level) discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - if (mDontDiscard) - { - // don't discard! - return FALSE; - } - else if (discard_level == mCurrentDiscardLevel) + if (discard_level == mCurrentDiscardLevel) { // nothing to do return FALSE; @@ -1096,7 +1222,7 @@ BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_h return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ; } -BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) +BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const { llpushcallstacks ; if (discard_level < 0) @@ -1205,33 +1331,48 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre 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; + glDeleteTextures(1, &tex); + stop_glerror(); + } +} - LLImageGL::deleteTextures(1, &mTexName); - mTextureState = DELETED ; +void LLImageGL::destroyGLTexture() +{ + if (mTexName != 0) + { + if(mTextureMemory) + { +#if !LL_RELEASE_FOR_DOWNLOAD + decTextureCounter(mTextureMemory / mComponents) ; +#endif + sGlobalTextureMemoryInBytes -= mTextureMemory; + mTextureMemory = 0; + } + + LLImageGL::deleteTextures(1, &mTexName); mTexName = 0; mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; - stop_glerror(); } } + + //---------------------------------------------------------------------------- void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) @@ -1257,12 +1398,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) @@ -1351,6 +1492,11 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) { + if(!mNeedsAlphaAndPickMask) + { + return ; + } + if (mFormatType != GL_UNSIGNED_BYTE) { llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; @@ -1377,7 +1523,6 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) stride = 4; break; default: - llwarns << "Cannot analyze alpha of image with primary format " << std::hex << mFormatPrimary << std::dec << llendl; return; } @@ -1409,60 +1554,14 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) } } -BOOL LLImageGL::isDeleted() -{ - return mTextureState == DELETED ; -} - -BOOL LLImageGL::isInactive() -{ - return mTextureState == INACTIVE ; -} - -BOOL LLImageGL::isDeletionCandidate() -{ - return mTextureState == DELETION_CANDIDATE ; -} - -void LLImageGL::setDeletionCandidate() -{ - if(mTexName && (mTextureState == INACTIVE)) - { - mTextureState = DELETION_CANDIDATE ; - } -} - -void LLImageGL::forceActive() -{ - mTextureState = ACTIVE ; -} - -void LLImageGL::setActive() -{ - if(mTextureState != NO_DELETE) - { - mTextureState = ACTIVE ; - } -} - -//set the texture inactive -void LLImageGL::setInactive() +//---------------------------------------------------------------------------- +void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { - if(mTexName && (mTextureState == ACTIVE) && !getBoundRecently()) + if(!mNeedsAlphaAndPickMask) { - mTextureState = INACTIVE ; + return ; } -} - -//set the texture to stay in memory -void LLImageGL::setNoDelete() -{ - mTextureState = NO_DELETE ; -} -//---------------------------------------------------------------------------- -void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) -{ if (mFormatType != GL_UNSIGNED_BYTE || mFormatPrimary != GL_RGBA) { @@ -1540,7 +1639,50 @@ BOOL LLImageGL::getMask(const LLVector2 &tc) } //---------------------------------------------------------------------------- - +#if !LL_RELEASE_FOR_DOWNLOAD +//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 ; + } +} +void LLImageGL::incTextureCounter(U32 val) +{ + sTextureLoadedCounter[getTextureCounterIndex(val)]++ ; +} +void LLImageGL::decTextureCounter(U32 val) +{ + sTextureLoadedCounter[getTextureCounterIndex(val)]-- ; +} +void LLImageGL::setCurTexSizebar(S32 index) +{ + sCurTexSizeBar = index ; + sCurTexPickSize = (1 << index) ; +} +void LLImageGL::resetCurTexSizebar() +{ + sCurTexSizeBar = -1 ; + sCurTexPickSize = -1 ; +} +//---------------------------------------------------------------------------- +#endif // Manual Mip Generation /* |