diff options
Diffstat (limited to 'indra/newview/llviewertexturelist.cpp')
-rw-r--r-- | indra/newview/llviewertexturelist.cpp | 322 |
1 files changed, 166 insertions, 156 deletions
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index b90c1868fc..08e9151940 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -70,6 +70,8 @@ S32 LLViewerTextureList::sNumImages = 0; LLViewerTextureList gTextureList; +extern LLGLSLShader gCopyProgram; + ETexListType get_element_type(S32 priority) { return (priority == LLViewerFetchedTexture::BOOST_ICON || priority == LLViewerFetchedTexture::BOOST_THUMBNAIL) ? TEX_LIST_SCALE : TEX_LIST_STANDARD; @@ -121,6 +123,9 @@ void LLViewerTextureList::doPreloadImages() LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); LLUIImageList* image_list = LLUIImageList::getInstance(); + // Set default particle texture + LLViewerFetchedTexture::sDefaultParticleImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); + // Set the default flat normal map // BLANK_OBJECT_NORMAL has a version on dataserver, but it has compression artifacts LLViewerFetchedTexture::sFlatNormalImagep = @@ -185,13 +190,6 @@ void LLViewerTextureList::doPreloadImages() image->setAddressMode(LLTexUnit::TAM_CLAMP); mImagePreloads.insert(image); } - - LLPointer<LLImageRaw> img_blak_square_tex(new LLImageRaw(2, 2, 3)); - memset(img_blak_square_tex->getData(), 0, img_blak_square_tex->getDataSize()); - LLPointer<LLViewerFetchedTexture> img_blak_square(new LLViewerFetchedTexture(img_blak_square_tex, FTT_DEFAULT, false)); - gBlackSquareID = img_blak_square->getID(); - img_blak_square->setUnremovable(true); - addImage(img_blak_square, TEX_LIST_STANDARD); } static std::string get_texture_list_name() @@ -296,7 +294,7 @@ void LLViewerTextureList::shutdown() // Write out list of currently loaded textures for precaching on startup typedef std::set<std::pair<S32,LLViewerFetchedTexture*> > image_area_list_t; image_area_list_t image_area_list; - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ++iter) { LLViewerFetchedTexture* image = *iter; @@ -352,8 +350,11 @@ void LLViewerTextureList::shutdown() mCallbackList.clear(); // Flush all of the references - mLoadingStreamList.clear(); - mCreateTextureList.clear(); + while (!mCreateTextureList.empty()) + { + mCreateTextureList.front()->mCreatePending = false; + mCreateTextureList.pop(); + } mFastCacheList.clear(); mUUIDMap.clear(); @@ -367,7 +368,7 @@ void LLViewerTextureList::dump() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL; - for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) + for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) { LLViewerFetchedTexture* image = *it; @@ -381,15 +382,9 @@ void LLViewerTextureList::dump() } } -void LLViewerTextureList::destroyGL(bool save_state) -{ - LLImageGL::destroyGL(save_state); -} - -void LLViewerTextureList::restoreGL() +void LLViewerTextureList::destroyGL() { - llassert_always(mInitialized) ; - LLImageGL::restoreGL(); + LLImageGL::destroyGL(); } /* Vertical tab container button image IDs @@ -411,6 +406,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& const LLUUID& force_id) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LL_PROFILE_ZONE_TEXT(filename.c_str(), filename.size()); if(!mInitialized) { return NULL ; @@ -726,6 +722,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) size_t count = 0; if (image->isInImageList()) { + image->setInImageList(false); count = mImageList.erase(image) ; if(count != 1) { @@ -762,8 +759,6 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) << LL_ENDL; } } - - image->setInImageList(false) ; } void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type) @@ -809,15 +804,6 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) /////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////// - -void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image) -{ - mDirtyTextureList.insert(image); -} - -//////////////////////////////////////////////////////////////////////////// - void LLViewerTextureList::updateImages(F32 max_time) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -834,7 +820,7 @@ void LLViewerTextureList::updateImages(F32 max_time) } cleared = false; - LLAppViewer::getTextureFetch()->setTextureBandwidth(LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED).value()); + LLAppViewer::getTextureFetch()->setTextureBandwidth((F32)LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED).value()); { using namespace LLStatViewer; @@ -858,12 +844,6 @@ void LLViewerTextureList::updateImages(F32 max_time) //handle results from decode threads updateImagesCreateTextures(remaining_time); - if (!mDirtyTextureList.empty()) - { - gPipeline.dirtyPoolObjectTextures(mDirtyTextureList); - mDirtyTextureList.clear(); - } - bool didone = false; for (image_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) @@ -895,7 +875,7 @@ void LLViewerTextureList::clearFetchingRequests() LLAppViewer::getTextureFetch()->deleteAllRequests(); - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ++iter) { LLViewerFetchedTexture* imagep = *iter; @@ -903,106 +883,137 @@ void LLViewerTextureList::clearFetchingRequests() } } -static void touch_texture(LLViewerFetchedTexture* tex, F32 vsize) -{ - if (tex) - { - tex->addTextureStats(vsize); - } -} - extern bool gCubeSnapshot; -void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imagep) +void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imagep, bool flush_images) { - if (imagep->isInDebug() || imagep->isUnremovable()) + llassert(!gCubeSnapshot); + + if (imagep->getBoostLevel() < LLViewerFetchedTexture::BOOST_HIGH) // don't bother checking face list for boosted textures { - //update_counter--; - return; //is in debug, ignore. - } + static LLCachedControl<F32> bias_distance_scale(gSavedSettings, "TextureBiasDistanceScale", 1.f); + static LLCachedControl<F32> texture_scale_min(gSavedSettings, "TextureScaleMinAreaFactor", 0.04f); + static LLCachedControl<F32> texture_scale_max(gSavedSettings, "TextureScaleMaxAreaFactor", 25.f); - llassert(!gCubeSnapshot); + F32 max_vsize = 0.f; + bool on_screen = false; - static LLCachedControl<F32> bias_distance_scale(gSavedSettings, "TextureBiasDistanceScale", 1.f); - static LLCachedControl<F32> texture_scale_min(gSavedSettings, "TextureScaleMinAreaFactor", 0.04f); - static LLCachedControl<F32> texture_scale_max(gSavedSettings, "TextureScaleMaxAreaFactor", 25.f); + U32 face_count = 0; - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE - { + F32 bias = (F32) llroundf(powf(4, LLViewerTexture::sDesiredDiscardBias - 1.f)); + + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { for (S32 fi = 0; fi < imagep->getNumFaces(i); ++fi) { LLFace* face = (*(imagep->getFaceList(i)))[fi]; - if (face && face->getViewerObject() && face->getTextureEntry()) + if (face && face->getViewerObject()) { + ++face_count; + F32 radius; + F32 cos_angle_to_view_dir; + static LLCachedControl<F32> bias_unimportant_threshold(gSavedSettings, "TextureBiasUnimportantFactor", 0.25f); + + if ((gFrameCount - face->mLastTextureUpdate) > 10) + { // only call calcPixelArea at most once every 10 frames for a given face + // this helps eliminate redundant calls to calcPixelArea for faces that have multiple textures + // assigned to them, such as is the case with GLTF materials or Blinn-Phong materials + face->mInFrustum = face->calcPixelArea(cos_angle_to_view_dir, radius); + face->mLastTextureUpdate = gFrameCount; + } + F32 vsize = face->getPixelArea(); + on_screen = face->mInFrustum; + // Scale desired texture resolution higher or lower depending on texture scale // // Minimum usage examples: a 1024x1024 texture with aplhabet, runing string // shows one letter at a time // // Maximum usage examples: huge chunk of terrain repeats texture - const LLTextureEntry* te = face->getTextureEntry(); + // TODO: make this work with the GLTF texture transforms + S32 te_offset = face->getTEOffset(); // offset is -1 if not inited + LLViewerObject* objp = face->getViewerObject(); + const LLTextureEntry* te = (te_offset < 0 || te_offset >= objp->getNumTEs()) ? nullptr : objp->getTE(te_offset); F32 min_scale = te ? llmin(fabsf(te->getScaleS()), fabsf(te->getScaleT())) : 1.f; - min_scale = llclamp(min_scale*min_scale, texture_scale_min(), texture_scale_max()); - + min_scale = llclamp(min_scale * min_scale, texture_scale_min(), texture_scale_max()); vsize /= min_scale; - vsize /= LLViewerTexture::sDesiredDiscardBias; - vsize /= llmax(1.f, (LLViewerTexture::sDesiredDiscardBias-1.f) * (1.f + face->getDrawable()->mDistanceWRTCamera * bias_distance_scale)); - F32 radius; - F32 cos_angle_to_view_dir; - bool in_frustum = face->calcPixelArea(cos_angle_to_view_dir, radius); - if (!in_frustum || !face->getDrawable()->isVisible()) - { // further reduce by discard bias when off screen or occluded - vsize /= LLViewerTexture::sDesiredDiscardBias; - } - // if a GLTF material is present, ignore that face - // as far as this texture stats go, but update the GLTF material - // stats - LLFetchedGLTFMaterial* mat = te ? (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial() : nullptr; - llassert(mat == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(te->getGLTFRenderMaterial()) != nullptr); - if (mat) - { - touch_texture(mat->mBaseColorTexture, vsize); - touch_texture(mat->mNormalTexture, vsize); - touch_texture(mat->mMetallicRoughnessTexture, vsize); - touch_texture(mat->mEmissiveTexture, vsize); - } - else + // apply bias to offscreen faces all the time, but only to onscreen faces when bias is large + if (!face->mInFrustum || LLViewerTexture::sDesiredDiscardBias > 2.f) { - imagep->addTextureStats(vsize); + vsize /= bias; } + + max_vsize = llmax(max_vsize, vsize); } } } + + if (face_count > 1024) + { // this texture is used in so many places we should just boost it and not bother checking its vsize + // this is especially important because the above is not time sliced and can hit multiple ms for a single texture + imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_HIGH); + } + + if (imagep->getType() == LLViewerTexture::LOD_TEXTURE && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE) + { // conditionally reset max virtual size for unboosted LOD_TEXTURES + // this is an alternative to decaying mMaxVirtualSize over time + // that keeps textures from continously downrezzing and uprezzing in the background + + if (LLViewerTexture::sDesiredDiscardBias > 1.5f || + (!on_screen && LLViewerTexture::sDesiredDiscardBias > 1.f)) + { + imagep->mMaxVirtualSize = 0.f; + } + } + + imagep->addTextureStats(max_vsize); } - //imagep->setDebugText(llformat("%.3f - %d", sqrtf(imagep->getMaxVirtualSize()), imagep->getBoostLevel())); +#if 0 + imagep->setDebugText(llformat("%d/%d - %d/%d -- %d/%d", + (S32)sqrtf(max_vsize), + (S32)sqrtf(imagep->mMaxVirtualSize), + imagep->getDiscardLevel(), + imagep->getDesiredDiscardLevel(), + imagep->getWidth(), + imagep->getFullWidth())); +#endif - 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 + // make sure to addTextureStats for any spotlights that are using this texture + for (S32 vi = 0; vi < imagep->getNumVolumes(LLRender::LIGHT_TEX); ++vi) + { + LLVOVolume* volume = (*imagep->getVolumeList(LLRender::LIGHT_TEX))[vi]; + volume->updateSpotLightPriority(); + } + + F32 max_inactive_time = 20.f; // inactive time before deleting saved raw image + S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, and 1 for "entries" in updateImagesFetchTextures + + F32 lazy_flush_timeout = 30.f; // delete unused images after 30 seconds // // Flush formatted images using a lazy flush // S32 num_refs = imagep->getNumRefs(); - if (num_refs == min_refs) + if (num_refs <= min_refs && flush_images) { if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) { // Remove the unused image from the image list deleteImage(imagep); - imagep = NULL; // should destroy the image + return; } - return; } else { + // still referenced outside of image list, reset timer + imagep->getLastReferencedTimer()->reset(); + if (imagep->hasSavedRawImage()) { if (imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) @@ -1015,26 +1026,6 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag { return; } - else if (imagep->isDeletionCandidate()) - { - imagep->destroyTexture(); - return; - } - else if (imagep->isInactive()) - { - if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) - { - imagep->setDeletionCandidate(); - } - return; - } - else - { - imagep->getLastReferencedTimer()->reset(); - - //reset texture state. - imagep->setInactive(); - } } if (!imagep->isInImageList()) @@ -1049,20 +1040,6 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag imagep->processTextureStats(); } -void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(!tex->setDebugFetching(debug_level)) - { - return; - } - - const F32 DEBUG_PRIORITY = 100000.f; - removeImageFromList(tex); - tex->mMaxVirtualSize = DEBUG_PRIORITY; - addImageToList(tex); -} - F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -1074,22 +1051,65 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) // LLTimer create_timer; - image_list_t::iterator enditer = mCreateTextureList.begin(); - for (image_list_t::iterator iter = mCreateTextureList.begin(); - iter != mCreateTextureList.end();) + + if (!mDownScaleQueue.empty() && gPipeline.mDownResMap.isComplete()) { - image_list_t::iterator curiter = iter++; - enditer = iter; - LLViewerFetchedTexture *imagep = *curiter; + // just in case we downres textures, bind downresmap and copy program + gPipeline.mDownResMap.bindTarget(); + gCopyProgram.bind(); + gPipeline.mScreenTriangleVB->setBuffer(); + + // give time to downscaling first -- if mDownScaleQueue is not empty, we're running out of memory and need + // to free up memory by discarding off screen textures quickly + + // do at least 5 and make sure we don't get too far behind even if it violates + // the time limit. If we don't downscale quickly the viewer will hit swap and may + // freeze. + S32 min_count = (S32)mCreateTextureList.size() / 20 + 5; + + while (!mDownScaleQueue.empty()) + { + LLViewerFetchedTexture* image = mDownScaleQueue.front(); + llassert(image->mDownScalePending); + + LLImageGL* img = image->getGLTexture(); + if (img && img->getHasGLTexture()) + { + img->scaleDown(image->getDesiredDiscardLevel()); + } + + image->mDownScalePending = false; + mDownScaleQueue.pop(); + + if (create_timer.getElapsedTimeF32() > max_time && --min_count <= 0) + { + break; + } + } + + gCopyProgram.unbind(); + gPipeline.mDownResMap.flush(); + } + + // do at least 5 and make sure we don't get too far behind even if it violates + // the time limit. Textures pending creation have a copy of their texture data + // in system memory, so we don't want to let them pile up. + S32 min_count = (S32) mCreateTextureList.size() / 20 + 5; + + while (!mCreateTextureList.empty()) + { + LLViewerFetchedTexture *imagep = mCreateTextureList.front(); + llassert(imagep->mCreatePending); imagep->createTexture(); imagep->postCreateTexture(); + imagep->mCreatePending = false; + mCreateTextureList.pop(); - if (create_timer.getElapsedTimeF32() > max_time) + if (create_timer.getElapsedTimeF32() > max_time && --min_count <= 0) { break; } } - mCreateTextureList.erase(mCreateTextureList.begin(), enditer); return create_timer.getElapsedTimeF32(); } @@ -1123,18 +1143,12 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time) void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if(!imagep) + if(!imagep || gCubeSnapshot) { return ; } - if(imagep->isInImageList()) - { - removeImageFromList(imagep); - } imagep->processTextureStats(); - imagep->sMaxVirtualSize = LLViewerFetchedTexture::sMaxVirtualSize; - addImageToList(imagep); return ; } @@ -1142,18 +1156,22 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep) F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + typedef std::vector<LLPointer<LLViewerFetchedTexture> > entries_list_t; entries_list_t entries; // update N textures at beginning of mImageList U32 update_count = 0; static const S32 MIN_UPDATE_COUNT = gSavedSettings.getS32("TextureFetchUpdateMinCount"); // default: 32 - // WIP -- dumb code here + + // NOTE: a texture may be deleted as a side effect of some of these updates + // Deletion rules check ref count, so be careful not to hold any LLPointer references to the textures here other than the one in entries. + //update MIN_UPDATE_COUNT or 5% of other textures, whichever is greater update_count = llmax((U32) MIN_UPDATE_COUNT, (U32) mUUIDMap.size()/20); update_count = llmin(update_count, (U32) mUUIDMap.size()); - { + { // copy entries out of UUID map to avoid iterator invalidation from deletion inside updateImageDecodeProiroty or updateFetch below LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vtluift - copy"); // copy entries out of UUID map for updating @@ -1176,30 +1194,22 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) LLTimer timer; - LLPointer<LLViewerTexture> last_imagep = nullptr; - for (auto& imagep : entries) { - if (imagep->getNumRefs() > 1) // make sure this image hasn't been deleted before attempting to update (may happen as a side effect of some other image updating) + mLastUpdateKey = LLTextureKey(imagep->getID(), (ETexListType)imagep->getTextureListType()); + if (imagep->getNumRefs() > 1) // make sure this image hasn't been deleted before attempting to update (may happen as a side effect of some other image updating) { updateImageDecodePriority(imagep); imagep->updateFetch(); } - last_imagep = imagep; - if (timer.getElapsedTimeF32() > max_time) { break; } } - if (last_imagep) - { - mLastUpdateKey = LLTextureKey(last_imagep->getID(), (ETexListType)last_imagep->getTextureListType()); - } - return timer.getElapsedTimeF32(); } @@ -1208,7 +1218,7 @@ void LLViewerTextureList::updateImagesUpdateStats() LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (mForceResetTextureStats) { - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; @@ -1228,7 +1238,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) // Update texture stats and priorities std::vector<LLPointer<LLViewerFetchedTexture> > image_list; - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; @@ -1248,7 +1258,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) image_list.clear(); // Update fetch (decode) - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; @@ -1275,7 +1285,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) } } // Update fetch again - for (image_priority_list_t::iterator iter = mImageList.begin(); + for (image_list_t::iterator iter = mImageList.begin(); iter != mImageList.end(); ) { LLViewerFetchedTexture* imagep = *iter++; |