From 74c8b028d42a8c5b080bb861e427f38cedd4ad7c Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 15 Dec 2023 18:26:14 +0100 Subject: SL-20743 Use LLMutex in LLImageBase for internal data thread-safety --- indra/newview/llviewertexture.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ec6f2c848f..820a051782 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -285,6 +285,7 @@ LLPointer LLViewerTextureManager::getLocalTexture(const U32 wid LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps) { + LLImageDataSharedLock lock(raw); LLViewerFetchedTexture* ret = new LLViewerFetchedTexture(raw, type, usemipmaps); gTextureList.addImage(ret, TEX_LIST_STANDARD); return ret; @@ -2905,6 +2906,8 @@ void LLViewerFetchedTexture::saveRawImage() return; } + LLImageDataSharedLock lock(mRawImage); + mSavedRawDiscardLevel = mRawDiscardLevel; if (mBoostLevel == LLGLTexture::BOOST_ICON) { -- cgit v1.2.3 From a02459dea6c24d851ab5e76f63f31376d9d4791c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 14 Feb 2024 21:39:13 +0200 Subject: Viewer#779 Show bias memory estimate in texture console --- indra/newview/llviewertexture.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c4a681f2b7..89b7b3ba0d 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -100,6 +100,9 @@ U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; bool LLViewerTexture::sFreezeImageUpdates = false; F32 LLViewerTexture::sCurrentTime = 0.0f; +constexpr F32 MIN_VRAM_BUDGET = 768.f; +F32 LLViewerTexture::sFreeVRAMMegabytes = MIN_VRAM_BUDGET; + LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; const F64 log_2 = log(2.0); @@ -509,7 +512,10 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p timer.reset(); { - gpu_res = (S32Megabytes)gViewerWindow->getWindow()->getAvailableVRAMMegabytes(); + // For purposes of texture memory need to check both, actual free + // memory and estimated free texture memory from bias calculations + U32 free_memory = llmin(gViewerWindow->getWindow()->getAvailableVRAMMegabytes(), (U32)sFreeVRAMMegabytes); + gpu_res = (S32Megabytes)free_memory; //check main memory, only works for windows and macos. LLMemory::updateMemoryInfo(); @@ -546,7 +552,8 @@ void LLViewerTexture::updateClass() F32 budget = max_vram_budget == 0 ? gGLManager.mVRAM : max_vram_budget; // try to leave half a GB for everyone else, but keep at least 768MB for ourselves - F32 target = llmax(budget - 512.f, 768.f); + F32 target = llmax(budget - 512.f, MIN_VRAM_BUDGET); + sFreeVRAMMegabytes = target - used; F32 over_pct = llmax((used-target) / target, 0.f); sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct); -- cgit v1.2.3 From b2c271367296744fbbe2262e55d0ea4f8f5ccdc9 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 20 Feb 2024 00:50:39 +0100 Subject: Convert BOOL to bool in llrender --- indra/newview/llviewertexture.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 89b7b3ba0d..fab125982c 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -342,12 +342,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const // Create a bridge to the viewer texture manager. class LLViewerTextureManagerBridge : public LLTextureManagerBridge { - /*virtual*/ LLPointer getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) + /*virtual*/ LLPointer getLocalTexture(bool usemipmaps = true, bool generate_gl_tex = true) { return LLViewerTextureManager::getLocalTexture(usemipmaps, generate_gl_tex); } - /*virtual*/ LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) + /*virtual*/ LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex = true) { return LLViewerTextureManager::getLocalTexture(width, height, components, usemipmaps, generate_gl_tex); } @@ -1355,7 +1355,7 @@ void LLViewerFetchedTexture::addToCreateTexture() if(isForSculptOnly()) { //just update some variables, not to create a real GL texture. - createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE); + createGLTexture(mRawDiscardLevel, mRawImage, 0, false); mNeedsCreateTexture = false; destroyRawImage(); } @@ -1540,7 +1540,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) return FALSE; } - BOOL res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); + BOOL res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, true, mBoostLevel); return res; } -- cgit v1.2.3 From 60d3dd98a44230c21803c1606552ee098ed9fa7c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 21 Feb 2024 21:05:14 +0100 Subject: Convert remaining BOOL to bool --- indra/newview/llviewertexture.cpp | 320 +++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 160 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index fab125982c..c70d2423e0 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -119,11 +119,11 @@ const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_S LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb, S32 discard_level, - BOOL need_imageraw, // Needs image raw for the callback + bool need_imageraw, // Needs image raw for the callback void* userdata, LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, LLViewerFetchedTexture* target, - BOOL pause) + bool pause) : mCallback(cb), mLastUsedDiscard(MAX_DISCARD_LEVEL+1), mDesiredDiscard(discard_level), @@ -169,7 +169,7 @@ void LLLoadedCallbackEntry::cleanUpCallbackList(LLLoadedCallbackEntry::source_ca } } -LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, BOOL usemipmaps, LLImageGL* gl_image) +LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, bool usemipmaps, LLImageGL* gl_image) { return new LLViewerMediaTexture(media_id, usemipmaps, gl_image); } @@ -215,7 +215,7 @@ LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &med return LLViewerMediaTexture::findMediaTexture(media_id); } -LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) +LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, bool usemipmaps, LLImageGL* gl_image) { LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id); if(!tex) @@ -228,7 +228,7 @@ LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, return tex; } -LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLTexture* tex, BOOL report_error) +LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLTexture* tex, bool report_error) { if(!tex) { @@ -249,7 +249,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLTex return NULL; } -LLPointer LLViewerTextureManager::getLocalTexture(BOOL usemipmaps, BOOL generate_gl_tex) +LLPointer LLViewerTextureManager::getLocalTexture(bool usemipmaps, bool generate_gl_tex) { LLPointer tex = new LLViewerTexture(usemipmaps); if(generate_gl_tex) @@ -259,7 +259,7 @@ LLPointer LLViewerTextureManager::getLocalTexture(BOOL usemipma } return tex; } -LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex) +LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& id, bool usemipmaps, bool generate_gl_tex) { LLPointer tex = new LLViewerTexture(id, usemipmaps); if(generate_gl_tex) @@ -269,13 +269,13 @@ LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& } return tex; } -LLPointer LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) +LLPointer LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, bool usemipmaps) { LLPointer tex = new LLViewerTexture(raw, usemipmaps); tex->setCategory(LLGLTexture::LOCAL); return tex; } -LLPointer LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex) +LLPointer LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex) { LLPointer tex = new LLViewerTexture(width, height, components, usemipmaps); if(generate_gl_tex) @@ -297,7 +297,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageR LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( const LLUUID &image_id, FTType f_type, - BOOL usemipmaps, + bool usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, @@ -310,7 +310,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( const std::string& filename, FTType f_type, - BOOL usemipmaps, + bool usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, @@ -323,7 +323,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( //static LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url, FTType f_type, - BOOL usemipmaps, + bool usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, LLGLint internal_format, @@ -364,7 +364,7 @@ void LLViewerTextureManager::init() { LLPointer raw = new LLImageRaw(1,1,3); raw->clear(0x77, 0x77, 0x77, 0xFF); - LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), TRUE); + LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), true); } const S32 dim = 128; @@ -372,7 +372,7 @@ void LLViewerTextureManager::init() U8* data = image_raw->getData(); memset(data, 0, dim * dim * 3); - LLViewerTexture::sBlackImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), TRUE); + LLViewerTexture::sBlackImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); #if 1 LLPointer imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT); @@ -404,7 +404,7 @@ void LLViewerTextureManager::init() imagep->setCachedRawImage(0, image_raw); image_raw = NULL; #else - LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, true, LLGLTexture::BOOST_UI); #endif LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER); @@ -422,7 +422,7 @@ void LLViewerTextureManager::init() data[i+2] = color; } - LLViewerTexture::sCheckerBoardImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), TRUE); + LLViewerTexture::sCheckerBoardImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); LLViewerTexture::initClass(); @@ -570,7 +570,7 @@ void LLViewerTexture::updateClass() //------------------------------------------------------------------------------------------- const U32 LLViewerTexture::sCurrentFileVersion = 1; -LLViewerTexture::LLViewerTexture(BOOL usemipmaps) : +LLViewerTexture::LLViewerTexture(bool usemipmaps) : LLGLTexture(usemipmaps) { init(true); @@ -579,7 +579,7 @@ LLViewerTexture::LLViewerTexture(BOOL usemipmaps) : sImageCount++; } -LLViewerTexture::LLViewerTexture(const LLUUID& id, BOOL usemipmaps) : +LLViewerTexture::LLViewerTexture(const LLUUID& id, bool usemipmaps) : LLGLTexture(usemipmaps), mID(id) { @@ -588,7 +588,7 @@ LLViewerTexture::LLViewerTexture(const LLUUID& id, BOOL usemipmaps) : sImageCount++; } -LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) : +LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps) : LLGLTexture(width, height, components, usemipmaps) { init(true); @@ -597,7 +597,7 @@ LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 com sImageCount++; } -LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) : +LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, bool usemipmaps) : LLGLTexture(raw, usemipmaps) { init(true); @@ -745,9 +745,9 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) } //virtual -BOOL LLViewerTexture::isMissingAsset()const +bool LLViewerTexture::isMissingAsset()const { - return FALSE; + return false; } //virtual @@ -755,12 +755,12 @@ void LLViewerTexture::forceImmediateUpdate() { } -void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const +void LLViewerTexture::addTextureStats(F32 virtual_size, bool needs_gltexture) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(needs_gltexture) { - mNeedsGLTexture = TRUE; + mNeedsGLTexture = true; } virtual_size = llmin(virtual_size, LLViewerFetchedTexture::sMaxVirtualSize); @@ -948,7 +948,7 @@ void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) //nothing here. } -BOOL LLViewerTexture::isLargeImage() +bool LLViewerTexture::isLargeImage() { return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize; } @@ -1005,11 +1005,11 @@ LLViewerFetchedTexture* LLViewerFetchedTexture::getSmokeImage() return sSmokeImagep; } -LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host, BOOL usemipmaps) +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host, bool usemipmaps) : LLViewerTexture(id, usemipmaps), mTargetHost(host) { - init(TRUE); + init(true); mFTType = f_type; if (mFTType == FTT_HOST_BAKE) { @@ -1018,18 +1018,18 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, generateGLTexture(); } -LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps) +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, bool usemipmaps) : LLViewerTexture(raw, usemipmaps) { - init(TRUE); + init(true); mFTType = f_type; } -LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps) +LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps) : LLViewerTexture(id, usemipmaps), mUrl(url) { - init(TRUE); + init(true); mFTType = f_type; generateGLTexture(); } @@ -1038,20 +1038,20 @@ void LLViewerFetchedTexture::init(bool firstinit) { mOrigWidth = 0; mOrigHeight = 0; - mHasAux = FALSE; - mNeedsAux = FALSE; + mHasAux = false; + mNeedsAux = false; mRequestedDiscardLevel = -1; mRequestedDownloadPriority = 0.f; - mFullyLoaded = FALSE; + mFullyLoaded = false; mCanUseHTTP = true; mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; - mDecodingAux = FALSE; + mDecodingAux = false; mKnownDrawWidth = 0; mKnownDrawHeight = 0; - mKnownDrawSizeChanged = FALSE; + mKnownDrawSizeChanged = false; if (firstinit) { @@ -1060,43 +1060,43 @@ void LLViewerFetchedTexture::init(bool firstinit) // Only set mIsMissingAsset true when we know for certain that the database // does not contain this image. - mIsMissingAsset = FALSE; + mIsMissingAsset = false; mLoadedCallbackDesiredDiscardLevel = S8_MAX; - mPauseLoadedCallBacks = FALSE; + mPauseLoadedCallBacks = false; mNeedsCreateTexture = false; - mIsRawImageValid = FALSE; + mIsRawImageValid = false; mRawDiscardLevel = INVALID_DISCARD_LEVEL; mMinDiscardLevel = 0; - mHasFetcher = FALSE; - mIsFetching = FALSE; + mHasFetcher = false; + mIsFetching = false; mFetchState = 0; mFetchPriority = 0; mDownloadProgress = 0.f; mFetchDeltaTime = 999999.f; mRequestDeltaTime = 0.f; - mForSculpt = FALSE; - mIsFetched = FALSE; - mInFastCacheList = FALSE; + mForSculpt = false; + mIsFetched = false; + mInFastCacheList = false; mCachedRawImage = NULL; mCachedRawDiscardLevel = -1; - mCachedRawImageReady = FALSE; + mCachedRawImageReady = false; mSavedRawImage = NULL; - mForceToSaveRawImage = FALSE; - mSaveRawImage = FALSE; + mForceToSaveRawImage = false; + mSaveRawImage = false; mSavedRawDiscardLevel = -1; mDesiredSavedRawDiscardLevel = -1; mLastReferencedSavedRawImageTime = 0.0f; mKeptSavedRawImageTime = 0.f; mLastCallBackActiveTime = 0.f; - mForceCallbackFetch = FALSE; - mInDebug = FALSE; - mUnremovable = FALSE; + mForceCallbackFetch = false; + mInDebug = false; + mUnremovable = false; mFTType = FTT_UNKNOWN; } @@ -1134,18 +1134,18 @@ void LLViewerFetchedTexture::cleanup() LLLoadedCallbackEntry *entryp = *iter++; // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData ); + entryp->mCallback( false, this, NULL, NULL, 0, true, entryp->mUserData ); entryp->removeTexture(this); delete entryp; } mLoadedCallbackList.clear(); - mNeedsAux = FALSE; + mNeedsAux = false; // Clean up image data destroyRawImage(); mCachedRawImage = NULL; mCachedRawDiscardLevel = -1; - mCachedRawImageReady = FALSE; + mCachedRawImageReady = false; mSavedRawImage = NULL; mSavedRawDiscardLevel = -1; } @@ -1158,7 +1158,7 @@ void LLViewerFetchedTexture::loadFromFastCache() { return; //no need to access the fast cache. } - mInFastCacheList = FALSE; + mInFastCacheList = false; add(LLTextureFetch::sCacheAttempt, 1.0); @@ -1211,7 +1211,7 @@ void LLViewerFetchedTexture::loadFromFastCache() } mRequestedDiscardLevel = mDesiredDiscardLevel + 1; - mIsRawImageValid = TRUE; + mIsRawImageValid = true; addToCreateTexture(); } } @@ -1225,7 +1225,7 @@ void LLViewerFetchedTexture::setForSculpt() { static const S32 MAX_INTERVAL = 8; //frames - mForSculpt = TRUE; + mForSculpt = true; if(isForSculptOnly() && hasGLTexture() && !getBoundRecently()) { destroyGLTexture(); //sculpt image does not need gl texture. @@ -1235,22 +1235,22 @@ void LLViewerFetchedTexture::setForSculpt() setMaxVirtualSizeResetInterval(MAX_INTERVAL); } -BOOL LLViewerFetchedTexture::isForSculptOnly() const +bool LLViewerFetchedTexture::isForSculptOnly() const { return mForSculpt && !mNeedsGLTexture; } -BOOL LLViewerFetchedTexture::isDeleted() +bool LLViewerFetchedTexture::isDeleted() { return mTextureState == DELETED; } -BOOL LLViewerFetchedTexture::isInactive() +bool LLViewerFetchedTexture::isInactive() { return mTextureState == INACTIVE; } -BOOL LLViewerFetchedTexture::isDeletionCandidate() +bool LLViewerFetchedTexture::isDeletionCandidate() { return mTextureState == DELETION_CANDIDATE; } @@ -1272,7 +1272,7 @@ void LLViewerFetchedTexture::setInactive() } } -BOOL LLViewerFetchedTexture::isFullyLoaded() const +bool LLViewerFetchedTexture::isFullyLoaded() const { // Unfortunately, the boolean "mFullyLoaded" is never updated correctly so we use that logic // to check if the texture is there and completely downloaded @@ -1319,7 +1319,7 @@ void LLViewerFetchedTexture::destroyTexture() //LL_DEBUGS("Avatar") << mID << LL_ENDL; destroyGLTexture(); - mFullyLoaded = FALSE; + mFullyLoaded = false; } void LLViewerFetchedTexture::addToCreateTexture() @@ -1345,7 +1345,7 @@ void LLViewerFetchedTexture::addToCreateTexture() } //discard the cached raw image and the saved raw image - mCachedRawImageReady = FALSE; + mCachedRawImageReady = false; mCachedRawDiscardLevel = -1; mCachedRawImage = NULL; mSavedRawDiscardLevel = -1; @@ -1417,7 +1417,7 @@ void LLViewerFetchedTexture::addToCreateTexture() } // ONLY called from LLViewerTextureList -BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) +bool LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; #if LL_IMAGEGL_THREAD_CHECK @@ -1427,7 +1427,7 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) if (!mNeedsCreateTexture) { destroyRawImage(); - return FALSE; + return false; } mNeedsCreateTexture = false; @@ -1439,13 +1439,13 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) { LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL; destroyRawImage(); - return FALSE; + return false; } // LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", // mRawDiscardLevel, // mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) // << mID.getString() << LL_ENDL; - BOOL res = TRUE; + bool res = true; // store original size only for locally-sourced images if (mUrl.compare(0, 7, "file://") == 0) @@ -1461,7 +1461,7 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) } else { // leave black border, do not scale image content - mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, false); } mFullWidth = mRawImage->getWidth(); @@ -1507,7 +1507,7 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL; setIsMissingAsset(); destroyRawImage(); - return FALSE; + return false; } if (mGLTexturep->getHasExplicitFormat()) @@ -1526,21 +1526,21 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) setIsMissingAsset(); destroyRawImage(); LLAppViewer::getTextureCache()->removeFromCache(mID); - return FALSE; + return false; } } return res; } -BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) +bool LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) { if (!mNeedsCreateTexture) { - return FALSE; + return false; } - BOOL res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, true, mBoostLevel); + bool res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, true, mBoostLevel); return res; } @@ -1560,7 +1560,7 @@ void LLViewerFetchedTexture::postCreateTexture() if (!needsToSaveRawImage()) { - mNeedsAux = FALSE; + mNeedsAux = false; destroyRawImage(); } @@ -1653,8 +1653,8 @@ void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height) mKnownDrawWidth = llmax(mKnownDrawWidth, width); mKnownDrawHeight = llmax(mKnownDrawHeight, height); - mKnownDrawSizeChanged = TRUE; - mFullyLoaded = FALSE; + mKnownDrawSizeChanged = true; + mFullyLoaded = false; } addTextureStats((F32)(mKnownDrawWidth * mKnownDrawHeight)); } @@ -1689,7 +1689,7 @@ void LLViewerFetchedTexture::processTextureStats() if(mDesiredDiscardLevel > mMinDesiredDiscardLevel)//need to load more { mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); - mFullyLoaded = FALSE; + mFullyLoaded = false; } //setDebugText("fully loaded"); } @@ -1739,11 +1739,11 @@ void LLViewerFetchedTexture::processTextureStats() mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()); mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); } - mKnownDrawSizeChanged = FALSE; + mKnownDrawSizeChanged = false; if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel)) { - mFullyLoaded = TRUE; + mFullyLoaded = true; } } } @@ -1753,7 +1753,7 @@ void LLViewerFetchedTexture::processTextureStats() mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); if(getDiscardLevel() < 0 || getDiscardLevel() > mDesiredDiscardLevel) { - mFullyLoaded = FALSE; + mFullyLoaded = false; } } } @@ -1789,10 +1789,10 @@ bool LLViewerFetchedTexture::setDebugFetching(S32 debug_level) { if(debug_level < 0) { - mInDebug = FALSE; + mInDebug = false; return false; } - mInDebug = TRUE; + mInDebug = true; mDesiredDiscardLevel = debug_level; @@ -1885,12 +1885,12 @@ bool LLViewerFetchedTexture::updateFetch() if (mRawImage.notNull()) sRawCount++; if (mAuxRawImage.notNull()) { - mHasAux = TRUE; + mHasAux = true; sAuxCount++; } if (finished) { - mIsFetching = FALSE; + mIsFetching = false; mLastFetchState = -1; mLastPacketTimer.reset(); } @@ -1907,7 +1907,7 @@ bool LLViewerFetchedTexture::updateFetch() LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - mIsFetched = TRUE; + mIsFetched = true; tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)); } mRawDiscardLevel = fetch_discard; @@ -1926,12 +1926,12 @@ bool LLViewerFetchedTexture::updateFetch() LL_WARNS() << "oversize, setting as missing" << LL_ENDL; setIsMissingAsset(); mRawDiscardLevel = INVALID_DISCARD_LEVEL; - mIsFetching = FALSE; + mIsFetching = false; mLastPacketTimer.reset(); } else { - mIsRawImageValid = TRUE; + mIsRawImageValid = true; addToCreateTexture(); } @@ -1959,7 +1959,7 @@ bool LLViewerFetchedTexture::updateFetch() } } - return TRUE; + return true; } else { @@ -2103,8 +2103,8 @@ bool LLViewerFetchedTexture::updateFetch() if (fetch_request_discard >= 0) { LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - request created"); - mHasFetcher = TRUE; - mIsFetching = TRUE; + mHasFetcher = true; + mIsFetching = true; // in some cases createRequest can modify discard, as an example // bake textures are always at discard 0 mRequestedDiscardLevel = llmin(desired_discard, fetch_request_discard); @@ -2128,7 +2128,7 @@ bool LLViewerFetchedTexture::updateFetch() { LL_DEBUGS("Texture") << "exceeded idle time " << FETCH_IDLE_TIME << ", deleting request: " << getID() << LL_ENDL; LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = FALSE; + mHasFetcher = false; } } @@ -2155,8 +2155,8 @@ void LLViewerFetchedTexture::forceToDeleteRequest() { if (mHasFetcher) { - mHasFetcher = FALSE; - mIsFetching = FALSE; + mHasFetcher = false; + mIsFetching = false; } resetTextureStats(); @@ -2164,7 +2164,7 @@ void LLViewerFetchedTexture::forceToDeleteRequest() mDesiredDiscardLevel = getMaxDiscardLevel() + 1; } -void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing) +void LLViewerFetchedTexture::setIsMissingAsset(bool is_missing) { if (is_missing == mIsMissingAsset) { @@ -2189,8 +2189,8 @@ void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing) if (mHasFetcher) { LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = FALSE; - mIsFetching = FALSE; + mHasFetcher = false; + mIsFetching = false; mLastPacketTimer.reset(); mFetchState = 0; mFetchPriority = 0; @@ -2204,8 +2204,8 @@ void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing) } void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, - S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* userdata, - LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause) + S32 discard_level, bool keep_imageraw, bool needs_aux, void* userdata, + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, bool pause) { // // Don't do ANYTHING here, just add it to the global callback list @@ -2239,7 +2239,7 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call mNeedsAux |= needs_aux; if(keep_imageraw) { - mSaveRawImage = TRUE; + mSaveRawImage = true; } if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) { @@ -2272,7 +2272,7 @@ void LLViewerFetchedTexture::clearCallbackEntryList() // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData); + entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); iter = mLoadedCallbackList.erase(iter); delete entryp; } @@ -2304,7 +2304,7 @@ void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::so { // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData); + entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); iter = mLoadedCallbackList.erase(iter); delete entryp; } @@ -2348,30 +2348,30 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry: { if(!callback_list) { - mPauseLoadedCallBacks = FALSE; + mPauseLoadedCallBacks = false; return; } - BOOL need_raw = FALSE; + bool need_raw = false; for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { LLLoadedCallbackEntry *entryp = *iter++; if(entryp->mSourceCallbackList == callback_list) { - entryp->mPaused = FALSE; + entryp->mPaused = false; if(entryp->mNeedsImageRaw) { - need_raw = TRUE; + need_raw = true; } } } - mPauseLoadedCallBacks = FALSE ; + mPauseLoadedCallBacks = false ; mLastCallBackActiveTime = sCurrentTime ; - mForceCallbackFetch = TRUE; + mForceCallbackFetch = true; if(need_raw) { - mSaveRawImage = TRUE; + mSaveRawImage = true; } } @@ -2390,7 +2390,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s LLLoadedCallbackEntry *entryp = *iter++; if(entryp->mSourceCallbackList == callback_list) { - entryp->mPaused = TRUE; + entryp->mPaused = true; } else if(!entryp->mPaused) { @@ -2400,9 +2400,9 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s if(paused) { - mPauseLoadedCallBacks = TRUE;//when set, loaded callback is paused. + mPauseLoadedCallBacks = true;//when set, loaded callback is paused. resetTextureStats(); - mSaveRawImage = FALSE; + mSaveRawImage = false; } } @@ -2453,7 +2453,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() LLLoadedCallbackEntry *entryp = *iter++; // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData); + entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); delete entryp; } mLoadedCallbackList.clear(); @@ -2586,11 +2586,11 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL; } - BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE; + bool final = mRawDiscardLevel <= entryp->mDesiredDiscard ? true : false; //LL_INFOS() << "Running callback for " << getID() << LL_ENDL; //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL; entryp->mLastUsedDiscard = mRawDiscardLevel; - entryp->mCallback(TRUE, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); + entryp->mCallback(true, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); if (final) { iter = mLoadedCallbackList.erase(curiter); @@ -2617,9 +2617,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard)) { mLastCallBackActiveTime = sCurrentTime; - BOOL final = gl_discard <= entryp->mDesiredDiscard ? TRUE : FALSE; + bool final = gl_discard <= entryp->mDesiredDiscard ? true : false; entryp->mLastUsedDiscard = gl_discard; - entryp->mCallback(TRUE, this, NULL, NULL, gl_discard, final, entryp->mUserData); + entryp->mCallback(true, this, NULL, NULL, gl_discard, final, entryp->mUserData); if (final) { iter = mLoadedCallbackList.erase(curiter); @@ -2644,7 +2644,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { //wait for long enough but no fetching request issued, force one. forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); - mForceCallbackFetch = FALSE; //fire once. + mForceCallbackFetch = false; //fire once. } return res; @@ -2717,7 +2717,7 @@ LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) mRawDiscardLevel = discard_level; } } - mIsRawImageValid = TRUE; + mIsRawImageValid = true; sRawCount++; return mRawImage; @@ -2752,7 +2752,7 @@ void LLViewerFetchedTexture::destroyRawImage() mRawImage = NULL; - mIsRawImageValid = FALSE; + mIsRawImageValid = false; mRawDiscardLevel = INVALID_DISCARD_LEVEL; } } @@ -2776,7 +2776,7 @@ void LLViewerFetchedTexture::switchToCachedImage() gTextureList.dirtyImage(this); } - mIsRawImageValid = TRUE; + mIsRawImageValid = true; mRawDiscardLevel = mCachedRawDiscardLevel; scheduleCreateTexture(); @@ -2822,7 +2822,7 @@ void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* im mCachedRawImage = imageraw; } mCachedRawDiscardLevel = discard_level; - mCachedRawImageReady = TRUE; + mCachedRawImageReady = true; } } @@ -2893,7 +2893,7 @@ void LLViewerFetchedTexture::checkCachedRawSculptImage() { if(getDiscardLevel() != 0) { - mCachedRawImageReady = FALSE; + mCachedRawImageReady = false; } else if(isForSculptOnly()) { @@ -2948,7 +2948,7 @@ void LLViewerFetchedTexture::saveRawImage() if(mForceToSaveRawImage && mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel) { - mForceToSaveRawImage = FALSE; + mForceToSaveRawImage = false; } mLastReferencedSavedRawImageTime = sCurrentTime; @@ -2964,7 +2964,7 @@ void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept } //trigger a new fetch. - mForceToSaveRawImage = TRUE ; + mForceToSaveRawImage = true ; mDesiredSavedRawDiscardLevel = desired_discard ; mKeptSavedRawImageTime = kept_time ; mLastReferencedSavedRawImageTime = sCurrentTime ; @@ -2984,7 +2984,7 @@ void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_t if(!mForceToSaveRawImage || mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard) { - mForceToSaveRawImage = TRUE; + mForceToSaveRawImage = true; mDesiredSavedRawDiscardLevel = desired_discard; //copy from the cached raw image if exists. @@ -3007,14 +3007,14 @@ void LLViewerFetchedTexture::destroySavedRawImage() return; //keep the saved raw image. } - mForceToSaveRawImage = FALSE; - mSaveRawImage = FALSE; + mForceToSaveRawImage = false; + mSaveRawImage = false; clearCallbackEntryList(); mSavedRawImage = NULL ; - mForceToSaveRawImage = FALSE ; - mSaveRawImage = FALSE ; + mForceToSaveRawImage = false ; + mSaveRawImage = false ; mSavedRawDiscardLevel = -1 ; mDesiredSavedRawDiscardLevel = -1 ; mLastReferencedSavedRawImageTime = 0.0f ; @@ -3034,7 +3034,7 @@ LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() return mSavedRawImage; } -BOOL LLViewerFetchedTexture::hasSavedRawImage() const +bool LLViewerFetchedTexture::hasSavedRawImage() const { return mSavedRawImage.notNull(); } @@ -3051,16 +3051,16 @@ F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const //---------------------------------------------------------------------------------------------- //start of LLViewerLODTexture //---------------------------------------------------------------------------------------------- -LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host, BOOL usemipmaps) +LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host, bool usemipmaps) : LLViewerFetchedTexture(id, f_type, host, usemipmaps) { - init(TRUE); + init(true); } -LLViewerLODTexture::LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps) +LLViewerLODTexture::LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps) : LLViewerFetchedTexture(url, f_type, id, usemipmaps) { - init(TRUE); + init(true); } void LLViewerLODTexture::init(bool firstinit) @@ -3286,7 +3286,7 @@ LLViewerMediaTexture* LLViewerMediaTexture::findMediaTexture(const LLUUID& media return media_tex; } -LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) +LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, bool usemipmaps, LLImageGL* gl_image) : LLViewerTexture(id, usemipmaps), mMediaImplp(NULL), mUpdateVirtualSizeTime(0) @@ -3302,9 +3302,9 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL mGLTexturep->setAllowCompression(false); - mGLTexturep->setNeedsAlphaAndPickMask(FALSE); + mGLTexturep->setNeedsAlphaAndPickMask(false); - mIsPlaying = FALSE; + mIsPlaying = false; setMediaImpl(); @@ -3327,17 +3327,17 @@ LLViewerMediaTexture::~LLViewerMediaTexture() } } -void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) +void LLViewerMediaTexture::reinit(bool usemipmaps /* = true */) { llassert(mGLTexturep.notNull()); mUseMipMaps = usemipmaps; getLastReferencedTimer()->reset(); mGLTexturep->setUseMipMaps(mUseMipMaps); - mGLTexturep->setNeedsAlphaAndPickMask(FALSE); + mGLTexturep->setNeedsAlphaAndPickMask(false); } -void LLViewerMediaTexture::setUseMipMaps(BOOL mipmap) +void LLViewerMediaTexture::setUseMipMaps(bool mipmap) { mUseMipMaps = mipmap; @@ -3369,11 +3369,11 @@ void LLViewerMediaTexture::setMediaImpl() //return true if all faces to reference to this media texture are found //Note: mMediaFaceList is valid only for the current instant // because it does not check the face validity after the current frame. -BOOL LLViewerMediaTexture::findFaces() +bool LLViewerMediaTexture::findFaces() { mMediaFaceList.clear(); - BOOL ret = TRUE; + bool ret = true; LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. @@ -3394,7 +3394,7 @@ BOOL LLViewerMediaTexture::findFaces() if(!mMediaImplp) { - return TRUE; + return true; } //for media on a face. @@ -3410,13 +3410,13 @@ BOOL LLViewerMediaTexture::findFaces() // If this happens, viewer is likely to crash llassert(0); LL_WARNS() << "Dead object in mMediaImplp's object list" << LL_ENDL; - ret = FALSE; + ret = false; continue; } if (obj->mDrawable.isNull() || obj->mDrawable->isDead()) { - ret = FALSE; + ret = false; continue; } @@ -3431,7 +3431,7 @@ BOOL LLViewerMediaTexture::findFaces() } else { - ret = FALSE; + ret = false; } } } @@ -3480,9 +3480,9 @@ void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) return; //no need to remove the face because the media is not in playing. } - mIsPlaying = FALSE; //set to remove the media from the face. + mIsPlaying = false; //set to remove the media from the face. switchTexture(LLRender::DIFFUSE_MAP, facep); - mIsPlaying = TRUE; //set the flag back. + mIsPlaying = true; //set the flag back. if(getTotalNumFaces() < 1) //no face referencing to this media { @@ -3610,7 +3610,7 @@ void LLViewerMediaTexture::stopPlaying() // { // mMediaImplp->stop(); // } - mIsPlaying = FALSE; + mIsPlaying = false; } void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep) @@ -3651,7 +3651,7 @@ void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep) } } -void LLViewerMediaTexture::setPlaying(BOOL playing) +void LLViewerMediaTexture::setPlaying(bool playing) { if(!mMediaImplp) { @@ -3673,7 +3673,7 @@ void LLViewerMediaTexture::setPlaying(BOOL playing) if(findFaces()) { //about to update all faces. - mMediaImplp->setUpdated(FALSE); + mMediaImplp->setUpdated(false); } if(mMediaFaceList.empty())//no face pointing to this media @@ -3711,7 +3711,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() if(!mMaxVirtualSizeResetCounter) { - addTextureStats(0.f, FALSE);//reset + addTextureStats(0.f, false);//reset } if(mIsPlaying) //media is playing @@ -3806,13 +3806,13 @@ void LLTexturePipelineTester::update() //start a new fetching session reset(); mStartFetchingTime = LLImageGL::sLastFrameTime; - mPause = FALSE; + mPause = false; } //update total gray time if(mUsingDefaultTexture) { - mUsingDefaultTexture = FALSE; + mUsingDefaultTexture = false; mTotalGrayTime = LLImageGL::sLastFrameTime - mStartFetchingTime; } @@ -3824,7 +3824,7 @@ void LLTexturePipelineTester::update() else if(!mPause) { //stop the current fetching session - mPause = TRUE; + mPause = true; outputTestResults(); reset(); } @@ -3832,9 +3832,9 @@ void LLTexturePipelineTester::update() void LLTexturePipelineTester::reset() { - mPause = TRUE; + mPause = true; - mUsingDefaultTexture = FALSE; + mUsingDefaultTexture = false; mStartStablizingTime = 0.0f; mEndStablizingTime = 0.0f; @@ -3885,7 +3885,7 @@ void LLTexturePipelineTester::updateTextureBindingStats(const LLViewerTexture* i } } -void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) +void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, bool from_cache) { U32Bytes data_size = (U32Bytes)raw_imagep->getDataSize(); mTotalBytesLoaded += data_size; @@ -3914,7 +3914,7 @@ void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTex void LLTexturePipelineTester::updateGrayTextureBinding() { - mUsingDefaultTexture = TRUE; + mUsingDefaultTexture = true; } void LLTexturePipelineTester::setStablizingTime() @@ -4041,7 +4041,7 @@ LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::lo //load a session std::string currentLabel = getCurrentLabelName(); - BOOL in_log = (*log).has(currentLabel); + bool in_log = (*log).has(currentLabel); while (in_log) { LLSD::String label = currentLabel; -- cgit v1.2.3 From f17d86889f8147095bfe2b966df2da834b1c00c6 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 4 Apr 2024 12:34:31 +0200 Subject: secondlife/viewer#984 BugSplat Crash: LLLoadedCallbackEntry::removeTexture(146) --- indra/newview/llviewertexture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c70d2423e0..ea7a8dbf13 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -144,7 +144,7 @@ LLLoadedCallbackEntry::~LLLoadedCallbackEntry() void LLLoadedCallbackEntry::removeTexture(LLViewerFetchedTexture* tex) { - if(mSourceCallbackList) + if (mSourceCallbackList && tex) { mSourceCallbackList->erase(LLTextureKey(tex->getID(), (ETexListType)tex->getTextureListType())); } -- cgit v1.2.3 From ea268fcd48550f98baceef0294fd977ff12d2b35 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 6 May 2024 22:48:24 +0300 Subject: viewer#799 getAvailableVRAMMegabytes cleanup --- indra/newview/llviewertexture.cpp | 52 +-------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 4b94fe141c..dee68b2068 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1,3 +1,4 @@ + /** * @file llviewertexture.cpp * @brief Object which handles a received image (and associated texture(s)) @@ -471,61 +472,10 @@ void LLViewerTexture::initClass() LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture(); } -// tuning params -const F32 GPU_MEMORY_CHECK_WAIT_TIME = 1.0f; // non-const (used externally F32 texmem_lower_bound_scale = 0.85f; F32 texmem_middle_bound_scale = 0.925f; -//static -bool LLViewerTexture::isMemoryForTextureLow() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - // Note: we need to figure out a better source for 'min' values, - // what is free for low end at minimal settings is 'nothing left' - // for higher end gpus at high settings. - const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); - const S32Megabytes MIN_FREE_MAIN_MEMORY(100); - - S32Megabytes gpu; - S32Megabytes physical; - getGPUMemoryForTextures(gpu, physical); - - return (gpu < MIN_FREE_TEXTURE_MEMORY); // || (physical < MIN_FREE_MAIN_MEMORY); -} - -//static -void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static LLFrameTimer timer; - - static S32Megabytes gpu_res = S32Megabytes(S32_MAX); - static S32Megabytes physical_res = S32Megabytes(S32_MAX); - - if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second. - { - gpu = gpu_res; - physical = physical_res; - return; - } - timer.reset(); - - { - // For purposes of texture memory need to check both, actual free - // memory and estimated free texture memory from bias calculations - U32 free_memory = llmin(gViewerWindow->getWindow()->getAvailableVRAMMegabytes(), (U32)sFreeVRAMMegabytes); - gpu_res = (S32Megabytes)free_memory; - - //check main memory, only works for windows and macos. - LLMemory::updateMemoryInfo(); - physical_res = LLMemory::getAvailableMemKB(); - - gpu = gpu_res; - physical = physical_res; - } -} - //static void LLViewerTexture::updateClass() { -- cgit v1.2.3 From b31dad179a87c11d1806bb7dece5dae76ac76c62 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 6 May 2024 23:26:22 +0300 Subject: viewer#799 Account for renderTarget --- indra/newview/llviewertexture.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index dee68b2068..389da801df 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -494,10 +494,11 @@ void LLViewerTexture::updateClass() F64 texture_bytes_alloc = LLImageGL::getTextureBytesAllocated() / 1024.0 / 512.0; F64 vertex_bytes_alloc = LLVertexBuffer::getBytesAllocated() / 1024.0 / 512.0; + F64 render_bytes_alloc = LLRenderTarget::sBytesAllocated / 1024.0 / 512.0; // get an estimate of how much video memory we're using // NOTE: our metrics miss about half the vram we use, so this biases high but turns out to typically be within 5% of the real number - F32 used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc); + F32 used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc + render_bytes_alloc); F32 budget = max_vram_budget == 0 ? gGLManager.mVRAM : max_vram_budget; -- cgit v1.2.3 From f9473e8afcb624cc1b101195bf15943ec372b56f Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 6 May 2024 16:52:34 +0200 Subject: secondlife/viewer#1333 BOOL to bool conversion leftovers: ternaries --- indra/newview/llviewertexture.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 389da801df..eab8e95ae7 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2083,7 +2083,7 @@ bool LLViewerFetchedTexture::updateFetch() } } - return mIsFetching ? true : false; + return mIsFetching; } void LLViewerFetchedTexture::clearFetchedResults() @@ -2537,7 +2537,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL; } - bool final = mRawDiscardLevel <= entryp->mDesiredDiscard ? true : false; + bool final = mRawDiscardLevel <= entryp->mDesiredDiscard; //LL_INFOS() << "Running callback for " << getID() << LL_ENDL; //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL; entryp->mLastUsedDiscard = mRawDiscardLevel; @@ -2568,7 +2568,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard)) { mLastCallBackActiveTime = sCurrentTime; - bool final = gl_discard <= entryp->mDesiredDiscard ? true : false; + bool final = gl_discard <= entryp->mDesiredDiscard; entryp->mLastUsedDiscard = gl_discard; entryp->mCallback(true, this, NULL, NULL, gl_discard, final, entryp->mUserData); if (final) -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/llviewertexture.cpp | 8216 ++++++++++++++++++------------------- 1 file changed, 4108 insertions(+), 4108 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 24b7a6586f..fbb423358b 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1,4108 +1,4108 @@ - -/** - * @file llviewertexture.cpp - * @brief Object which handles a received image (and associated texture(s)) - * - * $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 "llviewerprecompiledheaders.h" - -#include "llviewertexture.h" - -// Library includes -#include "llmath.h" -#include "llerror.h" -#include "llgl.h" -#include "llglheaders.h" -#include "llhost.h" -#include "llimage.h" -#include "llimagebmp.h" -#include "llimagej2c.h" -#include "llimagetga.h" -#include "llstl.h" -#include "message.h" -#include "lltimer.h" - -// viewer includes -#include "llimagegl.h" -#include "lldrawpool.h" -#include "lltexturefetch.h" -#include "llviewertexturelist.h" -#include "llviewercontrol.h" -#include "pipeline.h" -#include "llappviewer.h" -#include "llface.h" -#include "llviewercamera.h" -#include "lltextureentry.h" -#include "lltexturemanagerbridge.h" -#include "llmediaentry.h" -#include "llvovolume.h" -#include "llviewermedia.h" -#include "lltexturecache.h" -#include "llviewerwindow.h" -#include "llwindow.h" -/////////////////////////////////////////////////////////////////////////////// - -// extern -const S32Megabytes gMinVideoRam(32); -const S32Megabytes gMaxVideoRam(512); - - -// statics -LLPointer LLViewerTexture::sNullImagep = NULL; -LLPointer LLViewerTexture::sBlackImagep = NULL; -LLPointer LLViewerTexture::sCheckerBoardImagep = NULL; -LLPointer LLViewerFetchedTexture::sMissingAssetImagep = NULL; -LLPointer LLViewerFetchedTexture::sWhiteImagep = NULL; -LLPointer LLViewerFetchedTexture::sDefaultImagep = NULL; -LLPointer LLViewerFetchedTexture::sSmokeImagep = NULL; -LLPointer LLViewerFetchedTexture::sFlatNormalImagep = NULL; -LLPointer LLViewerFetchedTexture::sDefaultIrradiancePBRp; -LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap; -LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL; -F32 LLViewerFetchedTexture::sMaxVirtualSize = 8192.f*8192.f; - -const std::string sTesterName("TextureTester"); - -S32 LLViewerTexture::sImageCount = 0; -S32 LLViewerTexture::sRawCount = 0; -S32 LLViewerTexture::sAuxCount = 0; -LLFrameTimer LLViewerTexture::sEvaluationTimer; -F32 LLViewerTexture::sDesiredDiscardBias = 0.f; -F32 LLViewerTexture::sDesiredDiscardScale = 1.1f; -S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size -const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64; -const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez; -const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128; -const S32 DEFAULT_ICON_DIMENSIONS = 32; -const S32 DEFAULT_THUMBNAIL_DIMENSIONS = 256; -U32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256. -U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; -bool LLViewerTexture::sFreezeImageUpdates = false; -F32 LLViewerTexture::sCurrentTime = 0.0f; - -constexpr F32 MIN_VRAM_BUDGET = 768.f; -F32 LLViewerTexture::sFreeVRAMMegabytes = MIN_VRAM_BUDGET; - -LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; - -const F64 log_2 = log(2.0); - -#if ADDRESS_SIZE == 32 -const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT / 2; -#else -const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT; -#endif - -//---------------------------------------------------------------------------------------------- -//namespace: LLViewerTextureAccess -//---------------------------------------------------------------------------------------------- - -LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb, - S32 discard_level, - bool need_imageraw, // Needs image raw for the callback - void* userdata, - LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, - LLViewerFetchedTexture* target, - bool pause) - : mCallback(cb), - mLastUsedDiscard(MAX_DISCARD_LEVEL+1), - mDesiredDiscard(discard_level), - mNeedsImageRaw(need_imageraw), - mUserData(userdata), - mSourceCallbackList(src_callback_list), - mPaused(pause) -{ - if(mSourceCallbackList) - { - mSourceCallbackList->insert(LLTextureKey(target->getID(), (ETexListType)target->getTextureListType())); - } -} - -LLLoadedCallbackEntry::~LLLoadedCallbackEntry() -{ -} - -void LLLoadedCallbackEntry::removeTexture(LLViewerFetchedTexture* tex) -{ - if (mSourceCallbackList && tex) - { - mSourceCallbackList->erase(LLTextureKey(tex->getID(), (ETexListType)tex->getTextureListType())); - } -} - -//static -void LLLoadedCallbackEntry::cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list) -{ - //clear texture callbacks. - if(callback_list && !callback_list->empty()) - { - for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = callback_list->begin(); - iter != callback_list->end(); ++iter) - { - LLViewerFetchedTexture* tex = gTextureList.findImage(*iter); - if(tex) - { - tex->deleteCallbackEntry(callback_list); - } - } - callback_list->clear(); - } -} - -LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, bool usemipmaps, LLImageGL* gl_image) -{ - return new LLViewerMediaTexture(media_id, usemipmaps, gl_image); -} - -void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector &output) -{ - return gTextureList.findTexturesByID(id, output); -} - -void LLViewerTextureManager::findTextures(const LLUUID& id, std::vector &output) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - std::vector fetched_output; - gTextureList.findTexturesByID(id, fetched_output); - std::vector::iterator iter = fetched_output.begin(); - while (iter != fetched_output.end()) - { - output.push_back(*iter); - iter++; - } - - //search media texture list - if (output.empty()) - { - LLViewerTexture* tex; - tex = LLViewerTextureManager::findMediaTexture(id); - if (tex) - { - output.push_back(tex); - } - } - -} - -LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - return gTextureList.findImage(id, (ETexListType)tex_type); -} - -LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) -{ - return LLViewerMediaTexture::findMediaTexture(media_id); -} - -LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, bool usemipmaps, LLImageGL* gl_image) -{ - LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id); - if(!tex) - { - tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image); - } - - tex->initVirtualSize(); - - return tex; -} - -LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLTexture* tex, bool report_error) -{ - if(!tex) - { - return NULL; - } - - S8 type = tex->getType(); - if(type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) - { - return static_cast(tex); - } - - if(report_error) - { - LL_ERRS() << "not a fetched texture type: " << type << LL_ENDL; - } - - return NULL; -} - -LLPointer LLViewerTextureManager::getLocalTexture(bool usemipmaps, bool generate_gl_tex) -{ - LLPointer tex = new LLViewerTexture(usemipmaps); - if(generate_gl_tex) - { - tex->generateGLTexture(); - tex->setCategory(LLGLTexture::LOCAL); - } - return tex; -} -LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& id, bool usemipmaps, bool generate_gl_tex) -{ - LLPointer tex = new LLViewerTexture(id, usemipmaps); - if(generate_gl_tex) - { - tex->generateGLTexture(); - tex->setCategory(LLGLTexture::LOCAL); - } - return tex; -} -LLPointer LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, bool usemipmaps) -{ - LLPointer tex = new LLViewerTexture(raw, usemipmaps); - tex->setCategory(LLGLTexture::LOCAL); - return tex; -} -LLPointer LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex) -{ - LLPointer tex = new LLViewerTexture(width, height, components, usemipmaps); - if(generate_gl_tex) - { - tex->generateGLTexture(); - tex->setCategory(LLGLTexture::LOCAL); - } - return tex; -} - -LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps) -{ - LLImageDataSharedLock lock(raw); - LLViewerFetchedTexture* ret = new LLViewerFetchedTexture(raw, type, usemipmaps); - gTextureList.addImage(ret, TEX_LIST_STANDARD); - return ret; -} - -LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( - const LLUUID &image_id, - FTType f_type, - bool usemipmaps, - LLViewerTexture::EBoostLevel boost_priority, - S8 texture_type, - LLGLint internal_format, - LLGLenum primary_format, - LLHost request_from_host) -{ - return gTextureList.getImage(image_id, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host); -} - -LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( - const std::string& filename, - FTType f_type, - bool usemipmaps, - LLViewerTexture::EBoostLevel boost_priority, - S8 texture_type, - LLGLint internal_format, - LLGLenum primary_format, - const LLUUID& force_id) -{ - return gTextureList.getImageFromFile(filename, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); -} - -//static -LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url, - FTType f_type, - bool usemipmaps, - LLViewerTexture::EBoostLevel boost_priority, - S8 texture_type, - LLGLint internal_format, - LLGLenum primary_format, - const LLUUID& force_id - ) -{ - return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); -} - -LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) -{ - return gTextureList.getImageFromHost(image_id, f_type, host); -} - -// Create a bridge to the viewer texture manager. -class LLViewerTextureManagerBridge : public LLTextureManagerBridge -{ - /*virtual*/ LLPointer getLocalTexture(bool usemipmaps = true, bool generate_gl_tex = true) - { - return LLViewerTextureManager::getLocalTexture(usemipmaps, generate_gl_tex); - } - - /*virtual*/ LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex = true) - { - return LLViewerTextureManager::getLocalTexture(width, height, components, usemipmaps, generate_gl_tex); - } - - /*virtual*/ LLGLTexture* getFetchedTexture(const LLUUID &image_id) - { - return LLViewerTextureManager::getFetchedTexture(image_id); - } -}; - - -void LLViewerTextureManager::init() -{ - { - LLPointer raw = new LLImageRaw(1,1,3); - raw->clear(0x77, 0x77, 0x77, 0xFF); - LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), true); - } - - const S32 dim = 128; - LLPointer image_raw = new LLImageRaw(dim,dim,3); - U8* data = image_raw->getData(); - - memset(data, 0, dim * dim * 3); - LLViewerTexture::sBlackImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); - -#if 1 - LLPointer imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT); - LLViewerFetchedTexture::sDefaultImagep = imagep; - - for (S32 i = 0; i=(dim-border) || j>=(dim-border)) - { - *data++ = 0xff; - *data++ = 0xff; - *data++ = 0xff; - } - else -#endif - { - *data++ = 0x7f; - *data++ = 0x7f; - *data++ = 0x7f; - } - } - } - imagep->createGLTexture(0, image_raw); - //cache the raw image - imagep->setCachedRawImage(0, image_raw); - image_raw = NULL; -#else - LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, true, LLGLTexture::BOOST_UI); -#endif - LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); - LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER); - - image_raw = new LLImageRaw(32,32,3); - data = image_raw->getData(); - - for (S32 i = 0; i < (32*32*3); i+=3) - { - S32 x = (i % (32*3)) / (3*16); - S32 y = i / (32*3*16); - U8 color = ((x + y) % 2) * 255; - data[i] = color; - data[i+1] = color; - data[i+2] = color; - } - - LLViewerTexture::sCheckerBoardImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); - - LLViewerTexture::initClass(); - - // Create a texture manager bridge. - gTextureManagerBridgep = new LLViewerTextureManagerBridge; - - if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName)) - { - sTesterp = new LLTexturePipelineTester(); - if (!sTesterp->isValid()) - { - delete sTesterp; - sTesterp = NULL; - } - } -} - -void LLViewerTextureManager::cleanup() -{ - stop_glerror(); - - delete gTextureManagerBridgep; - LLImageGL::sDefaultGLTexture = NULL; - LLViewerTexture::sNullImagep = NULL; - LLViewerTexture::sBlackImagep = NULL; - LLViewerTexture::sCheckerBoardImagep = NULL; - LLViewerFetchedTexture::sDefaultImagep = NULL; - LLViewerFetchedTexture::sSmokeImagep = NULL; - LLViewerFetchedTexture::sMissingAssetImagep = NULL; - LLTexUnit::sWhiteTexture = 0; - LLViewerFetchedTexture::sWhiteImagep = NULL; - - LLViewerFetchedTexture::sFlatNormalImagep = NULL; - LLViewerFetchedTexture::sDefaultIrradiancePBRp = NULL; - - LLViewerMediaTexture::cleanUpClass(); -} - -//---------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------- -//start of LLViewerTexture -//---------------------------------------------------------------------------------------------- -// static -void LLViewerTexture::initClass() -{ - LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture(); -} - -// non-const (used externally -F32 texmem_lower_bound_scale = 0.85f; -F32 texmem_middle_bound_scale = 0.925f; - -//static -void LLViewerTexture::updateClass() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - sCurrentTime = gFrameTimeSeconds; - - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); - if (tester) - { - tester->update(); - } - - LLViewerMediaTexture::updateClass(); - - static LLCachedControl max_vram_budget(gSavedSettings, "RenderMaxVRAMBudget", 0); - - F64 texture_bytes_alloc = LLImageGL::getTextureBytesAllocated() / 1024.0 / 512.0; - F64 vertex_bytes_alloc = LLVertexBuffer::getBytesAllocated() / 1024.0 / 512.0; - F64 render_bytes_alloc = LLRenderTarget::sBytesAllocated / 1024.0 / 512.0; - - // get an estimate of how much video memory we're using - // NOTE: our metrics miss about half the vram we use, so this biases high but turns out to typically be within 5% of the real number - F32 used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc + render_bytes_alloc); - - F32 budget = max_vram_budget == 0 ? gGLManager.mVRAM : max_vram_budget; - - // try to leave half a GB for everyone else, but keep at least 768MB for ourselves - F32 target = llmax(budget - 512.f, MIN_VRAM_BUDGET); - sFreeVRAMMegabytes = target - used; - - F32 over_pct = llmax((used-target) / target, 0.f); - sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct); - - if (sDesiredDiscardBias > 1.f) - { - sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01; - } - - LLViewerTexture::sFreezeImageUpdates = false; // sDesiredDiscardBias > (desired_discard_bias_max - 1.0f); -} - -//end of static functions -//------------------------------------------------------------------------------------------- -const U32 LLViewerTexture::sCurrentFileVersion = 1; - -LLViewerTexture::LLViewerTexture(bool usemipmaps) : - LLGLTexture(usemipmaps) -{ - init(true); - - mID.generate(); - sImageCount++; -} - -LLViewerTexture::LLViewerTexture(const LLUUID& id, bool usemipmaps) : - LLGLTexture(usemipmaps), - mID(id) -{ - init(true); - - sImageCount++; -} - -LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps) : - LLGLTexture(width, height, components, usemipmaps) -{ - init(true); - - mID.generate(); - sImageCount++; -} - -LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, bool usemipmaps) : - LLGLTexture(raw, usemipmaps) -{ - init(true); - - mID.generate(); - sImageCount++; -} - -LLViewerTexture::~LLViewerTexture() -{ - // LL_DEBUGS("Avatar") << mID << LL_ENDL; - cleanup(); - sImageCount--; -} - -// virtual -void LLViewerTexture::init(bool firstinit) -{ - mMaxVirtualSize = 0.f; - mMaxVirtualSizeResetInterval = 1; - mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval; - mParcelMedia = NULL; - - memset(&mNumVolumes, 0, sizeof(U32)* LLRender::NUM_VOLUME_TEXTURE_CHANNELS); - mFaceList[LLRender::DIFFUSE_MAP].clear(); - mFaceList[LLRender::NORMAL_MAP].clear(); - mFaceList[LLRender::SPECULAR_MAP].clear(); - mNumFaces[LLRender::DIFFUSE_MAP] = - mNumFaces[LLRender::NORMAL_MAP] = - mNumFaces[LLRender::SPECULAR_MAP] = 0; - - mVolumeList[LLRender::LIGHT_TEX].clear(); - mVolumeList[LLRender::SCULPT_TEX].clear(); - - mMainQueue = LL::WorkQueue::getInstance("mainloop"); - mImageQueue = LL::WorkQueue::getInstance("LLImageGL"); -} - -//virtual -S8 LLViewerTexture::getType() const -{ - return LLViewerTexture::LOCAL_TEXTURE; -} - -void LLViewerTexture::cleanup() -{ - if (LLAppViewer::getTextureFetch()) - { - LLAppViewer::getTextureFetch()->updateRequestPriority(mID, 0.f); - } - - mFaceList[LLRender::DIFFUSE_MAP].clear(); - mFaceList[LLRender::NORMAL_MAP].clear(); - mFaceList[LLRender::SPECULAR_MAP].clear(); - mVolumeList[LLRender::LIGHT_TEX].clear(); - mVolumeList[LLRender::SCULPT_TEX].clear(); -} - -// virtual -void LLViewerTexture::dump() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - LLGLTexture::dump(); - - LL_INFOS() << "LLViewerTexture" - << " mID " << mID - << LL_ENDL; -} - -void LLViewerTexture::setBoostLevel(S32 level) -{ - if(mBoostLevel != level) - { - mBoostLevel = level; - if(mBoostLevel != LLViewerTexture::BOOST_NONE && - mBoostLevel != LLViewerTexture::BOOST_SELECTED && - mBoostLevel != LLViewerTexture::BOOST_ICON && - mBoostLevel != LLViewerTexture::BOOST_THUMBNAIL) - { - setNoDelete(); - } - } - - // strongly encourage anything boosted to load at full res - if (mBoostLevel >= LLViewerTexture::BOOST_HIGH) - { - mMaxVirtualSize = 2048.f * 2048.f; - } -} - -bool LLViewerTexture::isActiveFetching() -{ - return false; -} - -bool LLViewerTexture::bindDebugImage(const S32 stage) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (stage < 0) return false; - - bool res = true; - if (LLViewerTexture::sCheckerBoardImagep.notNull() && (this != LLViewerTexture::sCheckerBoardImagep.get())) - { - res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sCheckerBoardImagep); - } - - if(!res) - { - return bindDefaultImage(stage); - } - - return res; -} - -bool LLViewerTexture::bindDefaultImage(S32 stage) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (stage < 0) return false; - - bool res = true; - if (LLViewerFetchedTexture::sDefaultImagep.notNull() && (this != LLViewerFetchedTexture::sDefaultImagep.get())) - { - // use default if we've got it - res = gGL.getTexUnit(stage)->bind(LLViewerFetchedTexture::sDefaultImagep); - } - if (!res && LLViewerTexture::sNullImagep.notNull() && (this != LLViewerTexture::sNullImagep)) - { - res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sNullImagep); - } - if (!res) - { - LL_WARNS() << "LLViewerTexture::bindDefaultImage failed." << LL_ENDL; - } - stop_glerror(); - - //check if there is cached raw image and switch to it if possible - switchToCachedImage(); - - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); - if (tester) - { - tester->updateGrayTextureBinding(); - } - return res; -} - -//virtual -bool LLViewerTexture::isMissingAsset()const -{ - return false; -} - -//virtual -void LLViewerTexture::forceImmediateUpdate() -{ -} - -void LLViewerTexture::addTextureStats(F32 virtual_size, bool needs_gltexture) const -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(needs_gltexture) - { - mNeedsGLTexture = true; - } - - virtual_size = llmin(virtual_size, LLViewerFetchedTexture::sMaxVirtualSize); - - if (virtual_size > mMaxVirtualSize) - { - mMaxVirtualSize = virtual_size; - } -} - -void LLViewerTexture::resetTextureStats() -{ - mMaxVirtualSize = 0.0f; - mMaxVirtualSizeResetCounter = 0; -} - -//virtual -F32 LLViewerTexture::getMaxVirtualSize() -{ - return mMaxVirtualSize; -} - -//virtual -void LLViewerTexture::setKnownDrawSize(S32 width, S32 height) -{ - //nothing here. -} - -//virtual -void LLViewerTexture::addFace(U32 ch, LLFace* facep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); - - if(mNumFaces[ch] >= mFaceList[ch].size()) - { - mFaceList[ch].resize(2 * mNumFaces[ch] + 1); - } - mFaceList[ch][mNumFaces[ch]] = facep; - facep->setIndexInTex(ch, mNumFaces[ch]); - mNumFaces[ch]++; - mLastFaceListUpdateTimer.reset(); -} - -//virtual -void LLViewerTexture::removeFace(U32 ch, LLFace* facep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); - - if(mNumFaces[ch] > 1) - { - S32 index = facep->getIndexInTex(ch); - llassert(index < mFaceList[ch].size()); - llassert(index < mNumFaces[ch]); - mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]]; - mFaceList[ch][index]->setIndexInTex(ch, index); - } - else - { - mFaceList[ch].clear(); - mNumFaces[ch] = 0; - } - mLastFaceListUpdateTimer.reset(); -} - -S32 LLViewerTexture::getTotalNumFaces() const -{ - S32 ret = 0; - - for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) - { - ret += mNumFaces[i]; - } - - return ret; -} - -S32 LLViewerTexture::getNumFaces(U32 ch) const -{ - llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); - return mNumFaces[ch]; -} - - -//virtual -void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (mNumVolumes[ch] >= mVolumeList[ch].size()) - { - mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1); - } - mVolumeList[ch][mNumVolumes[ch]] = volumep; - volumep->setIndexInTex(ch, mNumVolumes[ch]); - mNumVolumes[ch]++; - mLastVolumeListUpdateTimer.reset(); -} - -//virtual -void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (mNumVolumes[ch] > 1) - { - S32 index = volumep->getIndexInTex(ch); - llassert(index < mVolumeList[ch].size()); - llassert(index < mNumVolumes[ch]); - mVolumeList[ch][index] = mVolumeList[ch][--mNumVolumes[ch]]; - mVolumeList[ch][index]->setIndexInTex(ch, index); - } - else - { - mVolumeList[ch].clear(); - mNumVolumes[ch] = 0; - } - mLastVolumeListUpdateTimer.reset(); -} - -S32 LLViewerTexture::getNumVolumes(U32 ch) const -{ - return mNumVolumes[ch]; -} - -void LLViewerTexture::reorganizeFaceList() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static const F32 MAX_WAIT_TIME = 20.f; // seconds - static const U32 MAX_EXTRA_BUFFER_SIZE = 4; - - if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) - { - return; - } - - for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) - { - if(mNumFaces[i] + MAX_EXTRA_BUFFER_SIZE > mFaceList[i].size()) - { - return; - } - - mFaceList[i].erase(mFaceList[i].begin() + mNumFaces[i], mFaceList[i].end()); - } - - mLastFaceListUpdateTimer.reset(); -} - -void LLViewerTexture::reorganizeVolumeList() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static const F32 MAX_WAIT_TIME = 20.f; // seconds - static const U32 MAX_EXTRA_BUFFER_SIZE = 4; - - - for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i) - { - if (mNumVolumes[i] + MAX_EXTRA_BUFFER_SIZE > mVolumeList[i].size()) - { - return; - } - } - - if(mLastVolumeListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) - { - return; - } - - mLastVolumeListUpdateTimer.reset(); - for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i) - { - mVolumeList[i].erase(mVolumeList[i].begin() + mNumVolumes[i], mVolumeList[i].end()); - } -} - -//virtual -void LLViewerTexture::switchToCachedImage() -{ - //nothing here. -} - -//virtual -void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) -{ - //nothing here. -} - -bool LLViewerTexture::isLargeImage() -{ - return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize; -} - -//virtual -void LLViewerTexture::updateBindStatsForTester() -{ - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); - if (tester) - { - tester->updateTextureBindingStats(this); - } -} - -//---------------------------------------------------------------------------------------------- -//end of LLViewerTexture -//---------------------------------------------------------------------------------------------- - -const std::string& fttype_to_string(const FTType& fttype) -{ - static const std::string ftt_unknown("FTT_UNKNOWN"); - static const std::string ftt_default("FTT_DEFAULT"); - static const std::string ftt_server_bake("FTT_SERVER_BAKE"); - static const std::string ftt_host_bake("FTT_HOST_BAKE"); - static const std::string ftt_map_tile("FTT_MAP_TILE"); - static const std::string ftt_local_file("FTT_LOCAL_FILE"); - static const std::string ftt_error("FTT_ERROR"); - switch(fttype) - { - case FTT_UNKNOWN: return ftt_unknown; break; - case FTT_DEFAULT: return ftt_default; break; - case FTT_SERVER_BAKE: return ftt_server_bake; break; - case FTT_HOST_BAKE: return ftt_host_bake; break; - case FTT_MAP_TILE: return ftt_map_tile; break; - case FTT_LOCAL_FILE: return ftt_local_file; break; - } - return ftt_error; -} - -//---------------------------------------------------------------------------------------------- -//start of LLViewerFetchedTexture -//---------------------------------------------------------------------------------------------- - -//static -LLViewerFetchedTexture* LLViewerFetchedTexture::getSmokeImage() -{ - if (sSmokeImagep.isNull()) - { - sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE); - } - - sSmokeImagep->addTextureStats(1024.f * 1024.f); - - return sSmokeImagep; -} - -LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host, bool usemipmaps) - : LLViewerTexture(id, usemipmaps), - mTargetHost(host) -{ - init(true); - mFTType = f_type; - if (mFTType == FTT_HOST_BAKE) - { - LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL; - } - generateGLTexture(); -} - -LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, bool usemipmaps) - : LLViewerTexture(raw, usemipmaps) -{ - init(true); - mFTType = f_type; -} - -LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps) - : LLViewerTexture(id, usemipmaps), - mUrl(url) -{ - init(true); - mFTType = f_type; - generateGLTexture(); -} - -void LLViewerFetchedTexture::init(bool firstinit) -{ - mOrigWidth = 0; - mOrigHeight = 0; - mHasAux = false; - mNeedsAux = false; - mRequestedDiscardLevel = -1; - mRequestedDownloadPriority = 0.f; - mFullyLoaded = false; - mCanUseHTTP = true; - mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; - mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; - - mDecodingAux = false; - - mKnownDrawWidth = 0; - mKnownDrawHeight = 0; - mKnownDrawSizeChanged = false; - - if (firstinit) - { - mInImageList = 0; - } - - // Only set mIsMissingAsset true when we know for certain that the database - // does not contain this image. - mIsMissingAsset = false; - - mLoadedCallbackDesiredDiscardLevel = S8_MAX; - mPauseLoadedCallBacks = false; - - mNeedsCreateTexture = false; - - mIsRawImageValid = false; - mRawDiscardLevel = INVALID_DISCARD_LEVEL; - mMinDiscardLevel = 0; - - mHasFetcher = false; - mIsFetching = false; - mFetchState = 0; - mFetchPriority = 0; - mDownloadProgress = 0.f; - mFetchDeltaTime = 999999.f; - mRequestDeltaTime = 0.f; - mForSculpt = false; - mIsFetched = false; - mInFastCacheList = false; - - mCachedRawImage = NULL; - mCachedRawDiscardLevel = -1; - mCachedRawImageReady = false; - - mSavedRawImage = NULL; - mForceToSaveRawImage = false; - mSaveRawImage = false; - mSavedRawDiscardLevel = -1; - mDesiredSavedRawDiscardLevel = -1; - mLastReferencedSavedRawImageTime = 0.0f; - mKeptSavedRawImageTime = 0.f; - mLastCallBackActiveTime = 0.f; - mForceCallbackFetch = false; - mInDebug = false; - mUnremovable = false; - - mFTType = FTT_UNKNOWN; -} - -LLViewerFetchedTexture::~LLViewerFetchedTexture() -{ - assert_main_thread(); - //*NOTE getTextureFetch can return NULL when Viewer is shutting down. - // This is due to LLWearableList is singleton and is destroyed after - // LLAppViewer::cleanup() was called. (see ticket EXT-177) - if (mHasFetcher && LLAppViewer::getTextureFetch()) - { - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - } - cleanup(); -} - -//virtual -S8 LLViewerFetchedTexture::getType() const -{ - return LLViewerTexture::FETCHED_TEXTURE; -} - -FTType LLViewerFetchedTexture::getFTType() const -{ - return mFTType; -} - -void LLViewerFetchedTexture::cleanup() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter++; - // We never finished loading the image. Indicate failure. - // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback( false, this, NULL, NULL, 0, true, entryp->mUserData ); - entryp->removeTexture(this); - delete entryp; - } - mLoadedCallbackList.clear(); - mNeedsAux = false; - - // Clean up image data - destroyRawImage(); - mCachedRawImage = NULL; - mCachedRawDiscardLevel = -1; - mCachedRawImageReady = false; - mSavedRawImage = NULL; - mSavedRawDiscardLevel = -1; -} - -//access the fast cache -void LLViewerFetchedTexture::loadFromFastCache() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(!mInFastCacheList) - { - return; //no need to access the fast cache. - } - mInFastCacheList = false; - - add(LLTextureFetch::sCacheAttempt, 1.0); - - LLTimer fastCacheTimer; - mRawImage = LLAppViewer::getTextureCache()->readFromFastCache(getID(), mRawDiscardLevel); - if(mRawImage.notNull()) - { - F32 cachReadTime = fastCacheTimer.getElapsedTimeF32(); - - add(LLTextureFetch::sCacheHit, 1.0); - record(LLTextureFetch::sCacheHitRate, LLUnits::Ratio::fromValue(1)); - sample(LLTextureFetch::sCacheReadLatency, cachReadTime); - - mFullWidth = mRawImage->getWidth() << mRawDiscardLevel; - mFullHeight = mRawImage->getHeight() << mRawDiscardLevel; - setTexelsPerImage(); - - if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE) - { - //discard all oversized textures. - destroyRawImage(); - LL_WARNS() << "oversized, setting as missing" << LL_ENDL; - setIsMissingAsset(); - mRawDiscardLevel = INVALID_DISCARD_LEVEL; - } - else - { - if (mBoostLevel == LLGLTexture::BOOST_ICON) - { - // Shouldn't do anything usefull since texures in fast cache are 16x16, - // it is here in case fast cache changes. - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; - if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) - { - // scale oversized icon, no need to give more work to gl - mRawImage->scale(expected_width, expected_height); - } - } - - if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; - if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) - { - // scale oversized icon, no need to give more work to gl - mRawImage->scale(expected_width, expected_height); - } - } - - mRequestedDiscardLevel = mDesiredDiscardLevel + 1; - mIsRawImageValid = true; - addToCreateTexture(); - } - } - else - { - record(LLTextureFetch::sCacheHitRate, LLUnits::Ratio::fromValue(0)); - } -} - -void LLViewerFetchedTexture::setForSculpt() -{ - static const S32 MAX_INTERVAL = 8; //frames - - mForSculpt = true; - if(isForSculptOnly() && hasGLTexture() && !getBoundRecently()) - { - destroyGLTexture(); //sculpt image does not need gl texture. - mTextureState = ACTIVE; - } - checkCachedRawSculptImage(); - setMaxVirtualSizeResetInterval(MAX_INTERVAL); -} - -bool LLViewerFetchedTexture::isForSculptOnly() const -{ - return mForSculpt && !mNeedsGLTexture; -} - -bool LLViewerFetchedTexture::isDeleted() -{ - return mTextureState == DELETED; -} - -bool LLViewerFetchedTexture::isInactive() -{ - return mTextureState == INACTIVE; -} - -bool LLViewerFetchedTexture::isDeletionCandidate() -{ - return mTextureState == DELETION_CANDIDATE; -} - -void LLViewerFetchedTexture::setDeletionCandidate() -{ - if(mGLTexturep.notNull() && mGLTexturep->getTexName() && (mTextureState == INACTIVE)) - { - mTextureState = DELETION_CANDIDATE; - } -} - -//set the texture inactive -void LLViewerFetchedTexture::setInactive() -{ - if(mTextureState == ACTIVE && mGLTexturep.notNull() && mGLTexturep->getTexName() && !mGLTexturep->getBoundRecently()) - { - mTextureState = INACTIVE; - } -} - -bool LLViewerFetchedTexture::isFullyLoaded() const -{ - // Unfortunately, the boolean "mFullyLoaded" is never updated correctly so we use that logic - // to check if the texture is there and completely downloaded - return (mFullWidth != 0) && (mFullHeight != 0) && !mIsFetching && !mHasFetcher; -} - - -// virtual -void LLViewerFetchedTexture::dump() -{ - LLViewerTexture::dump(); - - LL_INFOS() << "Dump : " << mID - << ", mIsMissingAsset = " << (S32)mIsMissingAsset - << ", mFullWidth = " << (S32)mFullWidth - << ", mFullHeight = " << (S32)mFullHeight - << ", mOrigWidth = " << (S32)mOrigWidth - << ", mOrigHeight = " << (S32)mOrigHeight - << LL_ENDL; - LL_INFOS() << " : " - << " mFullyLoaded = " << (S32)mFullyLoaded - << ", mFetchState = " << (S32)mFetchState - << ", mFetchPriority = " << (S32)mFetchPriority - << ", mDownloadProgress = " << (F32)mDownloadProgress - << LL_ENDL; - LL_INFOS() << " : " - << " mHasFetcher = " << (S32)mHasFetcher - << ", mIsFetching = " << (S32)mIsFetching - << ", mIsFetched = " << (S32)mIsFetched - << ", mBoostLevel = " << (S32)mBoostLevel - << LL_ENDL; -} - -/////////////////////////////////////////////////////////////////////////////// -// ONLY called from LLViewerFetchedTextureList -void LLViewerFetchedTexture::destroyTexture() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - - if (mNeedsCreateTexture)//return if in the process of generating a new texture. - { - return; - } - - //LL_DEBUGS("Avatar") << mID << LL_ENDL; - destroyGLTexture(); - mFullyLoaded = false; -} - -void LLViewerFetchedTexture::addToCreateTexture() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - bool force_update = false; - if (getComponents() != mRawImage->getComponents()) - { - // We've changed the number of components, so we need to move any - // objects using this pool to a different pool. - mComponents = mRawImage->getComponents(); - mGLTexturep->setComponents(mComponents); - force_update = true; - - for (U32 j = 0; j < LLRender::NUM_TEXTURE_CHANNELS; ++j) - { - llassert(mNumFaces[j] <= mFaceList[j].size()); - - for(U32 i = 0; i < mNumFaces[j]; i++) - { - mFaceList[j][i]->dirtyTexture(); - } - } - - //discard the cached raw image and the saved raw image - mCachedRawImageReady = false; - mCachedRawDiscardLevel = -1; - mCachedRawImage = NULL; - mSavedRawDiscardLevel = -1; - mSavedRawImage = NULL; - } - - if(isForSculptOnly()) - { - //just update some variables, not to create a real GL texture. - createGLTexture(mRawDiscardLevel, mRawImage, 0, false); - mNeedsCreateTexture = false; - destroyRawImage(); - } - else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel) - { - mNeedsCreateTexture = false; - destroyRawImage(); - } - else - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -#if 1 - // - //if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up, - //so do not scale down the over qualified image. - //Note: scaling down image is expensensive. Do it only when very necessary. - // - if(mRequestedDiscardLevel <= mDesiredDiscardLevel && !mForceToSaveRawImage) - { - S32 w = mFullWidth >> mRawDiscardLevel; - S32 h = mFullHeight >> mRawDiscardLevel; - - //if big image, do not load extra data - //scale it down to size >= LLViewerTexture::sMinLargeImageSize - if(w * h > LLViewerTexture::sMinLargeImageSize) - { - S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel; - - if(d_level > 0) - { - S32 i = 0; - while((d_level > 0) && ((w >> i) * (h >> i) > LLViewerTexture::sMinLargeImageSize)) - { - i++; - d_level--; - } - if(i > 0) - { - mRawDiscardLevel += i; - if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0) - { - mNeedsCreateTexture = false; - destroyRawImage(); - return; - } - - { - //make a duplicate in case somebody else is using this raw image - mRawImage = mRawImage->scaled(w >> i, h >> i); - } - } - } - } - } -#endif - scheduleCreateTexture(); - } - return; -} - -// ONLY called from LLViewerTextureList -bool LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -#if LL_IMAGEGL_THREAD_CHECK - mGLTexturep->checkActiveThread(); -#endif - - if (!mNeedsCreateTexture) - { - destroyRawImage(); - return false; - } - mNeedsCreateTexture = false; - - if (mRawImage.isNull()) - { - LL_ERRS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL; - } - if (mRawImage->isBufferInvalid()) - { - LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL; - destroyRawImage(); - return false; - } - // LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", - // mRawDiscardLevel, - // mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) - // << mID.getString() << LL_ENDL; - bool res = true; - - // store original size only for locally-sourced images - if (mUrl.compare(0, 7, "file://") == 0) - { - mOrigWidth = mRawImage->getWidth(); - mOrigHeight = mRawImage->getHeight(); - - // This is only safe because it's a local image and fetcher doesn't use raw data - // from local images, but this might become unsafe in case of changes to fetcher - if (mBoostLevel == BOOST_PREVIEW) - { - mRawImage->biasedScaleToPowerOfTwo(1024); - } - else - { // leave black border, do not scale image content - mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, false); - } - - mFullWidth = mRawImage->getWidth(); - mFullHeight = mRawImage->getHeight(); - setTexelsPerImage(); - } - else - { - mOrigWidth = mFullWidth; - mOrigHeight = mFullHeight; - } - - bool size_okay = true; - - S32 discard_level = mRawDiscardLevel; - if (mRawDiscardLevel < 0) - { - LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL; - discard_level = 0; - } - - U32 raw_width = mRawImage->getWidth() << discard_level; - U32 raw_height = mRawImage->getHeight() << discard_level; - - if (raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE) - { - LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL; - size_okay = false; - } - - if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) - { - // A non power-of-two image was uploaded (through a non standard client) - LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL; - size_okay = false; - } - - if (!size_okay) - { - // An inappropriately-sized image was uploaded (through a non standard client) - // We treat these images as missing assets which causes them to - // be renderd as 'missing image' and to stop requesting data - LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL; - setIsMissingAsset(); - destroyRawImage(); - return false; - } - - if (mGLTexturep->getHasExplicitFormat()) - { - LLGLenum format = mGLTexturep->getPrimaryFormat(); - S8 components = mRawImage->getComponents(); - if ((format == GL_RGBA && components < 4) - || (format == GL_RGB && components < 3)) - { - LL_WARNS() << "Can't create a texture " << mID << ": invalid image format " << std::hex << format << " vs components " << (U32)components << LL_ENDL; - // Was expecting specific format but raw texture has insufficient components for - // such format, using such texture will result in crash or will display wrongly - // if we change format. Texture might be corrupted server side, so just set as - // missing and clear cashed texture (do not cause reload loop, will retry&recover - // during new session) - setIsMissingAsset(); - destroyRawImage(); - LLAppViewer::getTextureCache()->removeFromCache(mID); - return false; - } - } - - return res; -} - -bool LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) -{ - if (!mNeedsCreateTexture) - { - return false; - } - - bool res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, true, mBoostLevel); - - return res; -} - -void LLViewerFetchedTexture::postCreateTexture() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (!mNeedsCreateTexture) - { - return; - } -#if LL_IMAGEGL_THREAD_CHECK - mGLTexturep->checkActiveThread(); -#endif - - setActive(); - - if (!needsToSaveRawImage()) - { - mNeedsAux = false; - destroyRawImage(); - } - - mNeedsCreateTexture = false; -} - -void LLViewerFetchedTexture::scheduleCreateTexture() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - - if (!mNeedsCreateTexture) - { - mNeedsCreateTexture = true; - if (preCreateTexture()) - { -#if LL_IMAGEGL_THREAD_CHECK - //grab a copy of the raw image data to make sure it isn't modified pending texture creation - U8* data = mRawImage->getData(); - U8* data_copy = nullptr; - S32 size = mRawImage->getDataSize(); - if (data != nullptr && size > 0) - { - data_copy = new U8[size]; - memcpy(data_copy, data, size); - } -#endif - mNeedsCreateTexture = true; - auto mainq = LLImageGLThread::sEnabledTextures ? mMainQueue.lock() : nullptr; - if (mainq) - { - ref(); - mainq->postTo( - mImageQueue, - // work to be done on LLImageGL worker thread -#if LL_IMAGEGL_THREAD_CHECK - [this, data, data_copy, size]() - { - mGLTexturep->mActiveThread = LLThread::currentID(); - //verify data is unmodified - llassert(data == mRawImage->getData()); - llassert(mRawImage->getDataSize() == size); - llassert(memcmp(data, data_copy, size) == 0); -#else - [this]() - { -#endif - //actually create the texture on a background thread - createTexture(); - -#if LL_IMAGEGL_THREAD_CHECK - //verify data is unmodified - llassert(data == mRawImage->getData()); - llassert(mRawImage->getDataSize() == size); - llassert(memcmp(data, data_copy, size) == 0); -#endif - }, - // callback to be run on main thread -#if LL_IMAGEGL_THREAD_CHECK - [this, data, data_copy, size]() - { - mGLTexturep->mActiveThread = LLThread::currentID(); - llassert(data == mRawImage->getData()); - llassert(mRawImage->getDataSize() == size); - llassert(memcmp(data, data_copy, size) == 0); - delete[] data_copy; -#else - [this]() - { -#endif - //finalize on main thread - postCreateTexture(); - unref(); - }); - } - else - { - gTextureList.mCreateTextureList.insert(this); - } - } - } -} - -// Call with 0,0 to turn this feature off. -//virtual -void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mKnownDrawWidth < width || mKnownDrawHeight < height) - { - mKnownDrawWidth = llmax(mKnownDrawWidth, width); - mKnownDrawHeight = llmax(mKnownDrawHeight, height); - - mKnownDrawSizeChanged = true; - mFullyLoaded = false; - } - addTextureStats((F32)(mKnownDrawWidth * mKnownDrawHeight)); -} - -void LLViewerFetchedTexture::setDebugText(const std::string& text) -{ - for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) - { - llassert(mNumFaces[ch] <= mFaceList[ch].size()); - - for (U32 i = 0; i < mNumFaces[ch]; i++) - { - LLFace* facep = mFaceList[ch][i]; - if (facep) - { - LLDrawable* drawable = facep->getDrawable(); - if (drawable) - { - drawable->getVObj()->setDebugText(text); - } - } - } - } -} - -//virtual -void LLViewerFetchedTexture::processTextureStats() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mFullyLoaded) - { - if(mDesiredDiscardLevel > mMinDesiredDiscardLevel)//need to load more - { - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); - mFullyLoaded = false; - } - //setDebugText("fully loaded"); - } - else - { - updateVirtualSize(); - - static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); - - if (textures_fullres) - { - mDesiredDiscardLevel = 0; - } - else if (mDontDiscard && (mBoostLevel == LLGLTexture::BOOST_ICON || mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)) - { - if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) - { - mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 - } - else - { - mDesiredDiscardLevel = 0; - } - } - else if(!mFullWidth || !mFullHeight) - { - mDesiredDiscardLevel = llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel); - } - else - { - U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 - if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight) - { - if (mFullWidth > desired_size || mFullHeight > desired_size) - { - mDesiredDiscardLevel = 1; - } - else - { - mDesiredDiscardLevel = 0; - } - } - else if(mKnownDrawSizeChanged)//known draw size is set - { - mDesiredDiscardLevel = (S8)llmin(log((F32)mFullWidth / mKnownDrawWidth) / log_2, - log((F32)mFullHeight / mKnownDrawHeight) / log_2); - mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()); - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); - } - mKnownDrawSizeChanged = false; - - if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel)) - { - mFullyLoaded = true; - } - } - } - - if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) //force to refetch the texture. - { - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); - if(getDiscardLevel() < 0 || getDiscardLevel() > mDesiredDiscardLevel) - { - mFullyLoaded = false; - } - } -} - -//============================================================================ - -void LLViewerFetchedTexture::updateVirtualSize() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - reorganizeFaceList(); - reorganizeVolumeList(); -} - -S32 LLViewerFetchedTexture::getCurrentDiscardLevelForFetching() -{ - S32 current_discard = getDiscardLevel(); - if(mForceToSaveRawImage) - { - if(mSavedRawDiscardLevel < 0 || current_discard < 0) - { - current_discard = -1; - } - else - { - current_discard = llmax(current_discard, mSavedRawDiscardLevel); - } - } - - return current_discard; -} - -bool LLViewerFetchedTexture::setDebugFetching(S32 debug_level) -{ - if(debug_level < 0) - { - mInDebug = false; - return false; - } - mInDebug = true; - - mDesiredDiscardLevel = debug_level; - - return true; -} - -bool LLViewerFetchedTexture::isActiveFetching() -{ - static LLCachedControl monitor_enabled(gSavedSettings,"DebugShowTextureInfo"); - - return mFetchState > 7 && mFetchState < 10 && monitor_enabled; //in state of WAIT_HTTP_REQ or DECODE_IMAGE. -} - -void LLViewerFetchedTexture::setBoostLevel(S32 level) -{ - LLViewerTexture::setBoostLevel(level); - - if (level >= LLViewerTexture::BOOST_HIGH) - { - mDesiredDiscardLevel = 0; - } -} - -bool LLViewerFetchedTexture::updateFetch() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false); - - if(textures_decode_disabled) // don't fetch the surface textures in wireframe mode - { - return false; - } - - mFetchState = 0; - mFetchPriority = 0; - mFetchDeltaTime = 999999.f; - mRequestDeltaTime = 999999.f; - -#ifndef LL_RELEASE_FOR_DOWNLOAD - if (mID == LLAppViewer::getTextureFetch()->mDebugID) - { - LLAppViewer::getTextureFetch()->mDebugCount++; // for setting breakpoints - } -#endif - - if (mNeedsCreateTexture) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - needs create"); - // We may be fetching still (e.g. waiting on write) - // but don't check until we've processed the raw data we have - return false; - } - if (mIsMissingAsset) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - missing asset"); - llassert(!mHasFetcher); - return false; // skip - } - if (!mLoadedCallbackList.empty() && mRawImage.notNull()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - callback pending"); - return false; // process any raw image data in callbacks before replacing - } - if(mInFastCacheList) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - in fast cache"); - return false; - } - if (mGLTexturep.isNull()) - { // fix for crash inside getCurrentDiscardLevelForFetching (shouldn't happen but appears to be happening) - llassert(false); - return false; - } - - S32 current_discard = getCurrentDiscardLevelForFetching(); - S32 desired_discard = getDesiredDiscardLevel(); - F32 decode_priority = mMaxVirtualSize; - - if (mIsFetching) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - is fetching"); - // Sets mRawDiscardLevel, mRawImage, mAuxRawImage - S32 fetch_discard = current_discard; - - if (mRawImage.notNull()) sRawCount--; - if (mAuxRawImage.notNull()) sAuxCount--; - // keep in mind that fetcher still might need raw image, don't modify original - bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, - mLastHttpGetStatus); - if (mRawImage.notNull()) sRawCount++; - if (mAuxRawImage.notNull()) - { - mHasAux = true; - sAuxCount++; - } - if (finished) - { - mIsFetching = false; - mLastFetchState = -1; - mLastPacketTimer.reset(); - } - else - { - mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, - mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP); - } - - // We may have data ready regardless of whether or not we are finished (e.g. waiting on write) - if (mRawImage.notNull()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - has raw image"); - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); - if (tester) - { - mIsFetched = true; - tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)); - } - mRawDiscardLevel = fetch_discard; - if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) && - (current_discard < 0 || mRawDiscardLevel < current_discard)) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - data good"); - mFullWidth = mRawImage->getWidth() << mRawDiscardLevel; - mFullHeight = mRawImage->getHeight() << mRawDiscardLevel; - setTexelsPerImage(); - - if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE) - { - //discard all oversized textures. - destroyRawImage(); - LL_WARNS() << "oversize, setting as missing" << LL_ENDL; - setIsMissingAsset(); - mRawDiscardLevel = INVALID_DISCARD_LEVEL; - mIsFetching = false; - mLastPacketTimer.reset(); - } - else - { - mIsRawImageValid = true; - addToCreateTexture(); - } - - if (mBoostLevel == LLGLTexture::BOOST_ICON) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; - if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) - { - // scale oversized icon, no need to give more work to gl - // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy - mRawImage = mRawImage->scaled(expected_width, expected_height); - } - } - - if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; - if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) - { - // scale oversized icon, no need to give more work to gl - // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy - mRawImage = mRawImage->scaled(expected_width, expected_height); - } - } - - return true; - } - else - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - data not needed"); - // Data is ready but we don't need it - // (received it already while fetcher was writing to disk) - destroyRawImage(); - return false; // done - } - } - - if (!mIsFetching) - { - if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL)) - { - // We finished but received no data - if (getDiscardLevel() < 0) - { - if (getFTType() != FTT_MAP_TILE) - { - LL_WARNS() << mID - << " Fetch failure, setting as missing, decode_priority " << decode_priority - << " mRawDiscardLevel " << mRawDiscardLevel - << " current_discard " << current_discard - << " stats " << mLastHttpGetStatus.toHex() - << LL_ENDL; - } - setIsMissingAsset(); - desired_discard = -1; - } - else - { - //LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL; - if(current_discard >= 0) - { - mMinDiscardLevel = current_discard; - //desired_discard = current_discard; - } - else - { - S32 dis_level = getDiscardLevel(); - mMinDiscardLevel = dis_level; - //desired_discard = dis_level; - } - } - destroyRawImage(); - } - else if (mRawImage.notNull()) - { - // We have data, but our fetch failed to return raw data - // *TODO: FIgure out why this is happening and fix it - destroyRawImage(); - } - } - else - { - static const F32 MAX_HOLD_TIME = 5.0f; //seconds to wait before canceling fecthing if decode_priority is 0.f. - if(decode_priority > 0.0f || mStopFetchingTimer.getElapsedTimeF32() > MAX_HOLD_TIME) - { - mStopFetchingTimer.reset(); - LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority); - } - } - } - - desired_discard = llmin(desired_discard, getMaxDiscardLevel()); - - bool make_request = true; - if (decode_priority <= 0) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - priority <= 0"); - make_request = false; - } - else if(mDesiredDiscardLevel > getMaxDiscardLevel()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - desired > max"); - make_request = false; - } - else if (mNeedsCreateTexture || mIsMissingAsset) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - create or missing"); - make_request = false; - } - else if (current_discard >= 0 && current_discard <= mMinDiscardLevel) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - current < min"); - make_request = false; - } - else if(mCachedRawImage.notNull() // can be empty - && mCachedRawImageReady - && (current_discard < 0 || current_discard > mCachedRawDiscardLevel)) - { - make_request = false; - switchToCachedImage(); //use the cached raw data first - } - - if (make_request) - { - if (mIsFetching) - { - // already requested a higher resolution mip - if (mRequestedDiscardLevel <= desired_discard) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - requested < desired"); - make_request = false; - } - } - else - { - // already at a higher resolution mip, don't discard - if (current_discard >= 0 && current_discard <= desired_discard) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - current <= desired"); - make_request = false; - } - } - } - - if (make_request) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - make request"); - S32 w=0, h=0, c=0; - if (getDiscardLevel() >= 0) - { - w = mGLTexturep->getWidth(0); - h = mGLTexturep->getHeight(0); - c = mComponents; - } - - const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); - if (override_tex_discard_level != 0) - { - desired_discard = override_tex_discard_level; - } - - // bypass texturefetch directly by pulling from LLTextureCache - S32 fetch_request_discard = -1; - fetch_request_discard = LLAppViewer::getTextureFetch()->createRequest(mFTType, mUrl, getID(), getTargetHost(), decode_priority, - w, h, c, desired_discard, needsAux(), mCanUseHTTP); - - if (fetch_request_discard >= 0) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - request created"); - mHasFetcher = true; - mIsFetching = true; - // in some cases createRequest can modify discard, as an example - // bake textures are always at discard 0 - mRequestedDiscardLevel = llmin(desired_discard, fetch_request_discard); - mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, - mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP); - } - - // If createRequest() failed, that means one of two things: - // 1. We're finishing up a request for this UUID, so we - // should wait for it to complete - // 2. We've failed a request for this UUID, so there is - // no need to create another request - } - else if (mHasFetcher && !mIsFetching) - { - // Only delete requests that haven't received any network data - // for a while. Note - this is the normal mechanism for - // deleting requests, not just a place to handle timeouts. - const F32 FETCH_IDLE_TIME = 0.1f; - if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME) - { - LL_DEBUGS("Texture") << "exceeded idle time " << FETCH_IDLE_TIME << ", deleting request: " << getID() << LL_ENDL; - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = false; - } - } - - return mIsFetching; -} - -void LLViewerFetchedTexture::clearFetchedResults() -{ - if(mNeedsCreateTexture || mIsFetching) - { - return; - } - - cleanup(); - destroyGLTexture(); - - if(getDiscardLevel() >= 0) //sculpty texture, force to invalidate - { - mGLTexturep->forceToInvalidateGLTexture(); - } -} - -void LLViewerFetchedTexture::forceToDeleteRequest() -{ - if (mHasFetcher) - { - mHasFetcher = false; - mIsFetching = false; - } - - resetTextureStats(); - - mDesiredDiscardLevel = getMaxDiscardLevel() + 1; -} - -void LLViewerFetchedTexture::setIsMissingAsset(bool is_missing) -{ - if (is_missing == mIsMissingAsset) - { - return; - } - if (is_missing) - { - if (mUrl.empty()) - { - LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; - } - else - { - // This may or may not be an error - it is normal to have no - // map tile on an empty region, but bad if we're failing on a - // server bake texture. - if (getFTType() != FTT_MAP_TILE) - { - LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; - } - } - if (mHasFetcher) - { - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = false; - mIsFetching = false; - mLastPacketTimer.reset(); - mFetchState = 0; - mFetchPriority = 0; - } - } - else - { - LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL; - } - mIsMissingAsset = is_missing; -} - -void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, - S32 discard_level, bool keep_imageraw, bool needs_aux, void* userdata, - LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, bool pause) -{ - // - // Don't do ANYTHING here, just add it to the global callback list - // - if (mLoadedCallbackList.empty()) - { - // Put in list to call this->doLoadedCallbacks() periodically - gTextureList.mCallbackList.insert(this); - mLoadedCallbackDesiredDiscardLevel = (S8)discard_level; - } - else - { - mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level); - } - - if(mPauseLoadedCallBacks) - { - if(!pause) - { - unpauseLoadedCallbacks(src_callback_list); - } - } - else if(pause) - { - pauseLoadedCallbacks(src_callback_list); - } - - LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata, src_callback_list, this, pause); - mLoadedCallbackList.push_back(entryp); - - mNeedsAux |= needs_aux; - if(keep_imageraw) - { - mSaveRawImage = true; - } - if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) - { - if(mHasAux) - { - //trigger a refetch - forceToRefetchTexture(); - } - else - { - // We need aux data, but we've already loaded the image, and it didn't have any - LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; - } - } - mLastCallBackActiveTime = sCurrentTime ; - mLastReferencedSavedRawImageTime = sCurrentTime; -} - -void LLViewerFetchedTexture::clearCallbackEntryList() -{ - if(mLoadedCallbackList.empty()) - { - return; - } - - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter; - - // We never finished loading the image. Indicate failure. - // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); - iter = mLoadedCallbackList.erase(iter); - delete entryp; - } - gTextureList.mCallbackList.erase(this); - - mLoadedCallbackDesiredDiscardLevel = S8_MAX; - if(needsToSaveRawImage()) - { - destroySavedRawImage(); - } - - return; -} - -void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) -{ - if(mLoadedCallbackList.empty() || !callback_list) - { - return; - } - - S32 desired_discard = S8_MAX; - S32 desired_raw_discard = INVALID_DISCARD_LEVEL; - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter; - if(entryp->mSourceCallbackList == callback_list) - { - // We never finished loading the image. Indicate failure. - // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); - iter = mLoadedCallbackList.erase(iter); - delete entryp; - } - else - { - ++iter; - - desired_discard = llmin(desired_discard, entryp->mDesiredDiscard); - if(entryp->mNeedsImageRaw) - { - desired_raw_discard = llmin(desired_raw_discard, entryp->mDesiredDiscard); - } - } - } - - mLoadedCallbackDesiredDiscardLevel = desired_discard; - if (mLoadedCallbackList.empty()) - { - // If we have no callbacks, take us off of the image callback list. - gTextureList.mCallbackList.erase(this); - - if(needsToSaveRawImage()) - { - destroySavedRawImage(); - } - } - else if(needsToSaveRawImage() && mBoostLevel != LLGLTexture::BOOST_PREVIEW) - { - if(desired_raw_discard != INVALID_DISCARD_LEVEL) - { - mDesiredSavedRawDiscardLevel = desired_raw_discard; - } - else - { - destroySavedRawImage(); - } - } -} - -void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) -{ - if(!callback_list) -{ - mPauseLoadedCallBacks = false; - return; - } - - bool need_raw = false; - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter++; - if(entryp->mSourceCallbackList == callback_list) - { - entryp->mPaused = false; - if(entryp->mNeedsImageRaw) - { - need_raw = true; - } - } - } - mPauseLoadedCallBacks = false ; - mLastCallBackActiveTime = sCurrentTime ; - mForceCallbackFetch = true; - if(need_raw) - { - mSaveRawImage = true; - } -} - -void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) -{ - if(!callback_list) -{ - return; - } - - bool paused = true; - - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter++; - if(entryp->mSourceCallbackList == callback_list) - { - entryp->mPaused = true; - } - else if(!entryp->mPaused) - { - paused = false; - } - } - - if(paused) - { - mPauseLoadedCallBacks = true;//when set, loaded callback is paused. - resetTextureStats(); - mSaveRawImage = false; - } -} - -bool LLViewerFetchedTexture::doLoadedCallbacks() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds - static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds - - if (mNeedsCreateTexture) - { - return false; - } - if(mPauseLoadedCallBacks) - { - destroyRawImage(); - return false; //paused - } - if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME && !mIsFetching) - { - if (mFTType == FTT_SERVER_BAKE) - { - //output some debug info - LL_INFOS() << "baked texture: " << mID << "clears all call backs due to inactivity." << LL_ENDL; - LL_INFOS() << mUrl << LL_ENDL; - LL_INFOS() << "current discard: " << getDiscardLevel() << " current discard for fetch: " << getCurrentDiscardLevelForFetching() << - " Desired discard: " << getDesiredDiscardLevel() << "decode Pri: " << mMaxVirtualSize << LL_ENDL; - } - - clearCallbackEntryList() ; //remove all callbacks. - return false ; - } - - bool res = false; - - if (isMissingAsset()) - { - if (mFTType == FTT_SERVER_BAKE) - { - //output some debug info - LL_INFOS() << "baked texture: " << mID << "is missing." << LL_ENDL; - LL_INFOS() << mUrl << LL_ENDL; - } - - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter++; - // We never finished loading the image. Indicate failure. - // Note: this allows mLoadedCallbackUserData to be cleaned up. - entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); - delete entryp; - } - mLoadedCallbackList.clear(); - - // Remove ourself from the global list of textures with callbacks - gTextureList.mCallbackList.erase(this); - return false; - } - - S32 gl_discard = getDiscardLevel(); - - // If we don't have a legit GL image, set it to be lower than the worst discard level - if (gl_discard == -1) - { - gl_discard = MAX_DISCARD_LEVEL + 1; - } - - // - // Determine the quality levels of textures that we can provide to callbacks - // and whether we need to do decompression/readback to get it - // - S32 current_raw_discard = MAX_DISCARD_LEVEL + 1; // We can always do a readback to get a raw discard - S32 best_raw_discard = gl_discard; // Current GL quality level - S32 current_aux_discard = MAX_DISCARD_LEVEL + 1; - S32 best_aux_discard = MAX_DISCARD_LEVEL + 1; - - if (mIsRawImageValid) - { - // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels. - best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel); - best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw - current_aux_discard = llmin(current_aux_discard, best_aux_discard); - } - else - { - // We have no data at all, we need to get it - // Do this by forcing the best aux discard to be 0. - best_aux_discard = 0; - } - - - // - // See if any of the callbacks would actually run using the data that we can provide, - // and also determine if we need to perform any readbacks or decodes. - // - bool run_gl_callbacks = false; - bool run_raw_callbacks = false; - bool need_readback = false; - - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - LLLoadedCallbackEntry *entryp = *iter++; - - if (entryp->mNeedsImageRaw) - { - if (mNeedsAux) - { - // - // Need raw and auxiliary channels - // - if (entryp->mLastUsedDiscard > current_aux_discard) - { - // We have useful data, run the callbacks - run_raw_callbacks = true; - } - } - else - { - if (entryp->mLastUsedDiscard > current_raw_discard) - { - // We have useful data, just run the callbacks - run_raw_callbacks = true; - } - else if (entryp->mLastUsedDiscard > best_raw_discard) - { - // We can readback data, and then run the callbacks - need_readback = true; - run_raw_callbacks = true; - } - } - } - else - { - // Needs just GL - if (entryp->mLastUsedDiscard > gl_discard) - { - // We have enough data, run this callback requiring GL data - run_gl_callbacks = true; - } - } - } - - // - // Do a readback if required, OR start off a texture decode - // - if (need_readback && (getMaxDiscardLevel() > gl_discard)) - { - // Do a readback to get the GL data into the raw image - // We have GL data. - - destroyRawImage(); - reloadRawImage(mLoadedCallbackDesiredDiscardLevel); - llassert(mRawImage.notNull()); - llassert(!mNeedsAux || mAuxRawImage.notNull()); - } - - // - // Run raw/auxiliary data callbacks - // - if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel())) - { - // Do callbacks which require raw image data. - //LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL; - - // Call each party interested in the raw data. - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - LLLoadedCallbackEntry *entryp = *curiter; - if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel)) - { - // If we've loaded all the data there is to load or we've loaded enough - // to satisfy the interested party, then this is the last time that - // we're going to call them. - - mLastCallBackActiveTime = sCurrentTime; - if(mNeedsAux && mAuxRawImage.isNull()) - { - LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL; - } - bool final = mRawDiscardLevel <= entryp->mDesiredDiscard; - //LL_INFOS() << "Running callback for " << getID() << LL_ENDL; - //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL; - entryp->mLastUsedDiscard = mRawDiscardLevel; - entryp->mCallback(true, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); - if (final) - { - iter = mLoadedCallbackList.erase(curiter); - delete entryp; - } - res = true; - } - } - } - - // - // Run GL callbacks - // - if (run_gl_callbacks && (gl_discard <= getMaxDiscardLevel())) - { - //LL_INFOS() << "doLoadedCallbacks GL for " << getID() << LL_ENDL; - - // Call the callbacks interested in GL data. - for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); - iter != mLoadedCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - LLLoadedCallbackEntry *entryp = *curiter; - if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard)) - { - mLastCallBackActiveTime = sCurrentTime; - bool final = gl_discard <= entryp->mDesiredDiscard; - entryp->mLastUsedDiscard = gl_discard; - entryp->mCallback(true, this, NULL, NULL, gl_discard, final, entryp->mUserData); - if (final) - { - iter = mLoadedCallbackList.erase(curiter); - delete entryp; - } - res = true; - } - } - } - - // Done with any raw image data at this point (will be re-created if we still have callbacks) - destroyRawImage(); - - // - // If we have no callbacks, take us off of the image callback list. - // - if (mLoadedCallbackList.empty()) - { - gTextureList.mCallbackList.erase(this); - } - else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching) - { - //wait for long enough but no fetching request issued, force one. - forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); - mForceCallbackFetch = false; //fire once. - } - - return res; -} - -//virtual -void LLViewerFetchedTexture::forceImmediateUpdate() -{ - //only immediately update a deleted texture which is now being re-used. - if(!isDeleted()) - { - return; - } - //if already called forceImmediateUpdate() - if(mInImageList && mMaxVirtualSize == LLViewerFetchedTexture::sMaxVirtualSize) - { - return; - } - - gTextureList.forceImmediateUpdate(this); - return; -} - -LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) -{ - llassert(mGLTexturep.notNull()); - llassert(discard_level >= 0); - llassert(mComponents > 0); - - if (mRawImage.notNull()) - { - //mRawImage is in use by somebody else, do not delete it. - return NULL; - } - - if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level) - { - if (mSavedRawDiscardLevel != discard_level - && mBoostLevel != BOOST_ICON - && mBoostLevel != BOOST_THUMBNAIL) - { - mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); - mRawImage->copy(getSavedRawImage()); - } - else - { - mRawImage = getSavedRawImage(); - } - mRawDiscardLevel = discard_level; - } - else - { - //force to fetch raw image again if cached raw image is not good enough. - if(mCachedRawDiscardLevel > discard_level) - { - mRawImage = mCachedRawImage; - mRawDiscardLevel = mCachedRawDiscardLevel; - } - else //cached raw image is good enough, copy it. - { - if(mCachedRawDiscardLevel != discard_level) - { - mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); - mRawImage->copy(mCachedRawImage); - } - else - { - mRawImage = mCachedRawImage; - } - mRawDiscardLevel = discard_level; - } - } - mIsRawImageValid = true; - sRawCount++; - - return mRawImage; -} - -bool LLViewerFetchedTexture::needsToSaveRawImage() -{ - return mForceToSaveRawImage || mSaveRawImage; -} - -void LLViewerFetchedTexture::destroyRawImage() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (mAuxRawImage.notNull() && !needsToSaveRawImage()) - { - sAuxCount--; - mAuxRawImage = NULL; - } - - if (mRawImage.notNull()) - { - sRawCount--; - - if(mIsRawImageValid) - { - if(needsToSaveRawImage()) - { - saveRawImage(); - } - setCachedRawImage(); - } - - mRawImage = NULL; - - mIsRawImageValid = false; - mRawDiscardLevel = INVALID_DISCARD_LEVEL; - } -} - -//use the mCachedRawImage to (re)generate the gl texture. -//virtual -void LLViewerFetchedTexture::switchToCachedImage() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mCachedRawImage.notNull() && - !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it - { - mRawImage = mCachedRawImage; - - if (getComponents() != mRawImage->getComponents()) - { - // We've changed the number of components, so we need to move any - // objects using this pool to a different pool. - mComponents = mRawImage->getComponents(); - mGLTexturep->setComponents(mComponents); - gTextureList.dirtyImage(this); - } - - mIsRawImageValid = true; - mRawDiscardLevel = mCachedRawDiscardLevel; - - scheduleCreateTexture(); - } -} - -//cache the imageraw forcefully. -//virtual -void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) -{ - if(imageraw != mRawImage.get()) - { - if (mBoostLevel == LLGLTexture::BOOST_ICON) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) - { - mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); - mCachedRawImage->copyScaled(imageraw); - } - else - { - mCachedRawImage = imageraw; - } - } - else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) - { - mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); - mCachedRawImage->copyScaled(imageraw); - } - else - { - mCachedRawImage = imageraw; - } - } - else - { - mCachedRawImage = imageraw; - } - mCachedRawDiscardLevel = discard_level; - mCachedRawImageReady = true; - } -} - -void LLViewerFetchedTexture::setCachedRawImage() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mRawImage == mCachedRawImage) - { - return; - } - if(!mIsRawImageValid) - { - return; - } - - if(mCachedRawImageReady) - { - return; - } - - if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel) - { - S32 i = 0; - S32 w = mRawImage->getWidth(); - S32 h = mRawImage->getHeight(); - - S32 max_size = MAX_CACHED_RAW_IMAGE_AREA; - if(LLGLTexture::BOOST_TERRAIN == mBoostLevel) - { - max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA; - } - if(mForSculpt) - { - max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA; - mCachedRawImageReady = !mRawDiscardLevel; - } - else - { - mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)); - } - - while(((w >> i) * (h >> i)) > max_size) - { - ++i; - } - - if(i) - { - if(!(w >> i) || !(h >> i)) - { - --i; - } - - { - //make a duplicate in case somebody else is using this raw image - mRawImage = mRawImage->scaled(w >> i, h >> i); - } - } - mCachedRawImage = mRawImage; - mRawDiscardLevel += i; - mCachedRawDiscardLevel = mRawDiscardLevel; - } -} - -void LLViewerFetchedTexture::checkCachedRawSculptImage() -{ - if(mCachedRawImageReady && mCachedRawDiscardLevel > 0) - { - if(getDiscardLevel() != 0) - { - mCachedRawImageReady = false; - } - else if(isForSculptOnly()) - { - resetTextureStats(); //do not update this image any more. - } - } -} - -void LLViewerFetchedTexture::saveRawImage() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(mRawImage.isNull() || mRawImage == mSavedRawImage || (mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= mRawDiscardLevel)) - { - return; - } - - LLImageDataSharedLock lock(mRawImage); - - mSavedRawDiscardLevel = mRawDiscardLevel; - if (mBoostLevel == LLGLTexture::BOOST_ICON) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) - { - mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); - mSavedRawImage->copyScaled(mRawImage); - } - else - { - mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); - } - } - else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) - { - S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; - S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; - if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) - { - mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); - mSavedRawImage->copyScaled(mRawImage); - } - else - { - mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); - } - } - else - { - mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); - } - - if(mForceToSaveRawImage && mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel) - { - mForceToSaveRawImage = false; - } - - mLastReferencedSavedRawImageTime = sCurrentTime; -} - -//force to refetch the texture to the discard level -void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time) -{ - if(mForceToSaveRawImage) - { - desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel); - kept_time = llmax(kept_time, mKeptSavedRawImageTime); - } - - //trigger a new fetch. - mForceToSaveRawImage = true ; - mDesiredSavedRawDiscardLevel = desired_discard ; - mKeptSavedRawImageTime = kept_time ; - mLastReferencedSavedRawImageTime = sCurrentTime ; - mSavedRawImage = NULL ; - mSavedRawDiscardLevel = -1 ; -} - -void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time) -{ - mKeptSavedRawImageTime = kept_time; - mLastReferencedSavedRawImageTime = sCurrentTime; - - if(mSavedRawDiscardLevel > -1 && mSavedRawDiscardLevel <= desired_discard) - { - return; //raw imge is ready. - } - - if(!mForceToSaveRawImage || mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard) - { - mForceToSaveRawImage = true; - mDesiredSavedRawDiscardLevel = desired_discard; - - //copy from the cached raw image if exists. - if(mCachedRawImage.notNull() && mRawImage.isNull() ) - { - mRawImage = mCachedRawImage; - mRawDiscardLevel = mCachedRawDiscardLevel; - - saveRawImage(); - - mRawImage = NULL; - mRawDiscardLevel = INVALID_DISCARD_LEVEL; - } - } -} -void LLViewerFetchedTexture::destroySavedRawImage() -{ - if(mLastReferencedSavedRawImageTime < mKeptSavedRawImageTime) - { - return; //keep the saved raw image. - } - - mForceToSaveRawImage = false; - mSaveRawImage = false; - - clearCallbackEntryList(); - - mSavedRawImage = NULL ; - mForceToSaveRawImage = false ; - mSaveRawImage = false ; - mSavedRawDiscardLevel = -1 ; - mDesiredSavedRawDiscardLevel = -1 ; - mLastReferencedSavedRawImageTime = 0.0f ; - mKeptSavedRawImageTime = 0.f ; - - if(mAuxRawImage.notNull()) - { - sAuxCount--; - mAuxRawImage = NULL; - } -} - -LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() -{ - mLastReferencedSavedRawImageTime = sCurrentTime; - - return mSavedRawImage; -} - -bool LLViewerFetchedTexture::hasSavedRawImage() const -{ - return mSavedRawImage.notNull(); -} - -F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const -{ - return sCurrentTime - mLastReferencedSavedRawImageTime; -} - -//---------------------------------------------------------------------------------------------- -//end of LLViewerFetchedTexture -//---------------------------------------------------------------------------------------------- - -//---------------------------------------------------------------------------------------------- -//start of LLViewerLODTexture -//---------------------------------------------------------------------------------------------- -LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host, bool usemipmaps) - : LLViewerFetchedTexture(id, f_type, host, usemipmaps) -{ - init(true); -} - -LLViewerLODTexture::LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps) - : LLViewerFetchedTexture(url, f_type, id, usemipmaps) -{ - init(true); -} - -void LLViewerLODTexture::init(bool firstinit) -{ - mTexelsPerImage = 64.f*64.f; - mDiscardVirtualSize = 0.f; - mCalculatedDiscardLevel = -1.f; -} - -//virtual -S8 LLViewerLODTexture::getType() const -{ - return LLViewerTexture::LOD_TEXTURE; -} - -bool LLViewerLODTexture::isUpdateFrozen() -{ - return LLViewerTexture::sFreezeImageUpdates; -} - -// This is gauranteed to get called periodically for every texture -//virtual -void LLViewerLODTexture::processTextureStats() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - updateVirtualSize(); - - static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); - - if (textures_fullres) - { - mDesiredDiscardLevel = 0; - } - // Generate the request priority and render priority - else if (mDontDiscard || !mUseMipMaps) - { - mDesiredDiscardLevel = 0; - if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) - mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 - } - else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) - { - // If the image has not been significantly visible in a while, we don't want it - mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1)); - } - else if (!mFullWidth || !mFullHeight) - { - mDesiredDiscardLevel = getMaxDiscardLevel(); - } - else - { - //static const F64 log_2 = log(2.0); - static const F64 log_4 = log(4.0); - - F32 discard_level = 0.f; - - // If we know the output width and height, we can force the discard - // level to the correct value, and thus not decode more texture - // data than we need to. - if (mKnownDrawWidth && mKnownDrawHeight) - { - S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight; - draw_texels = llclamp(draw_texels, MIN_IMAGE_AREA, MAX_IMAGE_AREA); - - // Use log_4 because we're in square-pixel space, so an image - // with twice the width and twice the height will have mTexelsPerImage - // 4 * draw_size - discard_level = (F32)(log(mTexelsPerImage / draw_texels) / log_4); - } - else - { - // Calculate the required scale factor of the image using pixels per texel - discard_level = (F32)(log(mTexelsPerImage / mMaxVirtualSize) / log_4); - mDiscardVirtualSize = mMaxVirtualSize; - mCalculatedDiscardLevel = discard_level; - } - if (mBoostLevel < LLGLTexture::BOOST_SCULPTED) - { - discard_level *= sDesiredDiscardScale; // scale (default 1.1f) - } - discard_level = floorf(discard_level); - - F32 min_discard = 0.f; - U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 - if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED) - { - desired_size = DESIRED_NORMAL_TEXTURE_SIZE; - } - if (mFullWidth > desired_size || mFullHeight > desired_size) - min_discard = 1.f; - - discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL); - - // Can't go higher than the max discard level - mDesiredDiscardLevel = llmin(getMaxDiscardLevel() + 1, (S32)discard_level); - // Clamp to min desired discard - mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel); - - // - // At this point we've calculated the quality level that we want, - // if possible. Now we check to see if we have it, and take the - // proper action if we don't. - // - - S32 current_discard = getDiscardLevel(); - if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED && - current_discard >= 0) - { - if (current_discard < (mDesiredDiscardLevel-1) && !mForceToSaveRawImage) - { // should scale down - scaleDown(); - } - } - - if (isUpdateFrozen() // we are out of memory and nearing max allowed bias - && mBoostLevel < LLGLTexture::BOOST_SCULPTED - && mDesiredDiscardLevel < current_discard) - { - // stop requesting more - mDesiredDiscardLevel = current_discard; - } - } - - if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) - { - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); - } - - // decay max virtual size over time - mMaxVirtualSize *= 0.8f; - - // selection manager will immediately reset BOOST_SELECTED but never unsets it - // unset it immediately after we consume it - if (getBoostLevel() == BOOST_SELECTED) - { - setBoostLevel(BOOST_NONE); - } -} - -bool LLViewerLODTexture::scaleDown() -{ - if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel()) - { - switchToCachedImage(); - - LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); - if (tester) - { - tester->setStablizingTime(); - } - - return true; - } - return false; -} -//---------------------------------------------------------------------------------------------- -//end of LLViewerLODTexture -//---------------------------------------------------------------------------------------------- - -//---------------------------------------------------------------------------------------------- -//start of LLViewerMediaTexture -//---------------------------------------------------------------------------------------------- -//static -void LLViewerMediaTexture::updateClass() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - static const F32 MAX_INACTIVE_TIME = 30.f; - -#if 0 - //force to play media. - gSavedSettings.setBOOL("AudioStreamingMedia", true); -#endif - - for(media_map_t::iterator iter = sMediaMap.begin(); iter != sMediaMap.end(); ) - { - LLViewerMediaTexture* mediap = iter->second; - - if(mediap->getNumRefs() == 1) //one reference by sMediaMap - { - // - //Note: delay some time to delete the media textures to stop endlessly creating and immediately removing media texture. - // - if(mediap->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) - { - media_map_t::iterator cur = iter++; - sMediaMap.erase(cur); - continue; - } - } - ++iter; - } -} - -//static -void LLViewerMediaTexture::removeMediaImplFromTexture(const LLUUID& media_id) -{ - LLViewerMediaTexture* media_tex = findMediaTexture(media_id); - if(media_tex) - { - media_tex->invalidateMediaImpl(); - } -} - -//static -void LLViewerMediaTexture::cleanUpClass() -{ - sMediaMap.clear(); -} - -//static -LLViewerMediaTexture* LLViewerMediaTexture::findMediaTexture(const LLUUID& media_id) -{ - media_map_t::iterator iter = sMediaMap.find(media_id); - if(iter == sMediaMap.end()) - { - return NULL; - } - - LLViewerMediaTexture* media_tex = iter->second; - media_tex->setMediaImpl(); - media_tex->getLastReferencedTimer()->reset(); - - return media_tex; -} - -LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, bool usemipmaps, LLImageGL* gl_image) - : LLViewerTexture(id, usemipmaps), - mMediaImplp(NULL), - mUpdateVirtualSizeTime(0) -{ - sMediaMap.insert(std::make_pair(id, this)); - - mGLTexturep = gl_image; - - if(mGLTexturep.isNull()) - { - generateGLTexture(); - } - - mGLTexturep->setAllowCompression(false); - - mGLTexturep->setNeedsAlphaAndPickMask(false); - - mIsPlaying = false; - - setMediaImpl(); - - setCategory(LLGLTexture::MEDIA); - - LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); - if(tex) //this media is a parcel media for tex. - { - tex->setParcelMedia(this); - } -} - -//virtual -LLViewerMediaTexture::~LLViewerMediaTexture() -{ - LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); - if(tex) //this media is a parcel media for tex. - { - tex->setParcelMedia(NULL); - } -} - -void LLViewerMediaTexture::reinit(bool usemipmaps /* = true */) -{ - llassert(mGLTexturep.notNull()); - - mUseMipMaps = usemipmaps; - getLastReferencedTimer()->reset(); - mGLTexturep->setUseMipMaps(mUseMipMaps); - mGLTexturep->setNeedsAlphaAndPickMask(false); -} - -void LLViewerMediaTexture::setUseMipMaps(bool mipmap) -{ - mUseMipMaps = mipmap; - - if(mGLTexturep.notNull()) - { - mGLTexturep->setUseMipMaps(mipmap); - } -} - -//virtual -S8 LLViewerMediaTexture::getType() const -{ - return LLViewerTexture::MEDIA_TEXTURE; -} - -void LLViewerMediaTexture::invalidateMediaImpl() -{ - mMediaImplp = NULL; -} - -void LLViewerMediaTexture::setMediaImpl() -{ - if(!mMediaImplp) - { - mMediaImplp = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mID); - } -} - -//return true if all faces to reference to this media texture are found -//Note: mMediaFaceList is valid only for the current instant -// because it does not check the face validity after the current frame. -bool LLViewerMediaTexture::findFaces() -{ - mMediaFaceList.clear(); - - bool ret = true; - - LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); - if(tex) //this media is a parcel media for tex. - { - for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) - { - const ll_face_list_t* face_list = tex->getFaceList(ch); - U32 end = tex->getNumFaces(ch); - for(U32 i = 0; i < end; i++) - { - if ((*face_list)[i]->isMediaAllowed()) - { - mMediaFaceList.push_back((*face_list)[i]); - } - } - } - } - - if(!mMediaImplp) - { - return true; - } - - //for media on a face. - const std::list< LLVOVolume* >* obj_list = mMediaImplp->getObjectList(); - std::list< LLVOVolume* >::const_iterator iter = obj_list->begin(); - for(; iter != obj_list->end(); ++iter) - { - LLVOVolume* obj = *iter; - if (obj->isDead()) - { - // Isn't supposed to happen, objects are supposed to detach - // themselves on markDead() - // If this happens, viewer is likely to crash - llassert(0); - LL_WARNS() << "Dead object in mMediaImplp's object list" << LL_ENDL; - ret = false; - continue; - } - - if (obj->mDrawable.isNull() || obj->mDrawable->isDead()) - { - ret = false; - continue; - } - - S32 face_id = -1; - S32 num_faces = obj->mDrawable->getNumFaces(); - while((face_id = obj->getFaceIndexWithMediaImpl(mMediaImplp, face_id)) > -1 && face_id < num_faces) - { - LLFace* facep = obj->mDrawable->getFace(face_id); - if(facep) - { - mMediaFaceList.push_back(facep); - } - else - { - ret = false; - } - } - } - - return ret; -} - -void LLViewerMediaTexture::initVirtualSize() -{ - if(mIsPlaying) - { - return; - } - - findFaces(); - for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) - { - addTextureStats((*iter)->getVirtualSize()); - } -} - -void LLViewerMediaTexture::addMediaToFace(LLFace* facep) -{ - if(facep) - { - facep->setHasMedia(true); - } - if(!mIsPlaying) - { - return; //no need to add the face because the media is not in playing. - } - - switchTexture(LLRender::DIFFUSE_MAP, facep); -} - -void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) -{ - if(!facep) - { - return; - } - facep->setHasMedia(false); - - if(!mIsPlaying) - { - return; //no need to remove the face because the media is not in playing. - } - - mIsPlaying = false; //set to remove the media from the face. - switchTexture(LLRender::DIFFUSE_MAP, facep); - mIsPlaying = true; //set the flag back. - - if(getTotalNumFaces() < 1) //no face referencing to this media - { - stopPlaying(); - } -} - -//virtual -void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) -{ - LLViewerTexture::addFace(ch, facep); - - const LLTextureEntry* te = facep->getTextureEntry(); - if(te && te->getID().notNull()) - { - LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); - if(tex) - { - mTextureList.push_back(tex);//increase the reference number by one for tex to avoid deleting it. - return; - } - } - - //check if it is a parcel media - if(facep->getTexture() && facep->getTexture() != this && facep->getTexture()->getID() == mID) - { - mTextureList.push_back(facep->getTexture()); //a parcel media. - return; - } - - if(te && te->getID().notNull()) //should have a texture - { - LL_WARNS_ONCE() << "The face's texture " << te->getID() << " is not valid. Face must have a valid texture before media texture." << LL_ENDL; - // This might break the object, but it likely isn't a 'recoverable' situation. - LLViewerFetchedTexture* tex = LLViewerTextureManager::getFetchedTexture(te->getID()); - mTextureList.push_back(tex); - } -} - -//virtual -void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) -{ - LLViewerTexture::removeFace(ch, facep); - - const LLTextureEntry* te = facep->getTextureEntry(); - if(te && te->getID().notNull()) - { - LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); - if(tex) - { - for(std::list< LLPointer >::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter) - { - if(*iter == tex) - { - mTextureList.erase(iter); //decrease the reference number for tex by one. - return; - } - } - - std::vector te_list; - - for (U32 ch = 0; ch < 3; ++ch) - { - // - //we have some trouble here: the texture of the face is changed. - //we need to find the former texture, and remove it from the list to avoid memory leaking. - - llassert(mNumFaces[ch] <= mFaceList[ch].size()); - - for(U32 j = 0; j < mNumFaces[ch]; j++) - { - te_list.push_back(mFaceList[ch][j]->getTextureEntry());//all textures are in use. - } - } - - if (te_list.empty()) - { - mTextureList.clear(); - return; - } - - S32 end = te_list.size(); - - for(std::list< LLPointer >::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter) - { - S32 i = 0; - - for(i = 0; i < end; i++) - { - if(te_list[i] && te_list[i]->getID() == (*iter)->getID())//the texture is in use. - { - te_list[i] = NULL; - break; - } - } - if(i == end) //no hit for this texture, remove it. - { - mTextureList.erase(iter); //decrease the reference number for tex by one. - return; - } - } - } - } - - //check if it is a parcel media - for(std::list< LLPointer >::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter) - { - if((*iter)->getID() == mID) - { - mTextureList.erase(iter); //decrease the reference number for tex by one. - return; - } - } - - if(te && te->getID().notNull()) //should have a texture but none found - { - LL_ERRS() << "mTextureList texture reference number is corrupted. Texture id: " << te->getID() << " List size: " << (U32)mTextureList.size() << LL_ENDL; - } -} - -void LLViewerMediaTexture::stopPlaying() -{ - // Don't stop the media impl playing here -- this breaks non-inworld media (login screen, search, and media browser). -// if(mMediaImplp) -// { -// mMediaImplp->stop(); -// } - mIsPlaying = false; -} - -void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep) -{ - if(facep) - { - //check if another media is playing on this face. - if(facep->getTexture() && facep->getTexture() != this - && facep->getTexture()->getType() == LLViewerTexture::MEDIA_TEXTURE) - { - if(mID == facep->getTexture()->getID()) //this is a parcel media - { - return; //let the prim media win. - } - } - - if(mIsPlaying) //old textures switch to the media texture - { - facep->switchTexture(ch, this); - } - else //switch to old textures. - { - const LLTextureEntry* te = facep->getTextureEntry(); - if(te) - { - LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; - if(!tex && te->getID() != mID)//try parcel media. - { - tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); - } - if(!tex) - { - tex = LLViewerFetchedTexture::sDefaultImagep; - } - facep->switchTexture(ch, tex); - } - } - } -} - -void LLViewerMediaTexture::setPlaying(bool playing) -{ - if(!mMediaImplp) - { - return; - } - if(!playing && !mIsPlaying) - { - return; //media is already off - } - - if(playing == mIsPlaying && !mMediaImplp->isUpdated()) - { - return; //nothing has changed since last time. - } - - mIsPlaying = playing; - if(mIsPlaying) //is about to play this media - { - if(findFaces()) - { - //about to update all faces. - mMediaImplp->setUpdated(false); - } - - if(mMediaFaceList.empty())//no face pointing to this media - { - stopPlaying(); - return; - } - - for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) - { - switchTexture(LLRender::DIFFUSE_MAP, *iter); - } - } - else //stop playing this media - { - U32 ch = LLRender::DIFFUSE_MAP; - - llassert(mNumFaces[ch] <= mFaceList[ch].size()); - for(U32 i = mNumFaces[ch]; i; i--) - { - switchTexture(ch, mFaceList[ch][i - 1]); //current face could be removed in this function. - } - } - return; -} - -//virtual -F32 LLViewerMediaTexture::getMaxVirtualSize() -{ - if(LLFrameTimer::getFrameCount() == mUpdateVirtualSizeTime) - { - return mMaxVirtualSize; - } - mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount(); - - if(!mMaxVirtualSizeResetCounter) - { - addTextureStats(0.f, false);//reset - } - - if(mIsPlaying) //media is playing - { - for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) - { - llassert(mNumFaces[ch] <= mFaceList[ch].size()); - for(U32 i = 0; i < mNumFaces[ch]; i++) - { - LLFace* facep = mFaceList[ch][i]; - if(facep->getDrawable()->isRecentlyVisible()) - { - addTextureStats(facep->getVirtualSize()); - } - } - } - } - else //media is not in playing - { - findFaces(); - - if(!mMediaFaceList.empty()) - { - for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) - { - LLFace* facep = *iter; - if(facep->getDrawable()->isRecentlyVisible()) - { - addTextureStats(facep->getVirtualSize()); - } - } - } - } - - if(mMaxVirtualSizeResetCounter > 0) - { - mMaxVirtualSizeResetCounter--; - } - reorganizeFaceList(); - reorganizeVolumeList(); - - return mMaxVirtualSize; -} -//---------------------------------------------------------------------------------------------- -//end of LLViewerMediaTexture -//---------------------------------------------------------------------------------------------- - -//---------------------------------------------------------------------------------------------- -//start of LLTexturePipelineTester -//---------------------------------------------------------------------------------------------- -LLTexturePipelineTester::LLTexturePipelineTester() : LLMetricPerformanceTesterWithSession(sTesterName) -{ - addMetric("TotalBytesLoaded"); - addMetric("TotalBytesLoadedFromCache"); - addMetric("TotalBytesLoadedForLargeImage"); - addMetric("TotalBytesLoadedForSculpties"); - addMetric("StartFetchingTime"); - addMetric("TotalGrayTime"); - addMetric("TotalStablizingTime"); - addMetric("StartTimeLoadingSculpties"); - addMetric("EndTimeLoadingSculpties"); - - addMetric("Time"); - addMetric("TotalBytesBound"); - addMetric("TotalBytesBoundForLargeImage"); - addMetric("PercentageBytesBound"); - - mTotalBytesLoaded = (S32Bytes)0; - mTotalBytesLoadedFromCache = (S32Bytes)0; - mTotalBytesLoadedForLargeImage = (S32Bytes)0; - mTotalBytesLoadedForSculpties = (S32Bytes)0; - - reset(); -} - -LLTexturePipelineTester::~LLTexturePipelineTester() -{ - LLViewerTextureManager::sTesterp = NULL; -} - -void LLTexturePipelineTester::update() -{ - mLastTotalBytesUsed = mTotalBytesUsed; - mLastTotalBytesUsedForLargeImage = mTotalBytesUsedForLargeImage; - mTotalBytesUsed = (S32Bytes)0; - mTotalBytesUsedForLargeImage = (S32Bytes)0; - - if(LLAppViewer::getTextureFetch()->getNumRequests() > 0) //fetching list is not empty - { - if(mPause) - { - //start a new fetching session - reset(); - mStartFetchingTime = LLImageGL::sLastFrameTime; - mPause = false; - } - - //update total gray time - if(mUsingDefaultTexture) - { - mUsingDefaultTexture = false; - mTotalGrayTime = LLImageGL::sLastFrameTime - mStartFetchingTime; - } - - //update the stablizing timer. - updateStablizingTime(); - - outputTestResults(); - } - else if(!mPause) - { - //stop the current fetching session - mPause = true; - outputTestResults(); - reset(); - } -} - -void LLTexturePipelineTester::reset() -{ - mPause = true; - - mUsingDefaultTexture = false; - mStartStablizingTime = 0.0f; - mEndStablizingTime = 0.0f; - - mTotalBytesUsed = (S32Bytes)0; - mTotalBytesUsedForLargeImage = (S32Bytes)0; - mLastTotalBytesUsed = (S32Bytes)0; - mLastTotalBytesUsedForLargeImage = (S32Bytes)0; - - mStartFetchingTime = 0.0f; - - mTotalGrayTime = 0.0f; - mTotalStablizingTime = 0.0f; - - mStartTimeLoadingSculpties = 1.0f; - mEndTimeLoadingSculpties = 0.0f; -} - -//virtual -void LLTexturePipelineTester::outputTestRecord(LLSD *sd) -{ - std::string currentLabel = getCurrentLabelName(); - (*sd)[currentLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded.value(); - (*sd)[currentLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache.value(); - (*sd)[currentLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage.value(); - (*sd)[currentLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties.value(); - - (*sd)[currentLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime; - (*sd)[currentLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime; - (*sd)[currentLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime; - - (*sd)[currentLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties; - (*sd)[currentLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties; - - (*sd)[currentLabel]["Time"] = LLImageGL::sLastFrameTime; - (*sd)[currentLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed.value(); - (*sd)[currentLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage.value(); - (*sd)[currentLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded); -} - -void LLTexturePipelineTester::updateTextureBindingStats(const LLViewerTexture* imagep) -{ - U32Bytes mem_size = imagep->getTextureMemory(); - mTotalBytesUsed += mem_size; - - if(MIN_LARGE_IMAGE_AREA <= (U32)(mem_size.value() / (U32)imagep->getComponents())) - { - mTotalBytesUsedForLargeImage += mem_size; - } -} - -void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, bool from_cache) -{ - U32Bytes data_size = (U32Bytes)raw_imagep->getDataSize(); - mTotalBytesLoaded += data_size; - - if(from_cache) - { - mTotalBytesLoadedFromCache += data_size; - } - - if(MIN_LARGE_IMAGE_AREA <= (U32)(data_size.value() / (U32)raw_imagep->getComponents())) - { - mTotalBytesLoadedForLargeImage += data_size; - } - - if(imagep->forSculpt()) - { - mTotalBytesLoadedForSculpties += data_size; - - if(mStartTimeLoadingSculpties > mEndTimeLoadingSculpties) - { - mStartTimeLoadingSculpties = LLImageGL::sLastFrameTime; - } - mEndTimeLoadingSculpties = LLImageGL::sLastFrameTime; - } -} - -void LLTexturePipelineTester::updateGrayTextureBinding() -{ - mUsingDefaultTexture = true; -} - -void LLTexturePipelineTester::setStablizingTime() -{ - if(mStartStablizingTime <= mStartFetchingTime) - { - mStartStablizingTime = LLImageGL::sLastFrameTime; - } - mEndStablizingTime = LLImageGL::sLastFrameTime; -} - -void LLTexturePipelineTester::updateStablizingTime() -{ - if(mStartStablizingTime > mStartFetchingTime) - { - F32 t = mEndStablizingTime - mStartStablizingTime; - - if(t > F_ALMOST_ZERO && (t - mTotalStablizingTime) < F_ALMOST_ZERO) - { - //already stablized - mTotalStablizingTime = LLImageGL::sLastFrameTime - mStartStablizingTime; - - //cancel the timer - mStartStablizingTime = 0.f; - mEndStablizingTime = 0.f; - } - else - { - mTotalStablizingTime = t; - } - } - mTotalStablizingTime = 0.f; -} - -//virtual -void LLTexturePipelineTester::compareTestSessions(llofstream* os) -{ - LLTexturePipelineTester::LLTextureTestSession* base_sessionp = dynamic_cast(mBaseSessionp); - LLTexturePipelineTester::LLTextureTestSession* current_sessionp = dynamic_cast(mCurrentSessionp); - if(!base_sessionp || !current_sessionp) - { - LL_ERRS() << "type of test session does not match!" << LL_ENDL; - } - - //compare and output the comparison - *os << llformat("%s\n", getTesterName().c_str()); - *os << llformat("AggregateResults\n"); - - compareTestResults(os, "TotalGrayTime", base_sessionp->mTotalGrayTime, current_sessionp->mTotalGrayTime); - compareTestResults(os, "TotalStablizingTime", base_sessionp->mTotalStablizingTime, current_sessionp->mTotalStablizingTime); - compareTestResults(os, "StartTimeLoadingSculpties", base_sessionp->mStartTimeLoadingSculpties, current_sessionp->mStartTimeLoadingSculpties); - compareTestResults(os, "TotalTimeLoadingSculpties", base_sessionp->mTotalTimeLoadingSculpties, current_sessionp->mTotalTimeLoadingSculpties); - - compareTestResults(os, "TotalBytesLoaded", base_sessionp->mTotalBytesLoaded, current_sessionp->mTotalBytesLoaded); - compareTestResults(os, "TotalBytesLoadedFromCache", base_sessionp->mTotalBytesLoadedFromCache, current_sessionp->mTotalBytesLoadedFromCache); - compareTestResults(os, "TotalBytesLoadedForLargeImage", base_sessionp->mTotalBytesLoadedForLargeImage, current_sessionp->mTotalBytesLoadedForLargeImage); - compareTestResults(os, "TotalBytesLoadedForSculpties", base_sessionp->mTotalBytesLoadedForSculpties, current_sessionp->mTotalBytesLoadedForSculpties); - - *os << llformat("InstantResults\n"); - S32 size = llmin(base_sessionp->mInstantPerformanceListCounter, current_sessionp->mInstantPerformanceListCounter); - for(S32 i = 0; i < size; i++) - { - *os << llformat("Time(B-T)-%.4f-%.4f\n", base_sessionp->mInstantPerformanceList[i].mTime, current_sessionp->mInstantPerformanceList[i].mTime); - - compareTestResults(os, "AverageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond, - current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); - - compareTestResults(os, "AverageBytesUsedForLargeImagePerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond, - current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); - - compareTestResults(os, "AveragePercentageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond, - current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); - } - - if(size < base_sessionp->mInstantPerformanceListCounter) - { - for(S32 i = size; i < base_sessionp->mInstantPerformanceListCounter; i++) - { - *os << llformat("Time(B-T)-%.4f- \n", base_sessionp->mInstantPerformanceList[i].mTime); - - *os << llformat(", AverageBytesUsedPerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); - *os << llformat(", AverageBytesUsedForLargeImagePerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); - *os << llformat(", AveragePercentageBytesUsedPerSecond, %.4f, N/A \n", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); - } - } - else if(size < current_sessionp->mInstantPerformanceListCounter) - { - for(S32 i = size; i < current_sessionp->mInstantPerformanceListCounter; i++) - { - *os << llformat("Time(B-T)- -%.4f\n", current_sessionp->mInstantPerformanceList[i].mTime); - - *os << llformat(", AverageBytesUsedPerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); - *os << llformat(", AverageBytesUsedForLargeImagePerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); - *os << llformat(", AveragePercentageBytesUsedPerSecond, N/A, %.4f\n", current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); - } - } -} - -//virtual -LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::loadTestSession(LLSD* log) -{ - LLTexturePipelineTester::LLTextureTestSession* sessionp = new LLTexturePipelineTester::LLTextureTestSession(); - if(!sessionp) - { - return NULL; - } - - F32 total_gray_time = 0.f; - F32 total_stablizing_time = 0.f; - F32 total_loading_sculpties_time = 0.f; - - F32 start_fetching_time = -1.f; - F32 start_fetching_sculpties_time = 0.f; - - F32 last_time = 0.0f; - S32 frame_count = 0; - - sessionp->mInstantPerformanceListCounter = 0; - sessionp->mInstantPerformanceList.resize(128); - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f; - - //load a session - std::string currentLabel = getCurrentLabelName(); - bool in_log = (*log).has(currentLabel); - while (in_log) - { - LLSD::String label = currentLabel; - - if(sessionp->mInstantPerformanceListCounter >= (S32)sessionp->mInstantPerformanceList.size()) - { - sessionp->mInstantPerformanceList.resize(sessionp->mInstantPerformanceListCounter + 128); - } - - //time - F32 start_time = (*log)[label]["StartFetchingTime"].asReal(); - F32 cur_time = (*log)[label]["Time"].asReal(); - if(start_time - start_fetching_time > F_ALMOST_ZERO) //fetching has paused for a while - { - sessionp->mTotalGrayTime += total_gray_time; - sessionp->mTotalStablizingTime += total_stablizing_time; - - sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time; - sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time; - - start_fetching_time = start_time; - total_gray_time = 0.f; - total_stablizing_time = 0.f; - total_loading_sculpties_time = 0.f; - } - else - { - total_gray_time = (*log)[label]["TotalGrayTime"].asReal(); - total_stablizing_time = (*log)[label]["TotalStablizingTime"].asReal(); - - total_loading_sculpties_time = (*log)[label]["EndTimeLoadingSculpties"].asReal() - (*log)[label]["StartTimeLoadingSculpties"].asReal(); - if(start_fetching_sculpties_time < 0.f && total_loading_sculpties_time > 0.f) - { - start_fetching_sculpties_time = (*log)[label]["StartTimeLoadingSculpties"].asReal(); - } - } - - //total loaded bytes - sessionp->mTotalBytesLoaded = (*log)[label]["TotalBytesLoaded"].asInteger(); - sessionp->mTotalBytesLoadedFromCache = (*log)[label]["TotalBytesLoadedFromCache"].asInteger(); - sessionp->mTotalBytesLoadedForLargeImage = (*log)[label]["TotalBytesLoadedForLargeImage"].asInteger(); - sessionp->mTotalBytesLoadedForSculpties = (*log)[label]["TotalBytesLoadedForSculpties"].asInteger(); - - //instant metrics - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond += - (*log)[label]["TotalBytesBound"].asInteger(); - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond += - (*log)[label]["TotalBytesBoundForLargeImage"].asInteger(); - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond += - (*log)[label]["PercentageBytesBound"].asReal(); - frame_count++; - if(cur_time - last_time >= 1.0f) - { - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond /= frame_count; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond /= frame_count; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond /= frame_count; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = last_time; - - frame_count = 0; - last_time = cur_time; - sessionp->mInstantPerformanceListCounter++; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f; - } - // Next label - incrementCurrentCount(); - currentLabel = getCurrentLabelName(); - in_log = (*log).has(currentLabel); - } - - sessionp->mTotalGrayTime += total_gray_time; - sessionp->mTotalStablizingTime += total_stablizing_time; - - if(sessionp->mStartTimeLoadingSculpties < 0.f) - { - sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time; - } - sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time; - - return sessionp; -} - -LLTexturePipelineTester::LLTextureTestSession::LLTextureTestSession() -{ - reset(); -} -LLTexturePipelineTester::LLTextureTestSession::~LLTextureTestSession() -{ -} -void LLTexturePipelineTester::LLTextureTestSession::reset() -{ - mTotalGrayTime = 0.0f; - mTotalStablizingTime = 0.0f; - - mStartTimeLoadingSculpties = 0.0f; - mTotalTimeLoadingSculpties = 0.0f; - - mTotalBytesLoaded = 0; - mTotalBytesLoadedFromCache = 0; - mTotalBytesLoadedForLargeImage = 0; - mTotalBytesLoadedForSculpties = 0; - - mInstantPerformanceListCounter = 0; -} -//---------------------------------------------------------------------------------------------- -//end of LLTexturePipelineTester -//---------------------------------------------------------------------------------------------- - + +/** + * @file llviewertexture.cpp + * @brief Object which handles a received image (and associated texture(s)) + * + * $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 "llviewerprecompiledheaders.h" + +#include "llviewertexture.h" + +// Library includes +#include "llmath.h" +#include "llerror.h" +#include "llgl.h" +#include "llglheaders.h" +#include "llhost.h" +#include "llimage.h" +#include "llimagebmp.h" +#include "llimagej2c.h" +#include "llimagetga.h" +#include "llstl.h" +#include "message.h" +#include "lltimer.h" + +// viewer includes +#include "llimagegl.h" +#include "lldrawpool.h" +#include "lltexturefetch.h" +#include "llviewertexturelist.h" +#include "llviewercontrol.h" +#include "pipeline.h" +#include "llappviewer.h" +#include "llface.h" +#include "llviewercamera.h" +#include "lltextureentry.h" +#include "lltexturemanagerbridge.h" +#include "llmediaentry.h" +#include "llvovolume.h" +#include "llviewermedia.h" +#include "lltexturecache.h" +#include "llviewerwindow.h" +#include "llwindow.h" +/////////////////////////////////////////////////////////////////////////////// + +// extern +const S32Megabytes gMinVideoRam(32); +const S32Megabytes gMaxVideoRam(512); + + +// statics +LLPointer LLViewerTexture::sNullImagep = NULL; +LLPointer LLViewerTexture::sBlackImagep = NULL; +LLPointer LLViewerTexture::sCheckerBoardImagep = NULL; +LLPointer LLViewerFetchedTexture::sMissingAssetImagep = NULL; +LLPointer LLViewerFetchedTexture::sWhiteImagep = NULL; +LLPointer LLViewerFetchedTexture::sDefaultImagep = NULL; +LLPointer LLViewerFetchedTexture::sSmokeImagep = NULL; +LLPointer LLViewerFetchedTexture::sFlatNormalImagep = NULL; +LLPointer LLViewerFetchedTexture::sDefaultIrradiancePBRp; +LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap; +LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL; +F32 LLViewerFetchedTexture::sMaxVirtualSize = 8192.f*8192.f; + +const std::string sTesterName("TextureTester"); + +S32 LLViewerTexture::sImageCount = 0; +S32 LLViewerTexture::sRawCount = 0; +S32 LLViewerTexture::sAuxCount = 0; +LLFrameTimer LLViewerTexture::sEvaluationTimer; +F32 LLViewerTexture::sDesiredDiscardBias = 0.f; +F32 LLViewerTexture::sDesiredDiscardScale = 1.1f; +S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size +const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64; +const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez; +const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128; +const S32 DEFAULT_ICON_DIMENSIONS = 32; +const S32 DEFAULT_THUMBNAIL_DIMENSIONS = 256; +U32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256. +U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; +bool LLViewerTexture::sFreezeImageUpdates = false; +F32 LLViewerTexture::sCurrentTime = 0.0f; + +constexpr F32 MIN_VRAM_BUDGET = 768.f; +F32 LLViewerTexture::sFreeVRAMMegabytes = MIN_VRAM_BUDGET; + +LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; + +const F64 log_2 = log(2.0); + +#if ADDRESS_SIZE == 32 +const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT / 2; +#else +const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT; +#endif + +//---------------------------------------------------------------------------------------------- +//namespace: LLViewerTextureAccess +//---------------------------------------------------------------------------------------------- + +LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb, + S32 discard_level, + bool need_imageraw, // Needs image raw for the callback + void* userdata, + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, + LLViewerFetchedTexture* target, + bool pause) + : mCallback(cb), + mLastUsedDiscard(MAX_DISCARD_LEVEL+1), + mDesiredDiscard(discard_level), + mNeedsImageRaw(need_imageraw), + mUserData(userdata), + mSourceCallbackList(src_callback_list), + mPaused(pause) +{ + if(mSourceCallbackList) + { + mSourceCallbackList->insert(LLTextureKey(target->getID(), (ETexListType)target->getTextureListType())); + } +} + +LLLoadedCallbackEntry::~LLLoadedCallbackEntry() +{ +} + +void LLLoadedCallbackEntry::removeTexture(LLViewerFetchedTexture* tex) +{ + if (mSourceCallbackList && tex) + { + mSourceCallbackList->erase(LLTextureKey(tex->getID(), (ETexListType)tex->getTextureListType())); + } +} + +//static +void LLLoadedCallbackEntry::cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list) +{ + //clear texture callbacks. + if(callback_list && !callback_list->empty()) + { + for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = callback_list->begin(); + iter != callback_list->end(); ++iter) + { + LLViewerFetchedTexture* tex = gTextureList.findImage(*iter); + if(tex) + { + tex->deleteCallbackEntry(callback_list); + } + } + callback_list->clear(); + } +} + +LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, bool usemipmaps, LLImageGL* gl_image) +{ + return new LLViewerMediaTexture(media_id, usemipmaps, gl_image); +} + +void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector &output) +{ + return gTextureList.findTexturesByID(id, output); +} + +void LLViewerTextureManager::findTextures(const LLUUID& id, std::vector &output) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + std::vector fetched_output; + gTextureList.findTexturesByID(id, fetched_output); + std::vector::iterator iter = fetched_output.begin(); + while (iter != fetched_output.end()) + { + output.push_back(*iter); + iter++; + } + + //search media texture list + if (output.empty()) + { + LLViewerTexture* tex; + tex = LLViewerTextureManager::findMediaTexture(id); + if (tex) + { + output.push_back(tex); + } + } + +} + +LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + return gTextureList.findImage(id, (ETexListType)tex_type); +} + +LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) +{ + return LLViewerMediaTexture::findMediaTexture(media_id); +} + +LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, bool usemipmaps, LLImageGL* gl_image) +{ + LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id); + if(!tex) + { + tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image); + } + + tex->initVirtualSize(); + + return tex; +} + +LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLTexture* tex, bool report_error) +{ + if(!tex) + { + return NULL; + } + + S8 type = tex->getType(); + if(type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) + { + return static_cast(tex); + } + + if(report_error) + { + LL_ERRS() << "not a fetched texture type: " << type << LL_ENDL; + } + + return NULL; +} + +LLPointer LLViewerTextureManager::getLocalTexture(bool usemipmaps, bool generate_gl_tex) +{ + LLPointer tex = new LLViewerTexture(usemipmaps); + if(generate_gl_tex) + { + tex->generateGLTexture(); + tex->setCategory(LLGLTexture::LOCAL); + } + return tex; +} +LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& id, bool usemipmaps, bool generate_gl_tex) +{ + LLPointer tex = new LLViewerTexture(id, usemipmaps); + if(generate_gl_tex) + { + tex->generateGLTexture(); + tex->setCategory(LLGLTexture::LOCAL); + } + return tex; +} +LLPointer LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, bool usemipmaps) +{ + LLPointer tex = new LLViewerTexture(raw, usemipmaps); + tex->setCategory(LLGLTexture::LOCAL); + return tex; +} +LLPointer LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex) +{ + LLPointer tex = new LLViewerTexture(width, height, components, usemipmaps); + if(generate_gl_tex) + { + tex->generateGLTexture(); + tex->setCategory(LLGLTexture::LOCAL); + } + return tex; +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps) +{ + LLImageDataSharedLock lock(raw); + LLViewerFetchedTexture* ret = new LLViewerFetchedTexture(raw, type, usemipmaps); + gTextureList.addImage(ret, TEX_LIST_STANDARD); + return ret; +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( + const LLUUID &image_id, + FTType f_type, + bool usemipmaps, + LLViewerTexture::EBoostLevel boost_priority, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + LLHost request_from_host) +{ + return gTextureList.getImage(image_id, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host); +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( + const std::string& filename, + FTType f_type, + bool usemipmaps, + LLViewerTexture::EBoostLevel boost_priority, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + const LLUUID& force_id) +{ + return gTextureList.getImageFromFile(filename, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); +} + +//static +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url, + FTType f_type, + bool usemipmaps, + LLViewerTexture::EBoostLevel boost_priority, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + const LLUUID& force_id + ) +{ + return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) +{ + return gTextureList.getImageFromHost(image_id, f_type, host); +} + +// Create a bridge to the viewer texture manager. +class LLViewerTextureManagerBridge : public LLTextureManagerBridge +{ + /*virtual*/ LLPointer getLocalTexture(bool usemipmaps = true, bool generate_gl_tex = true) + { + return LLViewerTextureManager::getLocalTexture(usemipmaps, generate_gl_tex); + } + + /*virtual*/ LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps, bool generate_gl_tex = true) + { + return LLViewerTextureManager::getLocalTexture(width, height, components, usemipmaps, generate_gl_tex); + } + + /*virtual*/ LLGLTexture* getFetchedTexture(const LLUUID &image_id) + { + return LLViewerTextureManager::getFetchedTexture(image_id); + } +}; + + +void LLViewerTextureManager::init() +{ + { + LLPointer raw = new LLImageRaw(1,1,3); + raw->clear(0x77, 0x77, 0x77, 0xFF); + LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), true); + } + + const S32 dim = 128; + LLPointer image_raw = new LLImageRaw(dim,dim,3); + U8* data = image_raw->getData(); + + memset(data, 0, dim * dim * 3); + LLViewerTexture::sBlackImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); + +#if 1 + LLPointer imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT); + LLViewerFetchedTexture::sDefaultImagep = imagep; + + for (S32 i = 0; i=(dim-border) || j>=(dim-border)) + { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0xff; + } + else +#endif + { + *data++ = 0x7f; + *data++ = 0x7f; + *data++ = 0x7f; + } + } + } + imagep->createGLTexture(0, image_raw); + //cache the raw image + imagep->setCachedRawImage(0, image_raw); + image_raw = NULL; +#else + LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, true, LLGLTexture::BOOST_UI); +#endif + LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); + LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER); + + image_raw = new LLImageRaw(32,32,3); + data = image_raw->getData(); + + for (S32 i = 0; i < (32*32*3); i+=3) + { + S32 x = (i % (32*3)) / (3*16); + S32 y = i / (32*3*16); + U8 color = ((x + y) % 2) * 255; + data[i] = color; + data[i+1] = color; + data[i+2] = color; + } + + LLViewerTexture::sCheckerBoardImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); + + LLViewerTexture::initClass(); + + // Create a texture manager bridge. + gTextureManagerBridgep = new LLViewerTextureManagerBridge; + + if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName)) + { + sTesterp = new LLTexturePipelineTester(); + if (!sTesterp->isValid()) + { + delete sTesterp; + sTesterp = NULL; + } + } +} + +void LLViewerTextureManager::cleanup() +{ + stop_glerror(); + + delete gTextureManagerBridgep; + LLImageGL::sDefaultGLTexture = NULL; + LLViewerTexture::sNullImagep = NULL; + LLViewerTexture::sBlackImagep = NULL; + LLViewerTexture::sCheckerBoardImagep = NULL; + LLViewerFetchedTexture::sDefaultImagep = NULL; + LLViewerFetchedTexture::sSmokeImagep = NULL; + LLViewerFetchedTexture::sMissingAssetImagep = NULL; + LLTexUnit::sWhiteTexture = 0; + LLViewerFetchedTexture::sWhiteImagep = NULL; + + LLViewerFetchedTexture::sFlatNormalImagep = NULL; + LLViewerFetchedTexture::sDefaultIrradiancePBRp = NULL; + + LLViewerMediaTexture::cleanUpClass(); +} + +//---------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------- +//start of LLViewerTexture +//---------------------------------------------------------------------------------------------- +// static +void LLViewerTexture::initClass() +{ + LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture(); +} + +// non-const (used externally +F32 texmem_lower_bound_scale = 0.85f; +F32 texmem_middle_bound_scale = 0.925f; + +//static +void LLViewerTexture::updateClass() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + sCurrentTime = gFrameTimeSeconds; + + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) + { + tester->update(); + } + + LLViewerMediaTexture::updateClass(); + + static LLCachedControl max_vram_budget(gSavedSettings, "RenderMaxVRAMBudget", 0); + + F64 texture_bytes_alloc = LLImageGL::getTextureBytesAllocated() / 1024.0 / 512.0; + F64 vertex_bytes_alloc = LLVertexBuffer::getBytesAllocated() / 1024.0 / 512.0; + F64 render_bytes_alloc = LLRenderTarget::sBytesAllocated / 1024.0 / 512.0; + + // get an estimate of how much video memory we're using + // NOTE: our metrics miss about half the vram we use, so this biases high but turns out to typically be within 5% of the real number + F32 used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc + render_bytes_alloc); + + F32 budget = max_vram_budget == 0 ? gGLManager.mVRAM : max_vram_budget; + + // try to leave half a GB for everyone else, but keep at least 768MB for ourselves + F32 target = llmax(budget - 512.f, MIN_VRAM_BUDGET); + sFreeVRAMMegabytes = target - used; + + F32 over_pct = llmax((used-target) / target, 0.f); + sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + over_pct); + + if (sDesiredDiscardBias > 1.f) + { + sDesiredDiscardBias -= gFrameIntervalSeconds * 0.01; + } + + LLViewerTexture::sFreezeImageUpdates = false; // sDesiredDiscardBias > (desired_discard_bias_max - 1.0f); +} + +//end of static functions +//------------------------------------------------------------------------------------------- +const U32 LLViewerTexture::sCurrentFileVersion = 1; + +LLViewerTexture::LLViewerTexture(bool usemipmaps) : + LLGLTexture(usemipmaps) +{ + init(true); + + mID.generate(); + sImageCount++; +} + +LLViewerTexture::LLViewerTexture(const LLUUID& id, bool usemipmaps) : + LLGLTexture(usemipmaps), + mID(id) +{ + init(true); + + sImageCount++; +} + +LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, bool usemipmaps) : + LLGLTexture(width, height, components, usemipmaps) +{ + init(true); + + mID.generate(); + sImageCount++; +} + +LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, bool usemipmaps) : + LLGLTexture(raw, usemipmaps) +{ + init(true); + + mID.generate(); + sImageCount++; +} + +LLViewerTexture::~LLViewerTexture() +{ + // LL_DEBUGS("Avatar") << mID << LL_ENDL; + cleanup(); + sImageCount--; +} + +// virtual +void LLViewerTexture::init(bool firstinit) +{ + mMaxVirtualSize = 0.f; + mMaxVirtualSizeResetInterval = 1; + mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval; + mParcelMedia = NULL; + + memset(&mNumVolumes, 0, sizeof(U32)* LLRender::NUM_VOLUME_TEXTURE_CHANNELS); + mFaceList[LLRender::DIFFUSE_MAP].clear(); + mFaceList[LLRender::NORMAL_MAP].clear(); + mFaceList[LLRender::SPECULAR_MAP].clear(); + mNumFaces[LLRender::DIFFUSE_MAP] = + mNumFaces[LLRender::NORMAL_MAP] = + mNumFaces[LLRender::SPECULAR_MAP] = 0; + + mVolumeList[LLRender::LIGHT_TEX].clear(); + mVolumeList[LLRender::SCULPT_TEX].clear(); + + mMainQueue = LL::WorkQueue::getInstance("mainloop"); + mImageQueue = LL::WorkQueue::getInstance("LLImageGL"); +} + +//virtual +S8 LLViewerTexture::getType() const +{ + return LLViewerTexture::LOCAL_TEXTURE; +} + +void LLViewerTexture::cleanup() +{ + if (LLAppViewer::getTextureFetch()) + { + LLAppViewer::getTextureFetch()->updateRequestPriority(mID, 0.f); + } + + mFaceList[LLRender::DIFFUSE_MAP].clear(); + mFaceList[LLRender::NORMAL_MAP].clear(); + mFaceList[LLRender::SPECULAR_MAP].clear(); + mVolumeList[LLRender::LIGHT_TEX].clear(); + mVolumeList[LLRender::SCULPT_TEX].clear(); +} + +// virtual +void LLViewerTexture::dump() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LLGLTexture::dump(); + + LL_INFOS() << "LLViewerTexture" + << " mID " << mID + << LL_ENDL; +} + +void LLViewerTexture::setBoostLevel(S32 level) +{ + if(mBoostLevel != level) + { + mBoostLevel = level; + if(mBoostLevel != LLViewerTexture::BOOST_NONE && + mBoostLevel != LLViewerTexture::BOOST_SELECTED && + mBoostLevel != LLViewerTexture::BOOST_ICON && + mBoostLevel != LLViewerTexture::BOOST_THUMBNAIL) + { + setNoDelete(); + } + } + + // strongly encourage anything boosted to load at full res + if (mBoostLevel >= LLViewerTexture::BOOST_HIGH) + { + mMaxVirtualSize = 2048.f * 2048.f; + } +} + +bool LLViewerTexture::isActiveFetching() +{ + return false; +} + +bool LLViewerTexture::bindDebugImage(const S32 stage) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (stage < 0) return false; + + bool res = true; + if (LLViewerTexture::sCheckerBoardImagep.notNull() && (this != LLViewerTexture::sCheckerBoardImagep.get())) + { + res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sCheckerBoardImagep); + } + + if(!res) + { + return bindDefaultImage(stage); + } + + return res; +} + +bool LLViewerTexture::bindDefaultImage(S32 stage) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (stage < 0) return false; + + bool res = true; + if (LLViewerFetchedTexture::sDefaultImagep.notNull() && (this != LLViewerFetchedTexture::sDefaultImagep.get())) + { + // use default if we've got it + res = gGL.getTexUnit(stage)->bind(LLViewerFetchedTexture::sDefaultImagep); + } + if (!res && LLViewerTexture::sNullImagep.notNull() && (this != LLViewerTexture::sNullImagep)) + { + res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sNullImagep); + } + if (!res) + { + LL_WARNS() << "LLViewerTexture::bindDefaultImage failed." << LL_ENDL; + } + stop_glerror(); + + //check if there is cached raw image and switch to it if possible + switchToCachedImage(); + + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) + { + tester->updateGrayTextureBinding(); + } + return res; +} + +//virtual +bool LLViewerTexture::isMissingAsset()const +{ + return false; +} + +//virtual +void LLViewerTexture::forceImmediateUpdate() +{ +} + +void LLViewerTexture::addTextureStats(F32 virtual_size, bool needs_gltexture) const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(needs_gltexture) + { + mNeedsGLTexture = true; + } + + virtual_size = llmin(virtual_size, LLViewerFetchedTexture::sMaxVirtualSize); + + if (virtual_size > mMaxVirtualSize) + { + mMaxVirtualSize = virtual_size; + } +} + +void LLViewerTexture::resetTextureStats() +{ + mMaxVirtualSize = 0.0f; + mMaxVirtualSizeResetCounter = 0; +} + +//virtual +F32 LLViewerTexture::getMaxVirtualSize() +{ + return mMaxVirtualSize; +} + +//virtual +void LLViewerTexture::setKnownDrawSize(S32 width, S32 height) +{ + //nothing here. +} + +//virtual +void LLViewerTexture::addFace(U32 ch, LLFace* facep) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mNumFaces[ch] >= mFaceList[ch].size()) + { + mFaceList[ch].resize(2 * mNumFaces[ch] + 1); + } + mFaceList[ch][mNumFaces[ch]] = facep; + facep->setIndexInTex(ch, mNumFaces[ch]); + mNumFaces[ch]++; + mLastFaceListUpdateTimer.reset(); +} + +//virtual +void LLViewerTexture::removeFace(U32 ch, LLFace* facep) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mNumFaces[ch] > 1) + { + S32 index = facep->getIndexInTex(ch); + llassert(index < mFaceList[ch].size()); + llassert(index < mNumFaces[ch]); + mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]]; + mFaceList[ch][index]->setIndexInTex(ch, index); + } + else + { + mFaceList[ch].clear(); + mNumFaces[ch] = 0; + } + mLastFaceListUpdateTimer.reset(); +} + +S32 LLViewerTexture::getTotalNumFaces() const +{ + S32 ret = 0; + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) + { + ret += mNumFaces[i]; + } + + return ret; +} + +S32 LLViewerTexture::getNumFaces(U32 ch) const +{ + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + return mNumFaces[ch]; +} + + +//virtual +void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (mNumVolumes[ch] >= mVolumeList[ch].size()) + { + mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1); + } + mVolumeList[ch][mNumVolumes[ch]] = volumep; + volumep->setIndexInTex(ch, mNumVolumes[ch]); + mNumVolumes[ch]++; + mLastVolumeListUpdateTimer.reset(); +} + +//virtual +void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (mNumVolumes[ch] > 1) + { + S32 index = volumep->getIndexInTex(ch); + llassert(index < mVolumeList[ch].size()); + llassert(index < mNumVolumes[ch]); + mVolumeList[ch][index] = mVolumeList[ch][--mNumVolumes[ch]]; + mVolumeList[ch][index]->setIndexInTex(ch, index); + } + else + { + mVolumeList[ch].clear(); + mNumVolumes[ch] = 0; + } + mLastVolumeListUpdateTimer.reset(); +} + +S32 LLViewerTexture::getNumVolumes(U32 ch) const +{ + return mNumVolumes[ch]; +} + +void LLViewerTexture::reorganizeFaceList() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + static const F32 MAX_WAIT_TIME = 20.f; // seconds + static const U32 MAX_EXTRA_BUFFER_SIZE = 4; + + if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) + { + return; + } + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) + { + if(mNumFaces[i] + MAX_EXTRA_BUFFER_SIZE > mFaceList[i].size()) + { + return; + } + + mFaceList[i].erase(mFaceList[i].begin() + mNumFaces[i], mFaceList[i].end()); + } + + mLastFaceListUpdateTimer.reset(); +} + +void LLViewerTexture::reorganizeVolumeList() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + static const F32 MAX_WAIT_TIME = 20.f; // seconds + static const U32 MAX_EXTRA_BUFFER_SIZE = 4; + + + for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i) + { + if (mNumVolumes[i] + MAX_EXTRA_BUFFER_SIZE > mVolumeList[i].size()) + { + return; + } + } + + if(mLastVolumeListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) + { + return; + } + + mLastVolumeListUpdateTimer.reset(); + for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i) + { + mVolumeList[i].erase(mVolumeList[i].begin() + mNumVolumes[i], mVolumeList[i].end()); + } +} + +//virtual +void LLViewerTexture::switchToCachedImage() +{ + //nothing here. +} + +//virtual +void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) +{ + //nothing here. +} + +bool LLViewerTexture::isLargeImage() +{ + return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize; +} + +//virtual +void LLViewerTexture::updateBindStatsForTester() +{ + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) + { + tester->updateTextureBindingStats(this); + } +} + +//---------------------------------------------------------------------------------------------- +//end of LLViewerTexture +//---------------------------------------------------------------------------------------------- + +const std::string& fttype_to_string(const FTType& fttype) +{ + static const std::string ftt_unknown("FTT_UNKNOWN"); + static const std::string ftt_default("FTT_DEFAULT"); + static const std::string ftt_server_bake("FTT_SERVER_BAKE"); + static const std::string ftt_host_bake("FTT_HOST_BAKE"); + static const std::string ftt_map_tile("FTT_MAP_TILE"); + static const std::string ftt_local_file("FTT_LOCAL_FILE"); + static const std::string ftt_error("FTT_ERROR"); + switch(fttype) + { + case FTT_UNKNOWN: return ftt_unknown; break; + case FTT_DEFAULT: return ftt_default; break; + case FTT_SERVER_BAKE: return ftt_server_bake; break; + case FTT_HOST_BAKE: return ftt_host_bake; break; + case FTT_MAP_TILE: return ftt_map_tile; break; + case FTT_LOCAL_FILE: return ftt_local_file; break; + } + return ftt_error; +} + +//---------------------------------------------------------------------------------------------- +//start of LLViewerFetchedTexture +//---------------------------------------------------------------------------------------------- + +//static +LLViewerFetchedTexture* LLViewerFetchedTexture::getSmokeImage() +{ + if (sSmokeImagep.isNull()) + { + sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE); + } + + sSmokeImagep->addTextureStats(1024.f * 1024.f); + + return sSmokeImagep; +} + +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host, bool usemipmaps) + : LLViewerTexture(id, usemipmaps), + mTargetHost(host) +{ + init(true); + mFTType = f_type; + if (mFTType == FTT_HOST_BAKE) + { + LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL; + } + generateGLTexture(); +} + +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, bool usemipmaps) + : LLViewerTexture(raw, usemipmaps) +{ + init(true); + mFTType = f_type; +} + +LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps) + : LLViewerTexture(id, usemipmaps), + mUrl(url) +{ + init(true); + mFTType = f_type; + generateGLTexture(); +} + +void LLViewerFetchedTexture::init(bool firstinit) +{ + mOrigWidth = 0; + mOrigHeight = 0; + mHasAux = false; + mNeedsAux = false; + mRequestedDiscardLevel = -1; + mRequestedDownloadPriority = 0.f; + mFullyLoaded = false; + mCanUseHTTP = true; + mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + + mDecodingAux = false; + + mKnownDrawWidth = 0; + mKnownDrawHeight = 0; + mKnownDrawSizeChanged = false; + + if (firstinit) + { + mInImageList = 0; + } + + // Only set mIsMissingAsset true when we know for certain that the database + // does not contain this image. + mIsMissingAsset = false; + + mLoadedCallbackDesiredDiscardLevel = S8_MAX; + mPauseLoadedCallBacks = false; + + mNeedsCreateTexture = false; + + mIsRawImageValid = false; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + mMinDiscardLevel = 0; + + mHasFetcher = false; + mIsFetching = false; + mFetchState = 0; + mFetchPriority = 0; + mDownloadProgress = 0.f; + mFetchDeltaTime = 999999.f; + mRequestDeltaTime = 0.f; + mForSculpt = false; + mIsFetched = false; + mInFastCacheList = false; + + mCachedRawImage = NULL; + mCachedRawDiscardLevel = -1; + mCachedRawImageReady = false; + + mSavedRawImage = NULL; + mForceToSaveRawImage = false; + mSaveRawImage = false; + mSavedRawDiscardLevel = -1; + mDesiredSavedRawDiscardLevel = -1; + mLastReferencedSavedRawImageTime = 0.0f; + mKeptSavedRawImageTime = 0.f; + mLastCallBackActiveTime = 0.f; + mForceCallbackFetch = false; + mInDebug = false; + mUnremovable = false; + + mFTType = FTT_UNKNOWN; +} + +LLViewerFetchedTexture::~LLViewerFetchedTexture() +{ + assert_main_thread(); + //*NOTE getTextureFetch can return NULL when Viewer is shutting down. + // This is due to LLWearableList is singleton and is destroyed after + // LLAppViewer::cleanup() was called. (see ticket EXT-177) + if (mHasFetcher && LLAppViewer::getTextureFetch()) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + } + cleanup(); +} + +//virtual +S8 LLViewerFetchedTexture::getType() const +{ + return LLViewerTexture::FETCHED_TEXTURE; +} + +FTType LLViewerFetchedTexture::getFTType() const +{ + return mFTType; +} + +void LLViewerFetchedTexture::cleanup() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + // We never finished loading the image. Indicate failure. + // Note: this allows mLoadedCallbackUserData to be cleaned up. + entryp->mCallback( false, this, NULL, NULL, 0, true, entryp->mUserData ); + entryp->removeTexture(this); + delete entryp; + } + mLoadedCallbackList.clear(); + mNeedsAux = false; + + // Clean up image data + destroyRawImage(); + mCachedRawImage = NULL; + mCachedRawDiscardLevel = -1; + mCachedRawImageReady = false; + mSavedRawImage = NULL; + mSavedRawDiscardLevel = -1; +} + +//access the fast cache +void LLViewerFetchedTexture::loadFromFastCache() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(!mInFastCacheList) + { + return; //no need to access the fast cache. + } + mInFastCacheList = false; + + add(LLTextureFetch::sCacheAttempt, 1.0); + + LLTimer fastCacheTimer; + mRawImage = LLAppViewer::getTextureCache()->readFromFastCache(getID(), mRawDiscardLevel); + if(mRawImage.notNull()) + { + F32 cachReadTime = fastCacheTimer.getElapsedTimeF32(); + + add(LLTextureFetch::sCacheHit, 1.0); + record(LLTextureFetch::sCacheHitRate, LLUnits::Ratio::fromValue(1)); + sample(LLTextureFetch::sCacheReadLatency, cachReadTime); + + mFullWidth = mRawImage->getWidth() << mRawDiscardLevel; + mFullHeight = mRawImage->getHeight() << mRawDiscardLevel; + setTexelsPerImage(); + + if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE) + { + //discard all oversized textures. + destroyRawImage(); + LL_WARNS() << "oversized, setting as missing" << LL_ENDL; + setIsMissingAsset(); + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + } + else + { + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + // Shouldn't do anything usefull since texures in fast cache are 16x16, + // it is here in case fast cache changes. + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) + { + // scale oversized icon, no need to give more work to gl + mRawImage->scale(expected_width, expected_height); + } + } + + if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) + { + // scale oversized icon, no need to give more work to gl + mRawImage->scale(expected_width, expected_height); + } + } + + mRequestedDiscardLevel = mDesiredDiscardLevel + 1; + mIsRawImageValid = true; + addToCreateTexture(); + } + } + else + { + record(LLTextureFetch::sCacheHitRate, LLUnits::Ratio::fromValue(0)); + } +} + +void LLViewerFetchedTexture::setForSculpt() +{ + static const S32 MAX_INTERVAL = 8; //frames + + mForSculpt = true; + if(isForSculptOnly() && hasGLTexture() && !getBoundRecently()) + { + destroyGLTexture(); //sculpt image does not need gl texture. + mTextureState = ACTIVE; + } + checkCachedRawSculptImage(); + setMaxVirtualSizeResetInterval(MAX_INTERVAL); +} + +bool LLViewerFetchedTexture::isForSculptOnly() const +{ + return mForSculpt && !mNeedsGLTexture; +} + +bool LLViewerFetchedTexture::isDeleted() +{ + return mTextureState == DELETED; +} + +bool LLViewerFetchedTexture::isInactive() +{ + return mTextureState == INACTIVE; +} + +bool LLViewerFetchedTexture::isDeletionCandidate() +{ + return mTextureState == DELETION_CANDIDATE; +} + +void LLViewerFetchedTexture::setDeletionCandidate() +{ + if(mGLTexturep.notNull() && mGLTexturep->getTexName() && (mTextureState == INACTIVE)) + { + mTextureState = DELETION_CANDIDATE; + } +} + +//set the texture inactive +void LLViewerFetchedTexture::setInactive() +{ + if(mTextureState == ACTIVE && mGLTexturep.notNull() && mGLTexturep->getTexName() && !mGLTexturep->getBoundRecently()) + { + mTextureState = INACTIVE; + } +} + +bool LLViewerFetchedTexture::isFullyLoaded() const +{ + // Unfortunately, the boolean "mFullyLoaded" is never updated correctly so we use that logic + // to check if the texture is there and completely downloaded + return (mFullWidth != 0) && (mFullHeight != 0) && !mIsFetching && !mHasFetcher; +} + + +// virtual +void LLViewerFetchedTexture::dump() +{ + LLViewerTexture::dump(); + + LL_INFOS() << "Dump : " << mID + << ", mIsMissingAsset = " << (S32)mIsMissingAsset + << ", mFullWidth = " << (S32)mFullWidth + << ", mFullHeight = " << (S32)mFullHeight + << ", mOrigWidth = " << (S32)mOrigWidth + << ", mOrigHeight = " << (S32)mOrigHeight + << LL_ENDL; + LL_INFOS() << " : " + << " mFullyLoaded = " << (S32)mFullyLoaded + << ", mFetchState = " << (S32)mFetchState + << ", mFetchPriority = " << (S32)mFetchPriority + << ", mDownloadProgress = " << (F32)mDownloadProgress + << LL_ENDL; + LL_INFOS() << " : " + << " mHasFetcher = " << (S32)mHasFetcher + << ", mIsFetching = " << (S32)mIsFetching + << ", mIsFetched = " << (S32)mIsFetched + << ", mBoostLevel = " << (S32)mBoostLevel + << LL_ENDL; +} + +/////////////////////////////////////////////////////////////////////////////// +// ONLY called from LLViewerFetchedTextureList +void LLViewerFetchedTexture::destroyTexture() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + if (mNeedsCreateTexture)//return if in the process of generating a new texture. + { + return; + } + + //LL_DEBUGS("Avatar") << mID << LL_ENDL; + destroyGLTexture(); + mFullyLoaded = false; +} + +void LLViewerFetchedTexture::addToCreateTexture() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + bool force_update = false; + if (getComponents() != mRawImage->getComponents()) + { + // We've changed the number of components, so we need to move any + // objects using this pool to a different pool. + mComponents = mRawImage->getComponents(); + mGLTexturep->setComponents(mComponents); + force_update = true; + + for (U32 j = 0; j < LLRender::NUM_TEXTURE_CHANNELS; ++j) + { + llassert(mNumFaces[j] <= mFaceList[j].size()); + + for(U32 i = 0; i < mNumFaces[j]; i++) + { + mFaceList[j][i]->dirtyTexture(); + } + } + + //discard the cached raw image and the saved raw image + mCachedRawImageReady = false; + mCachedRawDiscardLevel = -1; + mCachedRawImage = NULL; + mSavedRawDiscardLevel = -1; + mSavedRawImage = NULL; + } + + if(isForSculptOnly()) + { + //just update some variables, not to create a real GL texture. + createGLTexture(mRawDiscardLevel, mRawImage, 0, false); + mNeedsCreateTexture = false; + destroyRawImage(); + } + else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel) + { + mNeedsCreateTexture = false; + destroyRawImage(); + } + else + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; +#if 1 + // + //if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up, + //so do not scale down the over qualified image. + //Note: scaling down image is expensensive. Do it only when very necessary. + // + if(mRequestedDiscardLevel <= mDesiredDiscardLevel && !mForceToSaveRawImage) + { + S32 w = mFullWidth >> mRawDiscardLevel; + S32 h = mFullHeight >> mRawDiscardLevel; + + //if big image, do not load extra data + //scale it down to size >= LLViewerTexture::sMinLargeImageSize + if(w * h > LLViewerTexture::sMinLargeImageSize) + { + S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel; + + if(d_level > 0) + { + S32 i = 0; + while((d_level > 0) && ((w >> i) * (h >> i) > LLViewerTexture::sMinLargeImageSize)) + { + i++; + d_level--; + } + if(i > 0) + { + mRawDiscardLevel += i; + if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0) + { + mNeedsCreateTexture = false; + destroyRawImage(); + return; + } + + { + //make a duplicate in case somebody else is using this raw image + mRawImage = mRawImage->scaled(w >> i, h >> i); + } + } + } + } + } +#endif + scheduleCreateTexture(); + } + return; +} + +// ONLY called from LLViewerTextureList +bool LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; +#if LL_IMAGEGL_THREAD_CHECK + mGLTexturep->checkActiveThread(); +#endif + + if (!mNeedsCreateTexture) + { + destroyRawImage(); + return false; + } + mNeedsCreateTexture = false; + + if (mRawImage.isNull()) + { + LL_ERRS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL; + } + if (mRawImage->isBufferInvalid()) + { + LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL; + destroyRawImage(); + return false; + } + // LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", + // mRawDiscardLevel, + // mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) + // << mID.getString() << LL_ENDL; + bool res = true; + + // store original size only for locally-sourced images + if (mUrl.compare(0, 7, "file://") == 0) + { + mOrigWidth = mRawImage->getWidth(); + mOrigHeight = mRawImage->getHeight(); + + // This is only safe because it's a local image and fetcher doesn't use raw data + // from local images, but this might become unsafe in case of changes to fetcher + if (mBoostLevel == BOOST_PREVIEW) + { + mRawImage->biasedScaleToPowerOfTwo(1024); + } + else + { // leave black border, do not scale image content + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, false); + } + + mFullWidth = mRawImage->getWidth(); + mFullHeight = mRawImage->getHeight(); + setTexelsPerImage(); + } + else + { + mOrigWidth = mFullWidth; + mOrigHeight = mFullHeight; + } + + bool size_okay = true; + + S32 discard_level = mRawDiscardLevel; + if (mRawDiscardLevel < 0) + { + LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL; + discard_level = 0; + } + + U32 raw_width = mRawImage->getWidth() << discard_level; + U32 raw_height = mRawImage->getHeight() << discard_level; + + if (raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE) + { + LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL; + size_okay = false; + } + + if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) + { + // A non power-of-two image was uploaded (through a non standard client) + LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL; + size_okay = false; + } + + if (!size_okay) + { + // An inappropriately-sized image was uploaded (through a non standard client) + // We treat these images as missing assets which causes them to + // be renderd as 'missing image' and to stop requesting data + LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL; + setIsMissingAsset(); + destroyRawImage(); + return false; + } + + if (mGLTexturep->getHasExplicitFormat()) + { + LLGLenum format = mGLTexturep->getPrimaryFormat(); + S8 components = mRawImage->getComponents(); + if ((format == GL_RGBA && components < 4) + || (format == GL_RGB && components < 3)) + { + LL_WARNS() << "Can't create a texture " << mID << ": invalid image format " << std::hex << format << " vs components " << (U32)components << LL_ENDL; + // Was expecting specific format but raw texture has insufficient components for + // such format, using such texture will result in crash or will display wrongly + // if we change format. Texture might be corrupted server side, so just set as + // missing and clear cashed texture (do not cause reload loop, will retry&recover + // during new session) + setIsMissingAsset(); + destroyRawImage(); + LLAppViewer::getTextureCache()->removeFromCache(mID); + return false; + } + } + + return res; +} + +bool LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) +{ + if (!mNeedsCreateTexture) + { + return false; + } + + bool res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, true, mBoostLevel); + + return res; +} + +void LLViewerFetchedTexture::postCreateTexture() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (!mNeedsCreateTexture) + { + return; + } +#if LL_IMAGEGL_THREAD_CHECK + mGLTexturep->checkActiveThread(); +#endif + + setActive(); + + if (!needsToSaveRawImage()) + { + mNeedsAux = false; + destroyRawImage(); + } + + mNeedsCreateTexture = false; +} + +void LLViewerFetchedTexture::scheduleCreateTexture() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + if (!mNeedsCreateTexture) + { + mNeedsCreateTexture = true; + if (preCreateTexture()) + { +#if LL_IMAGEGL_THREAD_CHECK + //grab a copy of the raw image data to make sure it isn't modified pending texture creation + U8* data = mRawImage->getData(); + U8* data_copy = nullptr; + S32 size = mRawImage->getDataSize(); + if (data != nullptr && size > 0) + { + data_copy = new U8[size]; + memcpy(data_copy, data, size); + } +#endif + mNeedsCreateTexture = true; + auto mainq = LLImageGLThread::sEnabledTextures ? mMainQueue.lock() : nullptr; + if (mainq) + { + ref(); + mainq->postTo( + mImageQueue, + // work to be done on LLImageGL worker thread +#if LL_IMAGEGL_THREAD_CHECK + [this, data, data_copy, size]() + { + mGLTexturep->mActiveThread = LLThread::currentID(); + //verify data is unmodified + llassert(data == mRawImage->getData()); + llassert(mRawImage->getDataSize() == size); + llassert(memcmp(data, data_copy, size) == 0); +#else + [this]() + { +#endif + //actually create the texture on a background thread + createTexture(); + +#if LL_IMAGEGL_THREAD_CHECK + //verify data is unmodified + llassert(data == mRawImage->getData()); + llassert(mRawImage->getDataSize() == size); + llassert(memcmp(data, data_copy, size) == 0); +#endif + }, + // callback to be run on main thread +#if LL_IMAGEGL_THREAD_CHECK + [this, data, data_copy, size]() + { + mGLTexturep->mActiveThread = LLThread::currentID(); + llassert(data == mRawImage->getData()); + llassert(mRawImage->getDataSize() == size); + llassert(memcmp(data, data_copy, size) == 0); + delete[] data_copy; +#else + [this]() + { +#endif + //finalize on main thread + postCreateTexture(); + unref(); + }); + } + else + { + gTextureList.mCreateTextureList.insert(this); + } + } + } +} + +// Call with 0,0 to turn this feature off. +//virtual +void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(mKnownDrawWidth < width || mKnownDrawHeight < height) + { + mKnownDrawWidth = llmax(mKnownDrawWidth, width); + mKnownDrawHeight = llmax(mKnownDrawHeight, height); + + mKnownDrawSizeChanged = true; + mFullyLoaded = false; + } + addTextureStats((F32)(mKnownDrawWidth * mKnownDrawHeight)); +} + +void LLViewerFetchedTexture::setDebugText(const std::string& text) +{ + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + + for (U32 i = 0; i < mNumFaces[ch]; i++) + { + LLFace* facep = mFaceList[ch][i]; + if (facep) + { + LLDrawable* drawable = facep->getDrawable(); + if (drawable) + { + drawable->getVObj()->setDebugText(text); + } + } + } + } +} + +//virtual +void LLViewerFetchedTexture::processTextureStats() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(mFullyLoaded) + { + if(mDesiredDiscardLevel > mMinDesiredDiscardLevel)//need to load more + { + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); + mFullyLoaded = false; + } + //setDebugText("fully loaded"); + } + else + { + updateVirtualSize(); + + static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); + + if (textures_fullres) + { + mDesiredDiscardLevel = 0; + } + else if (mDontDiscard && (mBoostLevel == LLGLTexture::BOOST_ICON || mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)) + { + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + { + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + } + else + { + mDesiredDiscardLevel = 0; + } + } + else if(!mFullWidth || !mFullHeight) + { + mDesiredDiscardLevel = llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel); + } + else + { + U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight) + { + if (mFullWidth > desired_size || mFullHeight > desired_size) + { + mDesiredDiscardLevel = 1; + } + else + { + mDesiredDiscardLevel = 0; + } + } + else if(mKnownDrawSizeChanged)//known draw size is set + { + mDesiredDiscardLevel = (S8)llmin(log((F32)mFullWidth / mKnownDrawWidth) / log_2, + log((F32)mFullHeight / mKnownDrawHeight) / log_2); + mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()); + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); + } + mKnownDrawSizeChanged = false; + + if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel)) + { + mFullyLoaded = true; + } + } + } + + if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) //force to refetch the texture. + { + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); + if(getDiscardLevel() < 0 || getDiscardLevel() > mDesiredDiscardLevel) + { + mFullyLoaded = false; + } + } +} + +//============================================================================ + +void LLViewerFetchedTexture::updateVirtualSize() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + reorganizeFaceList(); + reorganizeVolumeList(); +} + +S32 LLViewerFetchedTexture::getCurrentDiscardLevelForFetching() +{ + S32 current_discard = getDiscardLevel(); + if(mForceToSaveRawImage) + { + if(mSavedRawDiscardLevel < 0 || current_discard < 0) + { + current_discard = -1; + } + else + { + current_discard = llmax(current_discard, mSavedRawDiscardLevel); + } + } + + return current_discard; +} + +bool LLViewerFetchedTexture::setDebugFetching(S32 debug_level) +{ + if(debug_level < 0) + { + mInDebug = false; + return false; + } + mInDebug = true; + + mDesiredDiscardLevel = debug_level; + + return true; +} + +bool LLViewerFetchedTexture::isActiveFetching() +{ + static LLCachedControl monitor_enabled(gSavedSettings,"DebugShowTextureInfo"); + + return mFetchState > 7 && mFetchState < 10 && monitor_enabled; //in state of WAIT_HTTP_REQ or DECODE_IMAGE. +} + +void LLViewerFetchedTexture::setBoostLevel(S32 level) +{ + LLViewerTexture::setBoostLevel(level); + + if (level >= LLViewerTexture::BOOST_HIGH) + { + mDesiredDiscardLevel = 0; + } +} + +bool LLViewerFetchedTexture::updateFetch() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false); + + if(textures_decode_disabled) // don't fetch the surface textures in wireframe mode + { + return false; + } + + mFetchState = 0; + mFetchPriority = 0; + mFetchDeltaTime = 999999.f; + mRequestDeltaTime = 999999.f; + +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (mID == LLAppViewer::getTextureFetch()->mDebugID) + { + LLAppViewer::getTextureFetch()->mDebugCount++; // for setting breakpoints + } +#endif + + if (mNeedsCreateTexture) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - needs create"); + // We may be fetching still (e.g. waiting on write) + // but don't check until we've processed the raw data we have + return false; + } + if (mIsMissingAsset) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - missing asset"); + llassert(!mHasFetcher); + return false; // skip + } + if (!mLoadedCallbackList.empty() && mRawImage.notNull()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - callback pending"); + return false; // process any raw image data in callbacks before replacing + } + if(mInFastCacheList) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - in fast cache"); + return false; + } + if (mGLTexturep.isNull()) + { // fix for crash inside getCurrentDiscardLevelForFetching (shouldn't happen but appears to be happening) + llassert(false); + return false; + } + + S32 current_discard = getCurrentDiscardLevelForFetching(); + S32 desired_discard = getDesiredDiscardLevel(); + F32 decode_priority = mMaxVirtualSize; + + if (mIsFetching) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - is fetching"); + // Sets mRawDiscardLevel, mRawImage, mAuxRawImage + S32 fetch_discard = current_discard; + + if (mRawImage.notNull()) sRawCount--; + if (mAuxRawImage.notNull()) sAuxCount--; + // keep in mind that fetcher still might need raw image, don't modify original + bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, + mLastHttpGetStatus); + if (mRawImage.notNull()) sRawCount++; + if (mAuxRawImage.notNull()) + { + mHasAux = true; + sAuxCount++; + } + if (finished) + { + mIsFetching = false; + mLastFetchState = -1; + mLastPacketTimer.reset(); + } + else + { + mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, + mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP); + } + + // We may have data ready regardless of whether or not we are finished (e.g. waiting on write) + if (mRawImage.notNull()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - has raw image"); + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) + { + mIsFetched = true; + tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)); + } + mRawDiscardLevel = fetch_discard; + if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) && + (current_discard < 0 || mRawDiscardLevel < current_discard)) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - data good"); + mFullWidth = mRawImage->getWidth() << mRawDiscardLevel; + mFullHeight = mRawImage->getHeight() << mRawDiscardLevel; + setTexelsPerImage(); + + if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE) + { + //discard all oversized textures. + destroyRawImage(); + LL_WARNS() << "oversize, setting as missing" << LL_ENDL; + setIsMissingAsset(); + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + mIsFetching = false; + mLastPacketTimer.reset(); + } + else + { + mIsRawImageValid = true; + addToCreateTexture(); + } + + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) + { + // scale oversized icon, no need to give more work to gl + // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy + mRawImage = mRawImage->scaled(expected_width, expected_height); + } + } + + if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) + { + // scale oversized icon, no need to give more work to gl + // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy + mRawImage = mRawImage->scaled(expected_width, expected_height); + } + } + + return true; + } + else + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - data not needed"); + // Data is ready but we don't need it + // (received it already while fetcher was writing to disk) + destroyRawImage(); + return false; // done + } + } + + if (!mIsFetching) + { + if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL)) + { + // We finished but received no data + if (getDiscardLevel() < 0) + { + if (getFTType() != FTT_MAP_TILE) + { + LL_WARNS() << mID + << " Fetch failure, setting as missing, decode_priority " << decode_priority + << " mRawDiscardLevel " << mRawDiscardLevel + << " current_discard " << current_discard + << " stats " << mLastHttpGetStatus.toHex() + << LL_ENDL; + } + setIsMissingAsset(); + desired_discard = -1; + } + else + { + //LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL; + if(current_discard >= 0) + { + mMinDiscardLevel = current_discard; + //desired_discard = current_discard; + } + else + { + S32 dis_level = getDiscardLevel(); + mMinDiscardLevel = dis_level; + //desired_discard = dis_level; + } + } + destroyRawImage(); + } + else if (mRawImage.notNull()) + { + // We have data, but our fetch failed to return raw data + // *TODO: FIgure out why this is happening and fix it + destroyRawImage(); + } + } + else + { + static const F32 MAX_HOLD_TIME = 5.0f; //seconds to wait before canceling fecthing if decode_priority is 0.f. + if(decode_priority > 0.0f || mStopFetchingTimer.getElapsedTimeF32() > MAX_HOLD_TIME) + { + mStopFetchingTimer.reset(); + LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority); + } + } + } + + desired_discard = llmin(desired_discard, getMaxDiscardLevel()); + + bool make_request = true; + if (decode_priority <= 0) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - priority <= 0"); + make_request = false; + } + else if(mDesiredDiscardLevel > getMaxDiscardLevel()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - desired > max"); + make_request = false; + } + else if (mNeedsCreateTexture || mIsMissingAsset) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - create or missing"); + make_request = false; + } + else if (current_discard >= 0 && current_discard <= mMinDiscardLevel) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - current < min"); + make_request = false; + } + else if(mCachedRawImage.notNull() // can be empty + && mCachedRawImageReady + && (current_discard < 0 || current_discard > mCachedRawDiscardLevel)) + { + make_request = false; + switchToCachedImage(); //use the cached raw data first + } + + if (make_request) + { + if (mIsFetching) + { + // already requested a higher resolution mip + if (mRequestedDiscardLevel <= desired_discard) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - requested < desired"); + make_request = false; + } + } + else + { + // already at a higher resolution mip, don't discard + if (current_discard >= 0 && current_discard <= desired_discard) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - current <= desired"); + make_request = false; + } + } + } + + if (make_request) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - make request"); + S32 w=0, h=0, c=0; + if (getDiscardLevel() >= 0) + { + w = mGLTexturep->getWidth(0); + h = mGLTexturep->getHeight(0); + c = mComponents; + } + + const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + if (override_tex_discard_level != 0) + { + desired_discard = override_tex_discard_level; + } + + // bypass texturefetch directly by pulling from LLTextureCache + S32 fetch_request_discard = -1; + fetch_request_discard = LLAppViewer::getTextureFetch()->createRequest(mFTType, mUrl, getID(), getTargetHost(), decode_priority, + w, h, c, desired_discard, needsAux(), mCanUseHTTP); + + if (fetch_request_discard >= 0) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - request created"); + mHasFetcher = true; + mIsFetching = true; + // in some cases createRequest can modify discard, as an example + // bake textures are always at discard 0 + mRequestedDiscardLevel = llmin(desired_discard, fetch_request_discard); + mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, + mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP); + } + + // If createRequest() failed, that means one of two things: + // 1. We're finishing up a request for this UUID, so we + // should wait for it to complete + // 2. We've failed a request for this UUID, so there is + // no need to create another request + } + else if (mHasFetcher && !mIsFetching) + { + // Only delete requests that haven't received any network data + // for a while. Note - this is the normal mechanism for + // deleting requests, not just a place to handle timeouts. + const F32 FETCH_IDLE_TIME = 0.1f; + if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME) + { + LL_DEBUGS("Texture") << "exceeded idle time " << FETCH_IDLE_TIME << ", deleting request: " << getID() << LL_ENDL; + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = false; + } + } + + return mIsFetching; +} + +void LLViewerFetchedTexture::clearFetchedResults() +{ + if(mNeedsCreateTexture || mIsFetching) + { + return; + } + + cleanup(); + destroyGLTexture(); + + if(getDiscardLevel() >= 0) //sculpty texture, force to invalidate + { + mGLTexturep->forceToInvalidateGLTexture(); + } +} + +void LLViewerFetchedTexture::forceToDeleteRequest() +{ + if (mHasFetcher) + { + mHasFetcher = false; + mIsFetching = false; + } + + resetTextureStats(); + + mDesiredDiscardLevel = getMaxDiscardLevel() + 1; +} + +void LLViewerFetchedTexture::setIsMissingAsset(bool is_missing) +{ + if (is_missing == mIsMissingAsset) + { + return; + } + if (is_missing) + { + if (mUrl.empty()) + { + LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; + } + else + { + // This may or may not be an error - it is normal to have no + // map tile on an empty region, but bad if we're failing on a + // server bake texture. + if (getFTType() != FTT_MAP_TILE) + { + LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; + } + } + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = false; + mIsFetching = false; + mLastPacketTimer.reset(); + mFetchState = 0; + mFetchPriority = 0; + } + } + else + { + LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL; + } + mIsMissingAsset = is_missing; +} + +void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, + S32 discard_level, bool keep_imageraw, bool needs_aux, void* userdata, + LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, bool pause) +{ + // + // Don't do ANYTHING here, just add it to the global callback list + // + if (mLoadedCallbackList.empty()) + { + // Put in list to call this->doLoadedCallbacks() periodically + gTextureList.mCallbackList.insert(this); + mLoadedCallbackDesiredDiscardLevel = (S8)discard_level; + } + else + { + mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level); + } + + if(mPauseLoadedCallBacks) + { + if(!pause) + { + unpauseLoadedCallbacks(src_callback_list); + } + } + else if(pause) + { + pauseLoadedCallbacks(src_callback_list); + } + + LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata, src_callback_list, this, pause); + mLoadedCallbackList.push_back(entryp); + + mNeedsAux |= needs_aux; + if(keep_imageraw) + { + mSaveRawImage = true; + } + if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) + { + if(mHasAux) + { + //trigger a refetch + forceToRefetchTexture(); + } + else + { + // We need aux data, but we've already loaded the image, and it didn't have any + LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; + } + } + mLastCallBackActiveTime = sCurrentTime ; + mLastReferencedSavedRawImageTime = sCurrentTime; +} + +void LLViewerFetchedTexture::clearCallbackEntryList() +{ + if(mLoadedCallbackList.empty()) + { + return; + } + + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter; + + // We never finished loading the image. Indicate failure. + // Note: this allows mLoadedCallbackUserData to be cleaned up. + entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); + iter = mLoadedCallbackList.erase(iter); + delete entryp; + } + gTextureList.mCallbackList.erase(this); + + mLoadedCallbackDesiredDiscardLevel = S8_MAX; + if(needsToSaveRawImage()) + { + destroySavedRawImage(); + } + + return; +} + +void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) +{ + if(mLoadedCallbackList.empty() || !callback_list) + { + return; + } + + S32 desired_discard = S8_MAX; + S32 desired_raw_discard = INVALID_DISCARD_LEVEL; + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter; + if(entryp->mSourceCallbackList == callback_list) + { + // We never finished loading the image. Indicate failure. + // Note: this allows mLoadedCallbackUserData to be cleaned up. + entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); + iter = mLoadedCallbackList.erase(iter); + delete entryp; + } + else + { + ++iter; + + desired_discard = llmin(desired_discard, entryp->mDesiredDiscard); + if(entryp->mNeedsImageRaw) + { + desired_raw_discard = llmin(desired_raw_discard, entryp->mDesiredDiscard); + } + } + } + + mLoadedCallbackDesiredDiscardLevel = desired_discard; + if (mLoadedCallbackList.empty()) + { + // If we have no callbacks, take us off of the image callback list. + gTextureList.mCallbackList.erase(this); + + if(needsToSaveRawImage()) + { + destroySavedRawImage(); + } + } + else if(needsToSaveRawImage() && mBoostLevel != LLGLTexture::BOOST_PREVIEW) + { + if(desired_raw_discard != INVALID_DISCARD_LEVEL) + { + mDesiredSavedRawDiscardLevel = desired_raw_discard; + } + else + { + destroySavedRawImage(); + } + } +} + +void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) +{ + if(!callback_list) +{ + mPauseLoadedCallBacks = false; + return; + } + + bool need_raw = false; + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + if(entryp->mSourceCallbackList == callback_list) + { + entryp->mPaused = false; + if(entryp->mNeedsImageRaw) + { + need_raw = true; + } + } + } + mPauseLoadedCallBacks = false ; + mLastCallBackActiveTime = sCurrentTime ; + mForceCallbackFetch = true; + if(need_raw) + { + mSaveRawImage = true; + } +} + +void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) +{ + if(!callback_list) +{ + return; + } + + bool paused = true; + + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + if(entryp->mSourceCallbackList == callback_list) + { + entryp->mPaused = true; + } + else if(!entryp->mPaused) + { + paused = false; + } + } + + if(paused) + { + mPauseLoadedCallBacks = true;//when set, loaded callback is paused. + resetTextureStats(); + mSaveRawImage = false; + } +} + +bool LLViewerFetchedTexture::doLoadedCallbacks() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds + static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds + + if (mNeedsCreateTexture) + { + return false; + } + if(mPauseLoadedCallBacks) + { + destroyRawImage(); + return false; //paused + } + if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME && !mIsFetching) + { + if (mFTType == FTT_SERVER_BAKE) + { + //output some debug info + LL_INFOS() << "baked texture: " << mID << "clears all call backs due to inactivity." << LL_ENDL; + LL_INFOS() << mUrl << LL_ENDL; + LL_INFOS() << "current discard: " << getDiscardLevel() << " current discard for fetch: " << getCurrentDiscardLevelForFetching() << + " Desired discard: " << getDesiredDiscardLevel() << "decode Pri: " << mMaxVirtualSize << LL_ENDL; + } + + clearCallbackEntryList() ; //remove all callbacks. + return false ; + } + + bool res = false; + + if (isMissingAsset()) + { + if (mFTType == FTT_SERVER_BAKE) + { + //output some debug info + LL_INFOS() << "baked texture: " << mID << "is missing." << LL_ENDL; + LL_INFOS() << mUrl << LL_ENDL; + } + + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + // We never finished loading the image. Indicate failure. + // Note: this allows mLoadedCallbackUserData to be cleaned up. + entryp->mCallback(false, this, NULL, NULL, 0, true, entryp->mUserData); + delete entryp; + } + mLoadedCallbackList.clear(); + + // Remove ourself from the global list of textures with callbacks + gTextureList.mCallbackList.erase(this); + return false; + } + + S32 gl_discard = getDiscardLevel(); + + // If we don't have a legit GL image, set it to be lower than the worst discard level + if (gl_discard == -1) + { + gl_discard = MAX_DISCARD_LEVEL + 1; + } + + // + // Determine the quality levels of textures that we can provide to callbacks + // and whether we need to do decompression/readback to get it + // + S32 current_raw_discard = MAX_DISCARD_LEVEL + 1; // We can always do a readback to get a raw discard + S32 best_raw_discard = gl_discard; // Current GL quality level + S32 current_aux_discard = MAX_DISCARD_LEVEL + 1; + S32 best_aux_discard = MAX_DISCARD_LEVEL + 1; + + if (mIsRawImageValid) + { + // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels. + best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel); + best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw + current_aux_discard = llmin(current_aux_discard, best_aux_discard); + } + else + { + // We have no data at all, we need to get it + // Do this by forcing the best aux discard to be 0. + best_aux_discard = 0; + } + + + // + // See if any of the callbacks would actually run using the data that we can provide, + // and also determine if we need to perform any readbacks or decodes. + // + bool run_gl_callbacks = false; + bool run_raw_callbacks = false; + bool need_readback = false; + + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + + if (entryp->mNeedsImageRaw) + { + if (mNeedsAux) + { + // + // Need raw and auxiliary channels + // + if (entryp->mLastUsedDiscard > current_aux_discard) + { + // We have useful data, run the callbacks + run_raw_callbacks = true; + } + } + else + { + if (entryp->mLastUsedDiscard > current_raw_discard) + { + // We have useful data, just run the callbacks + run_raw_callbacks = true; + } + else if (entryp->mLastUsedDiscard > best_raw_discard) + { + // We can readback data, and then run the callbacks + need_readback = true; + run_raw_callbacks = true; + } + } + } + else + { + // Needs just GL + if (entryp->mLastUsedDiscard > gl_discard) + { + // We have enough data, run this callback requiring GL data + run_gl_callbacks = true; + } + } + } + + // + // Do a readback if required, OR start off a texture decode + // + if (need_readback && (getMaxDiscardLevel() > gl_discard)) + { + // Do a readback to get the GL data into the raw image + // We have GL data. + + destroyRawImage(); + reloadRawImage(mLoadedCallbackDesiredDiscardLevel); + llassert(mRawImage.notNull()); + llassert(!mNeedsAux || mAuxRawImage.notNull()); + } + + // + // Run raw/auxiliary data callbacks + // + if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel())) + { + // Do callbacks which require raw image data. + //LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL; + + // Call each party interested in the raw data. + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLLoadedCallbackEntry *entryp = *curiter; + if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel)) + { + // If we've loaded all the data there is to load or we've loaded enough + // to satisfy the interested party, then this is the last time that + // we're going to call them. + + mLastCallBackActiveTime = sCurrentTime; + if(mNeedsAux && mAuxRawImage.isNull()) + { + LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL; + } + bool final = mRawDiscardLevel <= entryp->mDesiredDiscard; + //LL_INFOS() << "Running callback for " << getID() << LL_ENDL; + //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL; + entryp->mLastUsedDiscard = mRawDiscardLevel; + entryp->mCallback(true, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); + if (final) + { + iter = mLoadedCallbackList.erase(curiter); + delete entryp; + } + res = true; + } + } + } + + // + // Run GL callbacks + // + if (run_gl_callbacks && (gl_discard <= getMaxDiscardLevel())) + { + //LL_INFOS() << "doLoadedCallbacks GL for " << getID() << LL_ENDL; + + // Call the callbacks interested in GL data. + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLLoadedCallbackEntry *entryp = *curiter; + if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard)) + { + mLastCallBackActiveTime = sCurrentTime; + bool final = gl_discard <= entryp->mDesiredDiscard; + entryp->mLastUsedDiscard = gl_discard; + entryp->mCallback(true, this, NULL, NULL, gl_discard, final, entryp->mUserData); + if (final) + { + iter = mLoadedCallbackList.erase(curiter); + delete entryp; + } + res = true; + } + } + } + + // Done with any raw image data at this point (will be re-created if we still have callbacks) + destroyRawImage(); + + // + // If we have no callbacks, take us off of the image callback list. + // + if (mLoadedCallbackList.empty()) + { + gTextureList.mCallbackList.erase(this); + } + else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching) + { + //wait for long enough but no fetching request issued, force one. + forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); + mForceCallbackFetch = false; //fire once. + } + + return res; +} + +//virtual +void LLViewerFetchedTexture::forceImmediateUpdate() +{ + //only immediately update a deleted texture which is now being re-used. + if(!isDeleted()) + { + return; + } + //if already called forceImmediateUpdate() + if(mInImageList && mMaxVirtualSize == LLViewerFetchedTexture::sMaxVirtualSize) + { + return; + } + + gTextureList.forceImmediateUpdate(this); + return; +} + +LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) +{ + llassert(mGLTexturep.notNull()); + llassert(discard_level >= 0); + llassert(mComponents > 0); + + if (mRawImage.notNull()) + { + //mRawImage is in use by somebody else, do not delete it. + return NULL; + } + + if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level) + { + if (mSavedRawDiscardLevel != discard_level + && mBoostLevel != BOOST_ICON + && mBoostLevel != BOOST_THUMBNAIL) + { + mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); + mRawImage->copy(getSavedRawImage()); + } + else + { + mRawImage = getSavedRawImage(); + } + mRawDiscardLevel = discard_level; + } + else + { + //force to fetch raw image again if cached raw image is not good enough. + if(mCachedRawDiscardLevel > discard_level) + { + mRawImage = mCachedRawImage; + mRawDiscardLevel = mCachedRawDiscardLevel; + } + else //cached raw image is good enough, copy it. + { + if(mCachedRawDiscardLevel != discard_level) + { + mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); + mRawImage->copy(mCachedRawImage); + } + else + { + mRawImage = mCachedRawImage; + } + mRawDiscardLevel = discard_level; + } + } + mIsRawImageValid = true; + sRawCount++; + + return mRawImage; +} + +bool LLViewerFetchedTexture::needsToSaveRawImage() +{ + return mForceToSaveRawImage || mSaveRawImage; +} + +void LLViewerFetchedTexture::destroyRawImage() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (mAuxRawImage.notNull() && !needsToSaveRawImage()) + { + sAuxCount--; + mAuxRawImage = NULL; + } + + if (mRawImage.notNull()) + { + sRawCount--; + + if(mIsRawImageValid) + { + if(needsToSaveRawImage()) + { + saveRawImage(); + } + setCachedRawImage(); + } + + mRawImage = NULL; + + mIsRawImageValid = false; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + } +} + +//use the mCachedRawImage to (re)generate the gl texture. +//virtual +void LLViewerFetchedTexture::switchToCachedImage() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(mCachedRawImage.notNull() && + !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it + { + mRawImage = mCachedRawImage; + + if (getComponents() != mRawImage->getComponents()) + { + // We've changed the number of components, so we need to move any + // objects using this pool to a different pool. + mComponents = mRawImage->getComponents(); + mGLTexturep->setComponents(mComponents); + gTextureList.dirtyImage(this); + } + + mIsRawImageValid = true; + mRawDiscardLevel = mCachedRawDiscardLevel; + + scheduleCreateTexture(); + } +} + +//cache the imageraw forcefully. +//virtual +void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) +{ + if(imageraw != mRawImage.get()) + { + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); + mCachedRawImage->copyScaled(imageraw); + } + else + { + mCachedRawImage = imageraw; + } + } + else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); + mCachedRawImage->copyScaled(imageraw); + } + else + { + mCachedRawImage = imageraw; + } + } + else + { + mCachedRawImage = imageraw; + } + mCachedRawDiscardLevel = discard_level; + mCachedRawImageReady = true; + } +} + +void LLViewerFetchedTexture::setCachedRawImage() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(mRawImage == mCachedRawImage) + { + return; + } + if(!mIsRawImageValid) + { + return; + } + + if(mCachedRawImageReady) + { + return; + } + + if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel) + { + S32 i = 0; + S32 w = mRawImage->getWidth(); + S32 h = mRawImage->getHeight(); + + S32 max_size = MAX_CACHED_RAW_IMAGE_AREA; + if(LLGLTexture::BOOST_TERRAIN == mBoostLevel) + { + max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA; + } + if(mForSculpt) + { + max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA; + mCachedRawImageReady = !mRawDiscardLevel; + } + else + { + mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)); + } + + while(((w >> i) * (h >> i)) > max_size) + { + ++i; + } + + if(i) + { + if(!(w >> i) || !(h >> i)) + { + --i; + } + + { + //make a duplicate in case somebody else is using this raw image + mRawImage = mRawImage->scaled(w >> i, h >> i); + } + } + mCachedRawImage = mRawImage; + mRawDiscardLevel += i; + mCachedRawDiscardLevel = mRawDiscardLevel; + } +} + +void LLViewerFetchedTexture::checkCachedRawSculptImage() +{ + if(mCachedRawImageReady && mCachedRawDiscardLevel > 0) + { + if(getDiscardLevel() != 0) + { + mCachedRawImageReady = false; + } + else if(isForSculptOnly()) + { + resetTextureStats(); //do not update this image any more. + } + } +} + +void LLViewerFetchedTexture::saveRawImage() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(mRawImage.isNull() || mRawImage == mSavedRawImage || (mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= mRawDiscardLevel)) + { + return; + } + + LLImageDataSharedLock lock(mRawImage); + + mSavedRawDiscardLevel = mRawDiscardLevel; + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENSIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); + mSavedRawImage->copyScaled(mRawImage); + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + } + else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); + mSavedRawImage->copyScaled(mRawImage); + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + + if(mForceToSaveRawImage && mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel) + { + mForceToSaveRawImage = false; + } + + mLastReferencedSavedRawImageTime = sCurrentTime; +} + +//force to refetch the texture to the discard level +void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time) +{ + if(mForceToSaveRawImage) + { + desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel); + kept_time = llmax(kept_time, mKeptSavedRawImageTime); + } + + //trigger a new fetch. + mForceToSaveRawImage = true ; + mDesiredSavedRawDiscardLevel = desired_discard ; + mKeptSavedRawImageTime = kept_time ; + mLastReferencedSavedRawImageTime = sCurrentTime ; + mSavedRawImage = NULL ; + mSavedRawDiscardLevel = -1 ; +} + +void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time) +{ + mKeptSavedRawImageTime = kept_time; + mLastReferencedSavedRawImageTime = sCurrentTime; + + if(mSavedRawDiscardLevel > -1 && mSavedRawDiscardLevel <= desired_discard) + { + return; //raw imge is ready. + } + + if(!mForceToSaveRawImage || mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard) + { + mForceToSaveRawImage = true; + mDesiredSavedRawDiscardLevel = desired_discard; + + //copy from the cached raw image if exists. + if(mCachedRawImage.notNull() && mRawImage.isNull() ) + { + mRawImage = mCachedRawImage; + mRawDiscardLevel = mCachedRawDiscardLevel; + + saveRawImage(); + + mRawImage = NULL; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + } + } +} +void LLViewerFetchedTexture::destroySavedRawImage() +{ + if(mLastReferencedSavedRawImageTime < mKeptSavedRawImageTime) + { + return; //keep the saved raw image. + } + + mForceToSaveRawImage = false; + mSaveRawImage = false; + + clearCallbackEntryList(); + + mSavedRawImage = NULL ; + mForceToSaveRawImage = false ; + mSaveRawImage = false ; + mSavedRawDiscardLevel = -1 ; + mDesiredSavedRawDiscardLevel = -1 ; + mLastReferencedSavedRawImageTime = 0.0f ; + mKeptSavedRawImageTime = 0.f ; + + if(mAuxRawImage.notNull()) + { + sAuxCount--; + mAuxRawImage = NULL; + } +} + +LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() +{ + mLastReferencedSavedRawImageTime = sCurrentTime; + + return mSavedRawImage; +} + +bool LLViewerFetchedTexture::hasSavedRawImage() const +{ + return mSavedRawImage.notNull(); +} + +F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const +{ + return sCurrentTime - mLastReferencedSavedRawImageTime; +} + +//---------------------------------------------------------------------------------------------- +//end of LLViewerFetchedTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLViewerLODTexture +//---------------------------------------------------------------------------------------------- +LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host, bool usemipmaps) + : LLViewerFetchedTexture(id, f_type, host, usemipmaps) +{ + init(true); +} + +LLViewerLODTexture::LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps) + : LLViewerFetchedTexture(url, f_type, id, usemipmaps) +{ + init(true); +} + +void LLViewerLODTexture::init(bool firstinit) +{ + mTexelsPerImage = 64.f*64.f; + mDiscardVirtualSize = 0.f; + mCalculatedDiscardLevel = -1.f; +} + +//virtual +S8 LLViewerLODTexture::getType() const +{ + return LLViewerTexture::LOD_TEXTURE; +} + +bool LLViewerLODTexture::isUpdateFrozen() +{ + return LLViewerTexture::sFreezeImageUpdates; +} + +// This is gauranteed to get called periodically for every texture +//virtual +void LLViewerLODTexture::processTextureStats() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + updateVirtualSize(); + + static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); + + if (textures_fullres) + { + mDesiredDiscardLevel = 0; + } + // Generate the request priority and render priority + else if (mDontDiscard || !mUseMipMaps) + { + mDesiredDiscardLevel = 0; + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + } + else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) + { + // If the image has not been significantly visible in a while, we don't want it + mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1)); + } + else if (!mFullWidth || !mFullHeight) + { + mDesiredDiscardLevel = getMaxDiscardLevel(); + } + else + { + //static const F64 log_2 = log(2.0); + static const F64 log_4 = log(4.0); + + F32 discard_level = 0.f; + + // If we know the output width and height, we can force the discard + // level to the correct value, and thus not decode more texture + // data than we need to. + if (mKnownDrawWidth && mKnownDrawHeight) + { + S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight; + draw_texels = llclamp(draw_texels, MIN_IMAGE_AREA, MAX_IMAGE_AREA); + + // Use log_4 because we're in square-pixel space, so an image + // with twice the width and twice the height will have mTexelsPerImage + // 4 * draw_size + discard_level = (F32)(log(mTexelsPerImage / draw_texels) / log_4); + } + else + { + // Calculate the required scale factor of the image using pixels per texel + discard_level = (F32)(log(mTexelsPerImage / mMaxVirtualSize) / log_4); + mDiscardVirtualSize = mMaxVirtualSize; + mCalculatedDiscardLevel = discard_level; + } + if (mBoostLevel < LLGLTexture::BOOST_SCULPTED) + { + discard_level *= sDesiredDiscardScale; // scale (default 1.1f) + } + discard_level = floorf(discard_level); + + F32 min_discard = 0.f; + U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED) + { + desired_size = DESIRED_NORMAL_TEXTURE_SIZE; + } + if (mFullWidth > desired_size || mFullHeight > desired_size) + min_discard = 1.f; + + discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL); + + // Can't go higher than the max discard level + mDesiredDiscardLevel = llmin(getMaxDiscardLevel() + 1, (S32)discard_level); + // Clamp to min desired discard + mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel); + + // + // At this point we've calculated the quality level that we want, + // if possible. Now we check to see if we have it, and take the + // proper action if we don't. + // + + S32 current_discard = getDiscardLevel(); + if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED && + current_discard >= 0) + { + if (current_discard < (mDesiredDiscardLevel-1) && !mForceToSaveRawImage) + { // should scale down + scaleDown(); + } + } + + if (isUpdateFrozen() // we are out of memory and nearing max allowed bias + && mBoostLevel < LLGLTexture::BOOST_SCULPTED + && mDesiredDiscardLevel < current_discard) + { + // stop requesting more + mDesiredDiscardLevel = current_discard; + } + } + + if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) + { + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); + } + + // decay max virtual size over time + mMaxVirtualSize *= 0.8f; + + // selection manager will immediately reset BOOST_SELECTED but never unsets it + // unset it immediately after we consume it + if (getBoostLevel() == BOOST_SELECTED) + { + setBoostLevel(BOOST_NONE); + } +} + +bool LLViewerLODTexture::scaleDown() +{ + if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel()) + { + switchToCachedImage(); + + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) + { + tester->setStablizingTime(); + } + + return true; + } + return false; +} +//---------------------------------------------------------------------------------------------- +//end of LLViewerLODTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLViewerMediaTexture +//---------------------------------------------------------------------------------------------- +//static +void LLViewerMediaTexture::updateClass() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + static const F32 MAX_INACTIVE_TIME = 30.f; + +#if 0 + //force to play media. + gSavedSettings.setBOOL("AudioStreamingMedia", true); +#endif + + for(media_map_t::iterator iter = sMediaMap.begin(); iter != sMediaMap.end(); ) + { + LLViewerMediaTexture* mediap = iter->second; + + if(mediap->getNumRefs() == 1) //one reference by sMediaMap + { + // + //Note: delay some time to delete the media textures to stop endlessly creating and immediately removing media texture. + // + if(mediap->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) + { + media_map_t::iterator cur = iter++; + sMediaMap.erase(cur); + continue; + } + } + ++iter; + } +} + +//static +void LLViewerMediaTexture::removeMediaImplFromTexture(const LLUUID& media_id) +{ + LLViewerMediaTexture* media_tex = findMediaTexture(media_id); + if(media_tex) + { + media_tex->invalidateMediaImpl(); + } +} + +//static +void LLViewerMediaTexture::cleanUpClass() +{ + sMediaMap.clear(); +} + +//static +LLViewerMediaTexture* LLViewerMediaTexture::findMediaTexture(const LLUUID& media_id) +{ + media_map_t::iterator iter = sMediaMap.find(media_id); + if(iter == sMediaMap.end()) + { + return NULL; + } + + LLViewerMediaTexture* media_tex = iter->second; + media_tex->setMediaImpl(); + media_tex->getLastReferencedTimer()->reset(); + + return media_tex; +} + +LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, bool usemipmaps, LLImageGL* gl_image) + : LLViewerTexture(id, usemipmaps), + mMediaImplp(NULL), + mUpdateVirtualSizeTime(0) +{ + sMediaMap.insert(std::make_pair(id, this)); + + mGLTexturep = gl_image; + + if(mGLTexturep.isNull()) + { + generateGLTexture(); + } + + mGLTexturep->setAllowCompression(false); + + mGLTexturep->setNeedsAlphaAndPickMask(false); + + mIsPlaying = false; + + setMediaImpl(); + + setCategory(LLGLTexture::MEDIA); + + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); + if(tex) //this media is a parcel media for tex. + { + tex->setParcelMedia(this); + } +} + +//virtual +LLViewerMediaTexture::~LLViewerMediaTexture() +{ + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); + if(tex) //this media is a parcel media for tex. + { + tex->setParcelMedia(NULL); + } +} + +void LLViewerMediaTexture::reinit(bool usemipmaps /* = true */) +{ + llassert(mGLTexturep.notNull()); + + mUseMipMaps = usemipmaps; + getLastReferencedTimer()->reset(); + mGLTexturep->setUseMipMaps(mUseMipMaps); + mGLTexturep->setNeedsAlphaAndPickMask(false); +} + +void LLViewerMediaTexture::setUseMipMaps(bool mipmap) +{ + mUseMipMaps = mipmap; + + if(mGLTexturep.notNull()) + { + mGLTexturep->setUseMipMaps(mipmap); + } +} + +//virtual +S8 LLViewerMediaTexture::getType() const +{ + return LLViewerTexture::MEDIA_TEXTURE; +} + +void LLViewerMediaTexture::invalidateMediaImpl() +{ + mMediaImplp = NULL; +} + +void LLViewerMediaTexture::setMediaImpl() +{ + if(!mMediaImplp) + { + mMediaImplp = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mID); + } +} + +//return true if all faces to reference to this media texture are found +//Note: mMediaFaceList is valid only for the current instant +// because it does not check the face validity after the current frame. +bool LLViewerMediaTexture::findFaces() +{ + mMediaFaceList.clear(); + + bool ret = true; + + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); + if(tex) //this media is a parcel media for tex. + { + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + const ll_face_list_t* face_list = tex->getFaceList(ch); + U32 end = tex->getNumFaces(ch); + for(U32 i = 0; i < end; i++) + { + if ((*face_list)[i]->isMediaAllowed()) + { + mMediaFaceList.push_back((*face_list)[i]); + } + } + } + } + + if(!mMediaImplp) + { + return true; + } + + //for media on a face. + const std::list< LLVOVolume* >* obj_list = mMediaImplp->getObjectList(); + std::list< LLVOVolume* >::const_iterator iter = obj_list->begin(); + for(; iter != obj_list->end(); ++iter) + { + LLVOVolume* obj = *iter; + if (obj->isDead()) + { + // Isn't supposed to happen, objects are supposed to detach + // themselves on markDead() + // If this happens, viewer is likely to crash + llassert(0); + LL_WARNS() << "Dead object in mMediaImplp's object list" << LL_ENDL; + ret = false; + continue; + } + + if (obj->mDrawable.isNull() || obj->mDrawable->isDead()) + { + ret = false; + continue; + } + + S32 face_id = -1; + S32 num_faces = obj->mDrawable->getNumFaces(); + while((face_id = obj->getFaceIndexWithMediaImpl(mMediaImplp, face_id)) > -1 && face_id < num_faces) + { + LLFace* facep = obj->mDrawable->getFace(face_id); + if(facep) + { + mMediaFaceList.push_back(facep); + } + else + { + ret = false; + } + } + } + + return ret; +} + +void LLViewerMediaTexture::initVirtualSize() +{ + if(mIsPlaying) + { + return; + } + + findFaces(); + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + addTextureStats((*iter)->getVirtualSize()); + } +} + +void LLViewerMediaTexture::addMediaToFace(LLFace* facep) +{ + if(facep) + { + facep->setHasMedia(true); + } + if(!mIsPlaying) + { + return; //no need to add the face because the media is not in playing. + } + + switchTexture(LLRender::DIFFUSE_MAP, facep); +} + +void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) +{ + if(!facep) + { + return; + } + facep->setHasMedia(false); + + if(!mIsPlaying) + { + return; //no need to remove the face because the media is not in playing. + } + + mIsPlaying = false; //set to remove the media from the face. + switchTexture(LLRender::DIFFUSE_MAP, facep); + mIsPlaying = true; //set the flag back. + + if(getTotalNumFaces() < 1) //no face referencing to this media + { + stopPlaying(); + } +} + +//virtual +void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) +{ + LLViewerTexture::addFace(ch, facep); + + const LLTextureEntry* te = facep->getTextureEntry(); + if(te && te->getID().notNull()) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); + if(tex) + { + mTextureList.push_back(tex);//increase the reference number by one for tex to avoid deleting it. + return; + } + } + + //check if it is a parcel media + if(facep->getTexture() && facep->getTexture() != this && facep->getTexture()->getID() == mID) + { + mTextureList.push_back(facep->getTexture()); //a parcel media. + return; + } + + if(te && te->getID().notNull()) //should have a texture + { + LL_WARNS_ONCE() << "The face's texture " << te->getID() << " is not valid. Face must have a valid texture before media texture." << LL_ENDL; + // This might break the object, but it likely isn't a 'recoverable' situation. + LLViewerFetchedTexture* tex = LLViewerTextureManager::getFetchedTexture(te->getID()); + mTextureList.push_back(tex); + } +} + +//virtual +void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) +{ + LLViewerTexture::removeFace(ch, facep); + + const LLTextureEntry* te = facep->getTextureEntry(); + if(te && te->getID().notNull()) + { + LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); + if(tex) + { + for(std::list< LLPointer >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + if(*iter == tex) + { + mTextureList.erase(iter); //decrease the reference number for tex by one. + return; + } + } + + std::vector te_list; + + for (U32 ch = 0; ch < 3; ++ch) + { + // + //we have some trouble here: the texture of the face is changed. + //we need to find the former texture, and remove it from the list to avoid memory leaking. + + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + + for(U32 j = 0; j < mNumFaces[ch]; j++) + { + te_list.push_back(mFaceList[ch][j]->getTextureEntry());//all textures are in use. + } + } + + if (te_list.empty()) + { + mTextureList.clear(); + return; + } + + S32 end = te_list.size(); + + for(std::list< LLPointer >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + S32 i = 0; + + for(i = 0; i < end; i++) + { + if(te_list[i] && te_list[i]->getID() == (*iter)->getID())//the texture is in use. + { + te_list[i] = NULL; + break; + } + } + if(i == end) //no hit for this texture, remove it. + { + mTextureList.erase(iter); //decrease the reference number for tex by one. + return; + } + } + } + } + + //check if it is a parcel media + for(std::list< LLPointer >::iterator iter = mTextureList.begin(); + iter != mTextureList.end(); ++iter) + { + if((*iter)->getID() == mID) + { + mTextureList.erase(iter); //decrease the reference number for tex by one. + return; + } + } + + if(te && te->getID().notNull()) //should have a texture but none found + { + LL_ERRS() << "mTextureList texture reference number is corrupted. Texture id: " << te->getID() << " List size: " << (U32)mTextureList.size() << LL_ENDL; + } +} + +void LLViewerMediaTexture::stopPlaying() +{ + // Don't stop the media impl playing here -- this breaks non-inworld media (login screen, search, and media browser). +// if(mMediaImplp) +// { +// mMediaImplp->stop(); +// } + mIsPlaying = false; +} + +void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep) +{ + if(facep) + { + //check if another media is playing on this face. + if(facep->getTexture() && facep->getTexture() != this + && facep->getTexture()->getType() == LLViewerTexture::MEDIA_TEXTURE) + { + if(mID == facep->getTexture()->getID()) //this is a parcel media + { + return; //let the prim media win. + } + } + + if(mIsPlaying) //old textures switch to the media texture + { + facep->switchTexture(ch, this); + } + else //switch to old textures. + { + const LLTextureEntry* te = facep->getTextureEntry(); + if(te) + { + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; + if(!tex && te->getID() != mID)//try parcel media. + { + tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); + } + if(!tex) + { + tex = LLViewerFetchedTexture::sDefaultImagep; + } + facep->switchTexture(ch, tex); + } + } + } +} + +void LLViewerMediaTexture::setPlaying(bool playing) +{ + if(!mMediaImplp) + { + return; + } + if(!playing && !mIsPlaying) + { + return; //media is already off + } + + if(playing == mIsPlaying && !mMediaImplp->isUpdated()) + { + return; //nothing has changed since last time. + } + + mIsPlaying = playing; + if(mIsPlaying) //is about to play this media + { + if(findFaces()) + { + //about to update all faces. + mMediaImplp->setUpdated(false); + } + + if(mMediaFaceList.empty())//no face pointing to this media + { + stopPlaying(); + return; + } + + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + switchTexture(LLRender::DIFFUSE_MAP, *iter); + } + } + else //stop playing this media + { + U32 ch = LLRender::DIFFUSE_MAP; + + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + for(U32 i = mNumFaces[ch]; i; i--) + { + switchTexture(ch, mFaceList[ch][i - 1]); //current face could be removed in this function. + } + } + return; +} + +//virtual +F32 LLViewerMediaTexture::getMaxVirtualSize() +{ + if(LLFrameTimer::getFrameCount() == mUpdateVirtualSizeTime) + { + return mMaxVirtualSize; + } + mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount(); + + if(!mMaxVirtualSizeResetCounter) + { + addTextureStats(0.f, false);//reset + } + + if(mIsPlaying) //media is playing + { + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + for(U32 i = 0; i < mNumFaces[ch]; i++) + { + LLFace* facep = mFaceList[ch][i]; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()); + } + } + } + } + else //media is not in playing + { + findFaces(); + + if(!mMediaFaceList.empty()) + { + for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) + { + LLFace* facep = *iter; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()); + } + } + } + } + + if(mMaxVirtualSizeResetCounter > 0) + { + mMaxVirtualSizeResetCounter--; + } + reorganizeFaceList(); + reorganizeVolumeList(); + + return mMaxVirtualSize; +} +//---------------------------------------------------------------------------------------------- +//end of LLViewerMediaTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLTexturePipelineTester +//---------------------------------------------------------------------------------------------- +LLTexturePipelineTester::LLTexturePipelineTester() : LLMetricPerformanceTesterWithSession(sTesterName) +{ + addMetric("TotalBytesLoaded"); + addMetric("TotalBytesLoadedFromCache"); + addMetric("TotalBytesLoadedForLargeImage"); + addMetric("TotalBytesLoadedForSculpties"); + addMetric("StartFetchingTime"); + addMetric("TotalGrayTime"); + addMetric("TotalStablizingTime"); + addMetric("StartTimeLoadingSculpties"); + addMetric("EndTimeLoadingSculpties"); + + addMetric("Time"); + addMetric("TotalBytesBound"); + addMetric("TotalBytesBoundForLargeImage"); + addMetric("PercentageBytesBound"); + + mTotalBytesLoaded = (S32Bytes)0; + mTotalBytesLoadedFromCache = (S32Bytes)0; + mTotalBytesLoadedForLargeImage = (S32Bytes)0; + mTotalBytesLoadedForSculpties = (S32Bytes)0; + + reset(); +} + +LLTexturePipelineTester::~LLTexturePipelineTester() +{ + LLViewerTextureManager::sTesterp = NULL; +} + +void LLTexturePipelineTester::update() +{ + mLastTotalBytesUsed = mTotalBytesUsed; + mLastTotalBytesUsedForLargeImage = mTotalBytesUsedForLargeImage; + mTotalBytesUsed = (S32Bytes)0; + mTotalBytesUsedForLargeImage = (S32Bytes)0; + + if(LLAppViewer::getTextureFetch()->getNumRequests() > 0) //fetching list is not empty + { + if(mPause) + { + //start a new fetching session + reset(); + mStartFetchingTime = LLImageGL::sLastFrameTime; + mPause = false; + } + + //update total gray time + if(mUsingDefaultTexture) + { + mUsingDefaultTexture = false; + mTotalGrayTime = LLImageGL::sLastFrameTime - mStartFetchingTime; + } + + //update the stablizing timer. + updateStablizingTime(); + + outputTestResults(); + } + else if(!mPause) + { + //stop the current fetching session + mPause = true; + outputTestResults(); + reset(); + } +} + +void LLTexturePipelineTester::reset() +{ + mPause = true; + + mUsingDefaultTexture = false; + mStartStablizingTime = 0.0f; + mEndStablizingTime = 0.0f; + + mTotalBytesUsed = (S32Bytes)0; + mTotalBytesUsedForLargeImage = (S32Bytes)0; + mLastTotalBytesUsed = (S32Bytes)0; + mLastTotalBytesUsedForLargeImage = (S32Bytes)0; + + mStartFetchingTime = 0.0f; + + mTotalGrayTime = 0.0f; + mTotalStablizingTime = 0.0f; + + mStartTimeLoadingSculpties = 1.0f; + mEndTimeLoadingSculpties = 0.0f; +} + +//virtual +void LLTexturePipelineTester::outputTestRecord(LLSD *sd) +{ + std::string currentLabel = getCurrentLabelName(); + (*sd)[currentLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded.value(); + (*sd)[currentLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache.value(); + (*sd)[currentLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage.value(); + (*sd)[currentLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties.value(); + + (*sd)[currentLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime; + (*sd)[currentLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime; + (*sd)[currentLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime; + + (*sd)[currentLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties; + (*sd)[currentLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties; + + (*sd)[currentLabel]["Time"] = LLImageGL::sLastFrameTime; + (*sd)[currentLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed.value(); + (*sd)[currentLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage.value(); + (*sd)[currentLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded); +} + +void LLTexturePipelineTester::updateTextureBindingStats(const LLViewerTexture* imagep) +{ + U32Bytes mem_size = imagep->getTextureMemory(); + mTotalBytesUsed += mem_size; + + if(MIN_LARGE_IMAGE_AREA <= (U32)(mem_size.value() / (U32)imagep->getComponents())) + { + mTotalBytesUsedForLargeImage += mem_size; + } +} + +void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, bool from_cache) +{ + U32Bytes data_size = (U32Bytes)raw_imagep->getDataSize(); + mTotalBytesLoaded += data_size; + + if(from_cache) + { + mTotalBytesLoadedFromCache += data_size; + } + + if(MIN_LARGE_IMAGE_AREA <= (U32)(data_size.value() / (U32)raw_imagep->getComponents())) + { + mTotalBytesLoadedForLargeImage += data_size; + } + + if(imagep->forSculpt()) + { + mTotalBytesLoadedForSculpties += data_size; + + if(mStartTimeLoadingSculpties > mEndTimeLoadingSculpties) + { + mStartTimeLoadingSculpties = LLImageGL::sLastFrameTime; + } + mEndTimeLoadingSculpties = LLImageGL::sLastFrameTime; + } +} + +void LLTexturePipelineTester::updateGrayTextureBinding() +{ + mUsingDefaultTexture = true; +} + +void LLTexturePipelineTester::setStablizingTime() +{ + if(mStartStablizingTime <= mStartFetchingTime) + { + mStartStablizingTime = LLImageGL::sLastFrameTime; + } + mEndStablizingTime = LLImageGL::sLastFrameTime; +} + +void LLTexturePipelineTester::updateStablizingTime() +{ + if(mStartStablizingTime > mStartFetchingTime) + { + F32 t = mEndStablizingTime - mStartStablizingTime; + + if(t > F_ALMOST_ZERO && (t - mTotalStablizingTime) < F_ALMOST_ZERO) + { + //already stablized + mTotalStablizingTime = LLImageGL::sLastFrameTime - mStartStablizingTime; + + //cancel the timer + mStartStablizingTime = 0.f; + mEndStablizingTime = 0.f; + } + else + { + mTotalStablizingTime = t; + } + } + mTotalStablizingTime = 0.f; +} + +//virtual +void LLTexturePipelineTester::compareTestSessions(llofstream* os) +{ + LLTexturePipelineTester::LLTextureTestSession* base_sessionp = dynamic_cast(mBaseSessionp); + LLTexturePipelineTester::LLTextureTestSession* current_sessionp = dynamic_cast(mCurrentSessionp); + if(!base_sessionp || !current_sessionp) + { + LL_ERRS() << "type of test session does not match!" << LL_ENDL; + } + + //compare and output the comparison + *os << llformat("%s\n", getTesterName().c_str()); + *os << llformat("AggregateResults\n"); + + compareTestResults(os, "TotalGrayTime", base_sessionp->mTotalGrayTime, current_sessionp->mTotalGrayTime); + compareTestResults(os, "TotalStablizingTime", base_sessionp->mTotalStablizingTime, current_sessionp->mTotalStablizingTime); + compareTestResults(os, "StartTimeLoadingSculpties", base_sessionp->mStartTimeLoadingSculpties, current_sessionp->mStartTimeLoadingSculpties); + compareTestResults(os, "TotalTimeLoadingSculpties", base_sessionp->mTotalTimeLoadingSculpties, current_sessionp->mTotalTimeLoadingSculpties); + + compareTestResults(os, "TotalBytesLoaded", base_sessionp->mTotalBytesLoaded, current_sessionp->mTotalBytesLoaded); + compareTestResults(os, "TotalBytesLoadedFromCache", base_sessionp->mTotalBytesLoadedFromCache, current_sessionp->mTotalBytesLoadedFromCache); + compareTestResults(os, "TotalBytesLoadedForLargeImage", base_sessionp->mTotalBytesLoadedForLargeImage, current_sessionp->mTotalBytesLoadedForLargeImage); + compareTestResults(os, "TotalBytesLoadedForSculpties", base_sessionp->mTotalBytesLoadedForSculpties, current_sessionp->mTotalBytesLoadedForSculpties); + + *os << llformat("InstantResults\n"); + S32 size = llmin(base_sessionp->mInstantPerformanceListCounter, current_sessionp->mInstantPerformanceListCounter); + for(S32 i = 0; i < size; i++) + { + *os << llformat("Time(B-T)-%.4f-%.4f\n", base_sessionp->mInstantPerformanceList[i].mTime, current_sessionp->mInstantPerformanceList[i].mTime); + + compareTestResults(os, "AverageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond, + current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); + + compareTestResults(os, "AverageBytesUsedForLargeImagePerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond, + current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); + + compareTestResults(os, "AveragePercentageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond, + current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); + } + + if(size < base_sessionp->mInstantPerformanceListCounter) + { + for(S32 i = size; i < base_sessionp->mInstantPerformanceListCounter; i++) + { + *os << llformat("Time(B-T)-%.4f- \n", base_sessionp->mInstantPerformanceList[i].mTime); + + *os << llformat(", AverageBytesUsedPerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); + *os << llformat(", AverageBytesUsedForLargeImagePerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); + *os << llformat(", AveragePercentageBytesUsedPerSecond, %.4f, N/A \n", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); + } + } + else if(size < current_sessionp->mInstantPerformanceListCounter) + { + for(S32 i = size; i < current_sessionp->mInstantPerformanceListCounter; i++) + { + *os << llformat("Time(B-T)- -%.4f\n", current_sessionp->mInstantPerformanceList[i].mTime); + + *os << llformat(", AverageBytesUsedPerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); + *os << llformat(", AverageBytesUsedForLargeImagePerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); + *os << llformat(", AveragePercentageBytesUsedPerSecond, N/A, %.4f\n", current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); + } + } +} + +//virtual +LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::loadTestSession(LLSD* log) +{ + LLTexturePipelineTester::LLTextureTestSession* sessionp = new LLTexturePipelineTester::LLTextureTestSession(); + if(!sessionp) + { + return NULL; + } + + F32 total_gray_time = 0.f; + F32 total_stablizing_time = 0.f; + F32 total_loading_sculpties_time = 0.f; + + F32 start_fetching_time = -1.f; + F32 start_fetching_sculpties_time = 0.f; + + F32 last_time = 0.0f; + S32 frame_count = 0; + + sessionp->mInstantPerformanceListCounter = 0; + sessionp->mInstantPerformanceList.resize(128); + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f; + + //load a session + std::string currentLabel = getCurrentLabelName(); + bool in_log = (*log).has(currentLabel); + while (in_log) + { + LLSD::String label = currentLabel; + + if(sessionp->mInstantPerformanceListCounter >= (S32)sessionp->mInstantPerformanceList.size()) + { + sessionp->mInstantPerformanceList.resize(sessionp->mInstantPerformanceListCounter + 128); + } + + //time + F32 start_time = (*log)[label]["StartFetchingTime"].asReal(); + F32 cur_time = (*log)[label]["Time"].asReal(); + if(start_time - start_fetching_time > F_ALMOST_ZERO) //fetching has paused for a while + { + sessionp->mTotalGrayTime += total_gray_time; + sessionp->mTotalStablizingTime += total_stablizing_time; + + sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time; + sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time; + + start_fetching_time = start_time; + total_gray_time = 0.f; + total_stablizing_time = 0.f; + total_loading_sculpties_time = 0.f; + } + else + { + total_gray_time = (*log)[label]["TotalGrayTime"].asReal(); + total_stablizing_time = (*log)[label]["TotalStablizingTime"].asReal(); + + total_loading_sculpties_time = (*log)[label]["EndTimeLoadingSculpties"].asReal() - (*log)[label]["StartTimeLoadingSculpties"].asReal(); + if(start_fetching_sculpties_time < 0.f && total_loading_sculpties_time > 0.f) + { + start_fetching_sculpties_time = (*log)[label]["StartTimeLoadingSculpties"].asReal(); + } + } + + //total loaded bytes + sessionp->mTotalBytesLoaded = (*log)[label]["TotalBytesLoaded"].asInteger(); + sessionp->mTotalBytesLoadedFromCache = (*log)[label]["TotalBytesLoadedFromCache"].asInteger(); + sessionp->mTotalBytesLoadedForLargeImage = (*log)[label]["TotalBytesLoadedForLargeImage"].asInteger(); + sessionp->mTotalBytesLoadedForSculpties = (*log)[label]["TotalBytesLoadedForSculpties"].asInteger(); + + //instant metrics + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond += + (*log)[label]["TotalBytesBound"].asInteger(); + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond += + (*log)[label]["TotalBytesBoundForLargeImage"].asInteger(); + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond += + (*log)[label]["PercentageBytesBound"].asReal(); + frame_count++; + if(cur_time - last_time >= 1.0f) + { + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond /= frame_count; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond /= frame_count; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond /= frame_count; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = last_time; + + frame_count = 0; + last_time = cur_time; + sessionp->mInstantPerformanceListCounter++; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f; + } + // Next label + incrementCurrentCount(); + currentLabel = getCurrentLabelName(); + in_log = (*log).has(currentLabel); + } + + sessionp->mTotalGrayTime += total_gray_time; + sessionp->mTotalStablizingTime += total_stablizing_time; + + if(sessionp->mStartTimeLoadingSculpties < 0.f) + { + sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time; + } + sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time; + + return sessionp; +} + +LLTexturePipelineTester::LLTextureTestSession::LLTextureTestSession() +{ + reset(); +} +LLTexturePipelineTester::LLTextureTestSession::~LLTextureTestSession() +{ +} +void LLTexturePipelineTester::LLTextureTestSession::reset() +{ + mTotalGrayTime = 0.0f; + mTotalStablizingTime = 0.0f; + + mStartTimeLoadingSculpties = 0.0f; + mTotalTimeLoadingSculpties = 0.0f; + + mTotalBytesLoaded = 0; + mTotalBytesLoadedFromCache = 0; + mTotalBytesLoadedForLargeImage = 0; + mTotalBytesLoadedForSculpties = 0; + + mInstantPerformanceListCounter = 0; +} +//---------------------------------------------------------------------------------------------- +//end of LLTexturePipelineTester +//---------------------------------------------------------------------------------------------- + -- cgit v1.2.3 From 2f4120038429c6aff865f153f708ceefb60d67f4 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 28 May 2024 09:45:40 -0500 Subject: Remove tinygltf dependency from LL::GLTF (#1541) * #1535 Image loading/saving support in boost::json driven GLTF parser * #1536 GLB Support in boost::json drvien GLTF parser --- indra/newview/llviewertexture.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 06c0c62c70..7f913e4153 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -335,6 +335,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } +//static +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromMemory(const U8* data, U32 size, std::string_view mimetype) +{ + return gTextureList.getImageFromMemory(data, size, mimetype); +} + LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) { return gTextureList.getImageFromHost(image_id, f_type, host); -- cgit v1.2.3 From d1a8a9d0c39bff726e8c298c5bad309055726a30 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 30 May 2024 16:28:56 -0500 Subject: #1596 Fix for GLTF uploads failing after loading from .glb file (#1602) --- indra/newview/llviewertexture.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 7f913e4153..545bfeaafa 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -335,6 +335,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } +//static +LLImageRaw* LLViewerTextureManager::getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype) +{ + return gTextureList.getRawImageFromMemory(data, size, mimetype); +} + //static LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromMemory(const U8* data, U32 size, std::string_view mimetype) { -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/newview/llviewertexture.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index fbb423358b..879a4bd259 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3516,12 +3516,12 @@ void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) return; } - S32 end = te_list.size(); + auto end = te_list.size(); for(std::list< LLPointer >::iterator iter = mTextureList.begin(); iter != mTextureList.end(); ++iter) { - S32 i = 0; + size_t i = 0; for(i = 0; i < end; i++) { -- cgit v1.2.3 From c0fad3028fd55c2067ce6a0ae4382cffe1014284 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 16:42:43 +0200 Subject: Re-enable compiler warnings C4018, C4100, C4231 and C4506 --- indra/newview/llviewertexture.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 879a4bd259..55d0aba211 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1326,8 +1326,8 @@ void LLViewerFetchedTexture::addToCreateTexture() // if(mRequestedDiscardLevel <= mDesiredDiscardLevel && !mForceToSaveRawImage) { - S32 w = mFullWidth >> mRawDiscardLevel; - S32 h = mFullHeight >> mRawDiscardLevel; + U32 w = mFullWidth >> mRawDiscardLevel; + U32 h = mFullHeight >> mRawDiscardLevel; //if big image, do not load extra data //scale it down to size >= LLViewerTexture::sMinLargeImageSize @@ -1672,7 +1672,7 @@ void LLViewerFetchedTexture::processTextureStats() else { U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 - if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight) + if(!mKnownDrawWidth || !mKnownDrawHeight || (S32)mFullWidth <= mKnownDrawWidth || (S32)mFullHeight <= mKnownDrawHeight) { if (mFullWidth > desired_size || mFullHeight > desired_size) { -- cgit v1.2.3 From 13b08c8ae1c3b92236f156fba5686f231abfb711 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 17:17:50 +0200 Subject: Add more missing type casts --- indra/newview/llviewertexture.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/llviewertexture.cpp') diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 55d0aba211..e3f9b21342 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -765,8 +765,8 @@ void LLViewerTexture::removeFace(U32 ch, LLFace* facep) if(mNumFaces[ch] > 1) { S32 index = facep->getIndexInTex(ch); - llassert(index < mFaceList[ch].size()); - llassert(index < mNumFaces[ch]); + llassert(index < (S32)mFaceList[ch].size()); + llassert(index < (S32)mNumFaces[ch]); mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]]; mFaceList[ch][index]->setIndexInTex(ch, index); } @@ -818,8 +818,8 @@ void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep) if (mNumVolumes[ch] > 1) { S32 index = volumep->getIndexInTex(ch); - llassert(index < mVolumeList[ch].size()); - llassert(index < mNumVolumes[ch]); + llassert(index < (S32)mVolumeList[ch].size()); + llassert(index < (S32)mNumVolumes[ch]); mVolumeList[ch][index] = mVolumeList[ch][--mNumVolumes[ch]]; mVolumeList[ch][index]->setIndexInTex(ch, index); } -- cgit v1.2.3