summaryrefslogtreecommitdiff
path: root/indra/newview/llviewertexturelist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewertexturelist.cpp')
-rw-r--r--indra/newview/llviewertexturelist.cpp671
1 files changed, 412 insertions, 259 deletions
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 4c1dc7eb71..752cfb3884 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;
@@ -91,14 +93,14 @@ LLTextureKey::LLTextureKey(LLUUID id, ETexListType tex_type)
///////////////////////////////////////////////////////////////////////////////
LLViewerTextureList::LLViewerTextureList()
- : mForceResetTextureStats(FALSE),
- mInitialized(FALSE)
+ : mForceResetTextureStats(false),
+ mInitialized(false)
{
}
void LLViewerTextureList::init()
{
- mInitialized = TRUE ;
+ mInitialized = true ;
sNumImages = 0;
doPreloadImages();
}
@@ -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 =
@@ -139,12 +144,12 @@ void LLViewerTextureList::doPreloadImages()
image_list->initFromFile();
// turn off clamping and bilinear filtering for uv picking images
- //LLViewerFetchedTexture* uv_test = preloadUIImage("uv_test1.tga", LLUUID::null, FALSE);
- //uv_test->setClamp(FALSE, FALSE);
- //uv_test->setMipFilterNearest(TRUE, TRUE);
- //uv_test = preloadUIImage("uv_test2.tga", LLUUID::null, FALSE);
- //uv_test->setClamp(FALSE, FALSE);
- //uv_test->setMipFilterNearest(TRUE, TRUE);
+ //LLViewerFetchedTexture* uv_test = preloadUIImage("uv_test1.tga", LLUUID::null, false);
+ //uv_test->setClamp(false, false);
+ //uv_test->setMipFilterNearest(true, true);
+ //uv_test = preloadUIImage("uv_test2.tga", LLUUID::null, false);
+ //uv_test->setClamp(false, false);
+ //uv_test->setMipFilterNearest(true, true);
LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI);
if (image)
@@ -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()
@@ -231,7 +229,7 @@ void LLViewerTextureList::doPrefetchImages()
LLViewerTextureManager::getFetchedTexture(IMG_SHOT);
LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF);
- LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI);
+ LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, true, LLGLTexture::BOOST_UI);
LLViewerFetchedTexture::sSmokeImagep->setNoDelete();
LLStandardBumpmap::addstandard();
@@ -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,22 +350,46 @@ 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();
mImageList.clear();
- mInitialized = FALSE ; //prevent loading textures again.
+ mInitialized = false ; //prevent loading textures again.
}
+namespace
+{
+
+std::string tex_name_as_string(const LLViewerFetchedTexture* image)
+{
+ if (!image->getGLTexture()) { return std::string("N/A"); }
+ return std::to_string(image->getGLTexture()->getTexName());
+}
+
+const std::string& tex_label_as_string(const LLViewerFetchedTexture* image, std::string& label)
+{
+ bool error;
+ image->getGLObjectLabel(label, error);
+ if (error) { label.assign("N/A"); }
+ return label;
+}
+
+};
+
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)
+ LL_INFOS() << __FUNCTION__ << "()" << LL_ENDL;
+
+ std::string label;
+ for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
{
LLViewerFetchedTexture* image = *it;
@@ -377,19 +399,16 @@ void LLViewerTextureList::dump()
<< " discard " << image->getDiscardLevel()
<< " desired " << image->getDesiredDiscardLevel()
<< " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
+ << " faces " << image->getTotalNumFaces()
+ << " texname " << tex_name_as_string(image)
+ << " label \"" << tex_label_as_string(image, label) << "\""
<< LL_ENDL;
}
}
-void LLViewerTextureList::destroyGL(BOOL save_state)
+void LLViewerTextureList::destroyGL()
{
- LLImageGL::destroyGL(save_state);
-}
-
-void LLViewerTextureList::restoreGL()
-{
- llassert_always(mInitialized) ;
- LLImageGL::restoreGL();
+ LLImageGL::destroyGL();
}
/* Vertical tab container button image IDs
@@ -403,7 +422,7 @@ void LLViewerTextureList::restoreGL()
LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename,
FTType f_type,
- BOOL usemipmaps,
+ bool usemipmaps,
LLViewerTexture::EBoostLevel boost_priority,
S8 texture_type,
LLGLint internal_format,
@@ -411,6 +430,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 ;
@@ -421,17 +441,22 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
{
LL_WARNS() << "Failed to find local image file: " << filename << LL_ENDL;
LLViewerTexture::EBoostLevel priority = LLGLTexture::BOOST_UI;
- return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, priority);
+ return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, true, priority);
}
std::string url = "file://" + full_path;
- return getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
+ LLViewerFetchedTexture* tex = getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
+ if (gDebugTextureLabelLocalFilesSession)
+ {
+ gTextureList.mNameTextureList.push_back(LLViewerTextureList::NameElement(tex, filename));
+ }
+ return tex;
}
LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url,
FTType f_type,
- BOOL usemipmaps,
+ bool usemipmaps,
LLViewerTexture::EBoostLevel boost_priority,
S8 texture_type,
LLGLint internal_format,
@@ -518,10 +543,43 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
return imagep;
}
+LLImageRaw* LLViewerTextureList::getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype)
+{
+ LLPointer<LLImageFormatted> image = LLImageFormatted::loadFromMemory(data, size, mimetype);
+
+ if (image)
+ {
+ LLImageRaw* raw_image = new LLImageRaw();
+ image->decode(raw_image, 0.f);
+ return raw_image;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+LLViewerFetchedTexture* LLViewerTextureList::getImageFromMemory(const U8* data, U32 size, std::string_view mimetype)
+{
+ LLPointer<LLImageRaw> raw_image = getRawImageFromMemory(data, size, mimetype);
+ if (raw_image.notNull())
+ {
+ LLViewerFetchedTexture* imagep = new LLViewerFetchedTexture(raw_image, FTT_LOCAL_FILE, true);
+ addImage(imagep, TEX_LIST_STANDARD);
+
+ imagep->dontDiscard();
+ imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_PREVIEW);
+ return imagep;
+ }
+ else
+ {
+ return nullptr;
+ }
+}
LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
FTType f_type,
- BOOL usemipmaps,
+ bool usemipmaps,
LLViewerTexture::EBoostLevel boost_priority,
S8 texture_type,
LLGLint internal_format,
@@ -540,7 +598,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
if (image_id.isNull())
{
- return (LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI));
+ return (LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, true, LLGLTexture::BOOST_UI));
}
LLPointer<LLViewerFetchedTexture> imagep = findImage(image_id, get_element_type(boost_priority));
@@ -578,7 +636,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
//when this function is called, there is no such texture in the gTextureList with image_id.
LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
FTType f_type,
- BOOL usemipmaps,
+ bool usemipmaps,
LLViewerTexture::EBoostLevel boost_priority,
S8 texture_type,
LLGLint internal_format,
@@ -631,8 +689,8 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
imagep->forceActive() ;
}
- mFastCacheList.insert(imagep);
- imagep->setInFastCacheList(true);
+ mFastCacheList.insert(imagep);
+ imagep->setInFastCacheList(true);
return imagep ;
}
@@ -675,12 +733,12 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
}
else
{
- if((mImageList.insert(image)).second != true)
- {
+ if (!(mImageList.insert(image)).second)
+ {
LL_WARNS() << "Error happens when insert image " << image->getID() << " into mImageList!" << LL_ENDL ;
+ }
+ image->setInImageList(true);
}
- image->setInImageList(TRUE) ;
-}
}
void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
@@ -690,9 +748,10 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
llassert_always(mInitialized) ;
llassert(image);
- S32 count = 0;
+ size_t count = 0;
if (image->isInImageList())
{
+ image->setInImageList(false);
count = mImageList.erase(image) ;
if(count != 1)
{
@@ -729,8 +788,6 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
<< LL_ENDL;
}
}
-
- image->setInImageList(FALSE) ;
}
void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type)
@@ -776,32 +833,23 @@ 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;
- static BOOL cleared = FALSE;
+ static bool cleared = false;
if(gTeleportDisplay)
{
if(!cleared)
{
clearFetchingRequests();
gPipeline.clearRebuildGroups();
- cleared = TRUE;
+ cleared = true;
}
return;
}
- cleared = FALSE;
+ 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;
@@ -825,11 +873,9 @@ void LLViewerTextureList::updateImages(F32 max_time)
//handle results from decode threads
updateImagesCreateTextures(remaining_time);
- if (!mDirtyTextureList.empty())
- {
- gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
- mDirtyTextureList.clear();
- }
+ // Label all images (if enabled)
+ updateImagesNameTextures();
+ labelAll();
bool didone = false;
for (image_list_t::iterator iter = mCallbackList.begin();
@@ -862,7 +908,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;
@@ -870,104 +916,137 @@ void LLViewerTextureList::clearFetchingRequests()
}
}
-static void touch_texture(LLViewerFetchedTexture* tex, F32 vsize)
-{
- if (tex)
- {
- tex->addTextureStats(vsize);
- }
-}
-
-extern BOOL gCubeSnapshot;
+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);
+ 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 (U32 fi = 0; fi < imagep->getNumFaces(i); ++fi)
+ 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();
- // scale desired texture resolution higher or lower depending on texture scale
- const LLTextureEntry* te = face->getTextureEntry();
+ 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
+ // 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 = llmax(min_scale*min_scale, 0.1f);
-
+ min_scale = llclamp(min_scale * min_scale, texture_scale_min(), texture_scale_max());
vsize /= min_scale;
-#if LL_DARWIN
- vsize /= 1.f + LLViewerTexture::sDesiredDiscardBias*(1.f+face->getDrawable()->mDistanceWRTCamera*bias_distance_scale);
-#else
- 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;
- }
-#endif
- // 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)
+ // apply bias to offscreen faces all the time, but only to onscreen faces when bias is large
+ if (!face->mInFrustum || LLViewerTexture::sDesiredDiscardBias > 2.f)
{
- touch_texture(mat->mBaseColorTexture, vsize);
- touch_texture(mat->mNormalTexture, vsize);
- touch_texture(mat->mMetallicRoughnessTexture, vsize);
- touch_texture(mat->mEmissiveTexture, vsize);
- }
- else
- {
- 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
+
+ // 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 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
+ 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)
@@ -980,26 +1059,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())
@@ -1014,20 +1073,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;
@@ -1039,25 +1084,135 @@ 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();
}
+void LLViewerTextureList::updateImagesNameTextures()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ if (gGLManager.mIsDisabled) { return; }
+ static LLCachedControl<bool> debug_texture_label(gSavedSettings, "RenderDebugTextureLabel", false);
+ if (!debug_texture_label()) { return; }
+
+ static GLsizei max_length = 0;
+ if (max_length == 0) { glGetIntegerv(GL_MAX_LABEL_LENGTH, &max_length); }
+
+ auto it = mNameTextureList.begin();
+ while (it != mNameTextureList.end()) // For ALL textures needing names
+ {
+ LLViewerFetchedTexture* tex = it->mTex;
+ // Check that the texture is in the list first (otherwise it may be a dead pointer)
+ // A raw pointer ensures textures are cleaned up when this code isn't running.
+ const bool alive = mImageList.find(tex) != mImageList.end();
+
+ if (alive)
+ {
+ if (tex->hasGLTexture())
+ {
+ if(tex->getTexName())
+ {
+ tex->setGLObjectLabel(it->mPrefix, true);
+ it = mNameTextureList.erase(it); // Assume no rename needed
+ }
+ else
+ {
+ ++it; // Not ready
+ }
+ }
+ else
+ {
+ ++it; // Not ready
+ }
+ }
+ else
+ {
+ it = mNameTextureList.erase(it); // Remove dead pointer
+ }
+ }
+}
+
+void LLViewerTextureList::labelAll()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ static LLCachedControl<bool> debug_texture_label(gSavedSettings, "RenderDebugTextureLabel", false);
+ if (!debug_texture_label()) { return; }
+
+ static const std::string local_prefix = "lltexlocal";
+ static const std::string other_prefix = "lltexother";
+
+ std::string label;
+ bool error;
+ for (LLViewerFetchedTexture* image : mImageList)
+ {
+ image->getGLObjectLabel(label, error);
+ if (!error && label.empty())
+ {
+ const S32 category = image->getGLTexture()->getCategory();
+ const std::string& new_prefix = category == LLGLTexture::LOCAL ? local_prefix : other_prefix;
+ image->setGLObjectLabel(new_prefix, true);
+ }
+ }
+}
+
F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -1088,18 +1243,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 ;
}
@@ -1107,18 +1256,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
@@ -1141,30 +1294,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();
}
@@ -1173,13 +1318,13 @@ 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++;
imagep->resetTextureStats();
}
- mForceResetTextureStats = FALSE;
+ mForceResetTextureStats = false;
}
}
@@ -1193,12 +1338,12 @@ 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++;
image_list.push_back(imagep);
- imagep->setInImageList(FALSE) ;
+ imagep->setInImageList(false) ;
}
llassert_always(image_list.size() == mImageList.size()) ;
@@ -1213,7 +1358,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++;
@@ -1221,7 +1366,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
}
std::shared_ptr<LL::WorkQueue> main_queue = LLImageGLThread::sEnabledTextures ? LL::WorkQueue::getInstance("mainloop") : NULL;
// Run threads
- S32 fetch_pending = 0;
+ size_t fetch_pending = 0;
while (1)
{
LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread
@@ -1240,7 +1385,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++;
@@ -1250,6 +1395,10 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
max_time = llmax(max_time, .001f);
F32 create_time = updateImagesCreateTextures(max_time);
+ // Label all images (if enabled)
+ updateImagesNameTextures();
+ labelAll();
+
LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. "
<< " fetch_pending " << fetch_pending
<< " create_time " << create_time
@@ -1263,6 +1412,8 @@ bool LLViewerTextureList::createUploadFile(LLPointer<LLImageRaw> raw_image,
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ LLImageDataSharedLock lock(raw_image);
+
// make a copy, since convertToUploadFile scales raw image
LLPointer<LLImageRaw> scale_image = new LLImageRaw(
raw_image->getData(),
@@ -1306,63 +1457,63 @@ bool LLViewerTextureList::createUploadFile(const std::string& filename,
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
try
{
- // Load the image
- LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
- if (image.isNull())
- {
- LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
- return false;
- }
- if (!image->load(filename))
- {
- image->setLastError("Couldn't load the image to be uploaded.");
- return false;
- }
- // Decompress or expand it in a raw image structure
- LLPointer<LLImageRaw> raw_image = new LLImageRaw;
- if (!image->decode(raw_image, 0.0f))
- {
- image->setLastError("Couldn't decode the image to be uploaded.");
- return false;
- }
- // Check the image constraints
- if ((image->getComponents() != 3) && (image->getComponents() != 4))
- {
- image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
- return false;
- }
- if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
- {
- std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
- min_image_dimentions,
- min_image_dimentions,
- image->getWidth(),
- image->getHeight());
- image->setLastError(reason);
- return false;
- }
- // Convert to j2c (JPEG2000) and save the file locally
- LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
- if (compressedImage.isNull())
- {
- image->setLastError("Couldn't convert the image to jpeg2000.");
- LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL;
- return false;
- }
- if (!compressedImage->save(out_filename))
- {
- image->setLastError("Couldn't create the jpeg2000 image for upload.");
- LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
- return false;
- }
- // Test to see if the encode and save worked
- LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
- if (!integrity_test->loadAndValidate(out_filename))
- {
- image->setLastError("The created jpeg2000 image is corrupt.");
- LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL;
- return false;
- }
+ // Load the image
+ LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
+ if (image.isNull())
+ {
+ LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
+ return false;
+ }
+ if (!image->load(filename))
+ {
+ image->setLastError("Couldn't load the image to be uploaded.");
+ return false;
+ }
+ // Decompress or expand it in a raw image structure
+ LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+ if (!image->decode(raw_image, 0.0f))
+ {
+ image->setLastError("Couldn't decode the image to be uploaded.");
+ return false;
+ }
+ // Check the image constraints
+ if ((image->getComponents() != 3) && (image->getComponents() != 4))
+ {
+ image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
+ return false;
+ }
+ if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
+ {
+ std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
+ min_image_dimentions,
+ min_image_dimentions,
+ image->getWidth(),
+ image->getHeight());
+ image->setLastError(reason);
+ return false;
+ }
+ // Convert to j2c (JPEG2000) and save the file locally
+ LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
+ if (compressedImage.isNull())
+ {
+ image->setLastError("Couldn't convert the image to jpeg2000.");
+ LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL;
+ return false;
+ }
+ if (!compressedImage->save(out_filename))
+ {
+ image->setLastError("Couldn't create the jpeg2000 image for upload.");
+ LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
+ return false;
+ }
+ // Test to see if the encode and save worked
+ LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
+ if (!integrity_test->loadAndValidate( out_filename ))
+ {
+ image->setLastError("The created jpeg2000 image is corrupt.");
+ LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL;
+ return false;
+ }
}
catch (...)
{
@@ -1376,6 +1527,8 @@ bool LLViewerTextureList::createUploadFile(const std::string& filename,
LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions, bool force_square, bool force_lossless)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+ LLImageDataLock lock(raw_image);
+
if (force_square)
{
S32 biggest_side = llmax(raw_image->getWidth(), raw_image->getHeight());
@@ -1393,7 +1546,7 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
(gSavedSettings.getBOOL("LosslessJ2CUpload") &&
(raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF)))
{
- compressedImage->setReversible(TRUE);
+ compressedImage->setReversible(true);
}
@@ -1469,7 +1622,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority)
return found_it->second;
}
- const BOOL use_mips = FALSE;
+ const bool use_mips = false;
const LLRect scale_rect = LLRect::null;
const LLRect clip_rect = LLRect::null;
return loadUIImageByID(image_id, use_mips, scale_rect, clip_rect, (LLViewerTexture::EBoostLevel)priority);
@@ -1485,14 +1638,14 @@ LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priori
return found_it->second;
}
- const BOOL use_mips = FALSE;
+ const bool use_mips = false;
const LLRect scale_rect = LLRect::null;
const LLRect clip_rect = LLRect::null;
return loadUIImageByName(image_name, image_name, use_mips, scale_rect, clip_rect, (LLViewerTexture::EBoostLevel)priority);
}
LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std::string& filename,
- BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority,
+ bool use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority,
LLUIImage::EScaleStyle scale_style)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -1505,7 +1658,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std
}
LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id,
- BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority,
+ bool use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority,
LLUIImage::EScaleStyle scale_style)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -1517,7 +1670,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id,
return loadUIImage(imagep, id.asString(), use_mips, scale_rect, clip_rect, scale_style);
}
-LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect,
+LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, bool use_mips, const LLRect& scale_rect, const LLRect& clip_rect,
LLUIImage::EScaleStyle scale_style)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -1552,12 +1705,12 @@ LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const st
datap->mImageScaleRegion = scale_rect;
datap->mImageClipRegion = clip_rect;
- imagep->setLoadedCallback(onUIImageLoaded, 0, FALSE, FALSE, datap, NULL);
+ imagep->setLoadedCallback(onUIImageLoaded, 0, false, false, datap, NULL);
}
return new_imagep;
}
-LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle scale_style)
+LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, bool use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle scale_style)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
// look for existing image
@@ -1572,7 +1725,7 @@ LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::s
}
//static
-void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* user_data )
+void LLUIImageList::onUIImageLoaded( bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, bool final, void* user_data )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if(!success || !user_data)