diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index b162afddf0..808d218e8e 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -1006,9 +1006,13 @@ void LLPreviewTexture::onAspectRatioCommit(LLUICtrl* ctrl, void* userdata) void LLPreviewTexture::loadAsset() { - mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - mImageOldBoostLevel = mImage->getBoostLevel(); - mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + // mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + // mImageOldBoostLevel = mImage->getBoostLevel(); + // mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_PREVIEW, LLViewerTexture::LOD_TEXTURE); + mImageOldBoostLevel = LLGLTexture::BOOST_NONE; + // mImage->forceToSaveRawImage(0) ; // texture comment decoder mImage->setLoadedCallback(LLPreviewTexture::onTextureLoaded, 0, TRUE, FALSE, this, &mCallbackTextureList); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3cd7ccd3ee..16611734c2 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1696,6 +1696,8 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) mNeedsAux = FALSE; destroyRawImage(); } + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + gTextureList.recalcImageDecodePriority(this); return res; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 88777fbc15..1718435225 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -710,6 +710,8 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy addImageToList(new_image); mUUIDMap[key] = new_image; new_image->setTextureListType(tex_type); + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + gTextureList.recalcImageDecodePriority(new_image); } @@ -721,6 +723,9 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) { mCallbackList.erase(image); } + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + mImagesWithChangedPriorities.erase(image); + LLTextureKey key(image->getID(), (ETexListType)image->getTextureListType()); llverify(mUUIDMap.erase(key) == 1); sNumImages--; @@ -855,121 +860,252 @@ void LLViewerTextureList::clearFetchingRequests() } } +// FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) +// NOTE: previous version retained as single block comment, changes extend to the end of updateOneImageDecodePriority +// void LLViewerTextureList::updateImagesDecodePriorities() +// { +// // Update the decode priority for N images each frame +// { +// F32 lazy_flush_timeout = 30.f; // stop decoding +// F32 max_inactive_time = 20.f; // actually delete +// S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + +// //reset imagep->getLastReferencedTimer() when screen is showing the progress view to avoid removing pre-fetched textures too soon. +// bool reset_timer = gViewerWindow->getProgressView()->getVisible(); + +// static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 +// const size_t max_update_count = llmin((S32) (MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds.value()) + 1, MAX_PRIO_UPDATES); +// S32 update_counter = llmin(max_update_count, mUUIDMap.size()); +// uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); +// while ((update_counter-- > 0) && !mUUIDMap.empty()) +// { +// if (iter == mUUIDMap.end()) +// { +// iter = mUUIDMap.begin(); +// } +// mLastUpdateKey = iter->first; +// LLPointer imagep = iter->second; +// ++iter; // safe to increment now + +// if(imagep->isInDebug() || imagep->isUnremovable()) +// { +// update_counter--; +// continue; //is in debug, ignore. +// } + +// // +// // Flush formatted images using a lazy flush +// // +// S32 num_refs = imagep->getNumRefs(); +// if (num_refs == min_refs) +// { +// if(reset_timer) +// { +// imagep->getLastReferencedTimer()->reset(); +// } +// else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) +// { +// // Remove the unused image from the image list +// deleteImage(imagep); +// imagep = NULL; // should destroy the image +// } +// continue; +// } +// else +// { +// if(imagep->hasSavedRawImage()) +// { +// if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) +// { +// imagep->destroySavedRawImage() ; +// } +// } + +// if(imagep->isDeleted()) +// { +// continue ; +// } +// else if(imagep->isDeletionCandidate()) +// { +// imagep->destroyTexture() ; +// continue ; +// } +// else if(imagep->isInactive()) +// { +// if(reset_timer) +// { +// imagep->getLastReferencedTimer()->reset(); +// } +// else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) +// { +// imagep->setDeletionCandidate() ; +// } +// continue ; +// } +// else +// { +// imagep->getLastReferencedTimer()->reset(); + +// //reset texture state. +// imagep->setInactive() ; +// } +// } + +// if (!imagep->isInImageList()) +// { +// continue; +// } +// if(imagep->isInFastCacheList()) +// { +// continue; //wait for loading from the fast cache. +// } + +// imagep->processTextureStats(); +// F32 old_priority = imagep->getDecodePriority(); +// F32 old_priority_test = llmax(old_priority, 0.0f); +// F32 decode_priority = imagep->calcDecodePriority(); +// F32 decode_priority_test = llmax(decode_priority, 0.0f); +// // Ignore < 20% difference +// if ((decode_priority_test < old_priority_test * .8f) || +// (decode_priority_test > old_priority_test * 1.25f)) +// { +// mImageList.erase(imagep) ; +// imagep->setDecodePriority(decode_priority); +// mImageList.insert(imagep); +// } +// } +// } +// } + +void LLViewerTextureList::recalcImageDecodePriority(LLPointer image) +{ + mImagesWithChangedPriorities.insert(image); +} + void LLViewerTextureList::updateImagesDecodePriorities() { // Update the decode priority for N images each frame + static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 + const size_t max_update_count = llmin((S32)(MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds.value()) + 1, MAX_PRIO_UPDATES); + S32 update_counter = llmin(max_update_count, (mImagesWithChangedPriorities.size() + mUUIDMap.size())); + + // First, process images whose decode priorities may have changed recently + image_list_t::iterator iter2 = mImagesWithChangedPriorities.begin(); + while ((update_counter-- > 0) && (iter2 != mImagesWithChangedPriorities.end())) { - F32 lazy_flush_timeout = 30.f; // stop decoding - F32 max_inactive_time = 20.f; // actually delete - S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + LLPointer imagep = *iter2; + iter2 = mImagesWithChangedPriorities.erase(iter2); + updateOneImageDecodePriority(imagep); + } - //reset imagep->getLastReferencedTimer() when screen is showing the progress view to avoid removing pre-fetched textures too soon. - bool reset_timer = gViewerWindow->getProgressView()->getVisible(); - - static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 - const size_t max_update_count = llmin((S32) (MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds.value()) + 1, MAX_PRIO_UPDATES); - S32 update_counter = llmin(max_update_count, mUUIDMap.size()); - uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); - while ((update_counter-- > 0) && !mUUIDMap.empty()) + // Second, process all of the images + uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); + while ((update_counter-- > 0) && !mUUIDMap.empty()) + { + if (iter == mUUIDMap.end()) { - if (iter == mUUIDMap.end()) - { - iter = mUUIDMap.begin(); - } - mLastUpdateKey = iter->first; - LLPointer imagep = iter->second; - ++iter; // safe to increment now - - if(imagep->isInDebug() || imagep->isUnremovable()) - { - update_counter--; - continue; //is in debug, ignore. - } - - // - // Flush formatted images using a lazy flush - // - S32 num_refs = imagep->getNumRefs(); - if (num_refs == min_refs) - { - if(reset_timer) - { - imagep->getLastReferencedTimer()->reset(); - } - else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) - { - // Remove the unused image from the image list - deleteImage(imagep); - imagep = NULL; // should destroy the image - } - continue; - } - else - { - if(imagep->hasSavedRawImage()) - { - if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) - { - imagep->destroySavedRawImage() ; - } - } - - if(imagep->isDeleted()) - { - continue ; - } - else if(imagep->isDeletionCandidate()) - { - imagep->destroyTexture() ; - continue ; - } - else if(imagep->isInactive()) - { - if(reset_timer) - { - imagep->getLastReferencedTimer()->reset(); - } - else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) - { - imagep->setDeletionCandidate() ; - } - continue ; - } - else - { - imagep->getLastReferencedTimer()->reset(); - - //reset texture state. - imagep->setInactive() ; - } - } - - if (!imagep->isInImageList()) - { - continue; - } - if(imagep->isInFastCacheList()) - { - continue; //wait for loading from the fast cache. - } - - imagep->processTextureStats(); - F32 old_priority = imagep->getDecodePriority(); - F32 old_priority_test = llmax(old_priority, 0.0f); - F32 decode_priority = imagep->calcDecodePriority(); - F32 decode_priority_test = llmax(decode_priority, 0.0f); - // Ignore < 20% difference - if ((decode_priority_test < old_priority_test * .8f) || - (decode_priority_test > old_priority_test * 1.25f)) - { - mImageList.erase(imagep) ; - imagep->setDecodePriority(decode_priority); - mImageList.insert(imagep); - } + iter = mUUIDMap.begin(); } + mLastUpdateKey = iter->first; + LLPointer imagep = iter->second; + ++iter; // safe to increment now + updateOneImageDecodePriority(imagep); } } +void LLViewerTextureList::updateOneImageDecodePriority(LLPointer imagep) +{ + const F32 lazy_flush_timeout = 30.f; // stop decoding + const F32 max_inactive_time = 20.f; // actually delete + const S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + + bool reset_timer = gViewerWindow->getProgressView()->getVisible(); + + if(imagep->isInDebug() || imagep->isUnremovable()) + { + return; //is in debug, ignore. + } + // + // Flush formatted images using a lazy flush + // + S32 num_refs = imagep->getNumRefs(); + if (num_refs == min_refs) + { + if(reset_timer) + { + imagep->getLastReferencedTimer()->reset(); + } + else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) + { + // Remove the unused image from the image list + deleteImage(imagep); + imagep = NULL; // should destroy the image + } + return; + } + else + { + if(imagep->hasSavedRawImage()) + { + if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) + { + imagep->destroySavedRawImage() ; + } + } + + if(imagep->isDeleted()) + { + return; + } + else if(imagep->isDeletionCandidate()) + { + imagep->destroyTexture() ; + return; + } + else if(imagep->isInactive()) + { + if(reset_timer) + { + imagep->getLastReferencedTimer()->reset(); + } + else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) + { + imagep->setDeletionCandidate() ; + } + return; + } + else + { + imagep->getLastReferencedTimer()->reset(); + //reset texture state. + imagep->setInactive() ; + } + } + if (!imagep->isInImageList()) + { + return; + } + if(imagep->isInFastCacheList()) + { + return; //wait for loading from the fast cache. + } + + imagep->processTextureStats(); + F32 old_priority = imagep->getDecodePriority(); + F32 old_priority_test = llmax(old_priority, 0.0f); + F32 decode_priority = imagep->calcDecodePriority(); + F32 decode_priority_test = llmax(decode_priority, 0.0f); + // Ignore < 20% difference + if ((decode_priority_test < old_priority_test * .8f) || + (decode_priority_test > old_priority_test * 1.25f)) + { + mImageList.erase(imagep) ; + imagep->setDecodePriority(decode_priority); + mImageList.insert(imagep); + } +} +// FIRE-30559 + void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level) { if(!tex->setDebugFetching(debug_level)) diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 6feae4d897..ca26883763 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -34,6 +34,7 @@ #include "llui.h" #include #include +#include #include "lluiimage.h" const U32 LL_IMAGE_REZ_LOSSLESS_CUTOFF = 128; @@ -147,6 +148,8 @@ public: private: void updateImagesDecodePriorities(); + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + void updateOneImageDecodePriority(LLPointer imagep); F32 updateImagesCreateTextures(F32 max_time); F32 updateImagesFetchTextures(F32 max_time); void updateImagesUpdateStats(); @@ -219,7 +222,12 @@ public: // Fast cache stats static U32 sNumFastCacheReads; - + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + // Recalculate the image's Decode Priority. + // (We'll get to the image eventually even if this method isn't called, but this way it goes + // to the head(-ish) of the line.) + void recalcImageDecodePriority(LLPointer image); + // private: typedef std::map< LLTextureKey, LLPointer > uuid_map_t; uuid_map_t mUUIDMap; @@ -228,7 +236,11 @@ private: typedef std::set, LLViewerFetchedTexture::Compare> image_priority_list_t; image_priority_list_t mImageList; - + // FIRE-30559 texture fetch speedup for user previews (based on patches from Oren Hurvitz) + // Images that should be handled first in updateImagesDecodePriorities() + image_list_t mImagesWithChangedPriorities; + // + // simply holds on to LLViewerFetchedTexture references to stop them from being purged too soon std::set > mImagePreloads;