1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060 |
- /**
- * @file llviewertexture.cpp
- * @brief Object which handles a received image (and associated texture(s))
- *
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include <utility>
- #include "llviewertexture.h"
- #include "imageids.h"
- #include "llgl.h"
- #include "llfasttimer.h"
- #include "llhost.h"
- #include "llimage.h"
- #include "llimagegl.h"
- #include "llimagebmp.h"
- #include "llimagej2c.h"
- #include "llimagetga.h"
- #include "llmediaentry.h"
- #include "llnotifications.h"
- #include "llsys.h"
- #include "lltextureentry.h"
- #include "lltexturemanagerbridge.h"
- #include "llmessage.h"
- #include "llagent.h"
- #include "llappviewer.h"
- #include "lldrawpool.h"
- #include "llpipeline.h"
- #include "lltexturecache.h"
- #include "lltexturefetch.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewermedia.h"
- #include "llviewertexturelist.h"
- #include "llvlcomposition.h" // For LLTerrain::isAsset()
- #include "llvovolume.h"
- // Static members
- LLPointer<LLViewerTexture> LLViewerTexture::sNullImagep = NULL;
- LLPointer<LLViewerTexture> LLViewerTexture::sCloudImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWhiteImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sSmokeImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sFlatNormalImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultIrradiancePBRp = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultSunImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultMoonImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultCloudsImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultCloudNoiseImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sBloomImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sOpaqueWaterImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWaterImagep = NULL;
- LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWaterNormapMapImagep = NULL;
- LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap;
- U32 LLViewerFetchedTexture::sMainThreadCreations = 0;
- U32 LLViewerFetchedTexture::sImageThreadCreations = 0;
- U32 LLViewerFetchedTexture::sImageThreadQueueSize = 0;
- bool LLViewerFetchedTexture::sImageThreadCreationsCapped = false;
- S32 LLViewerTexture::sImageCount = 0;
- S32 LLViewerTexture::sRawCount = 0;
- S32 LLViewerTexture::sAuxCount = 0;
- F32 LLViewerTexture::sDesiredDiscardBias = 0.f;
- S32 LLViewerTexture::sBoundTexMemoryMB = 0;
- S32 LLViewerTexture::sLastBoundTexMemoryMB = 0;
- S32 LLViewerTexture::sTotalTexMemoryMB = 0;
- S32 LLViewerTexture::sLastTotalTexMemoryMB = 0;
- S32 LLViewerTexture::sMaxBoundTexMemMB = 0;
- S32 LLViewerTexture::sMaxTotalTexMemMB = 0;
- S32 LLViewerTexture::sLastFreeVRAMMB = -1;
- constexpr S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64;
- constexpr S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = MAX_SCULPT_REZ *
- MAX_SCULPT_REZ;
- constexpr S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128;
- S32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256.
- S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA;
- F32 LLViewerTexture::sCurrentTime = 0.f;
- F32 LLViewerTexture::sNextDiscardBiasUpdateTime = 0.f;
- F32 LLViewerTexture::sLastDiscardDecreaseTime = 0.f;
- F32 LLViewerTexture::sLastLowMemCondTime = 0.f;
- bool LLViewerTexture::sALMTexPenalty = false;
- bool LLViewerTexture::sDontLoadVolumeTextures = false;
- // Max number of levels to reduce image quality by:
- constexpr F32 DESIRED_DISCARD_BIAS_MAX = (F32)MAX_DISCARD_LEVEL;
- //-----------------------------------------------------------------------------
- //namespace: LLViewerTextureAccess
- //-----------------------------------------------------------------------------
- LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb,
- S32 discard_level,
- bool need_imageraw,
- void* userdata,
- uuid_list_t* cb_list,
- LLViewerFetchedTexture* target,
- bool pause)
- : mCallback(cb),
- mLastUsedDiscard(MAX_DISCARD_LEVEL + 1),
- mDesiredDiscard(discard_level),
- mNeedsImageRaw(need_imageraw),
- mUserData(userdata),
- mSourceCallbackList(cb_list),
- mPaused(pause)
- {
- if (mSourceCallbackList)
- {
- mSourceCallbackList->emplace(target->getID());
- }
- }
- void LLLoadedCallbackEntry::removeTexture(LLViewerFetchedTexture* texp)
- {
- if (mSourceCallbackList)
- {
- mSourceCallbackList->erase(texp->getID());
- }
- }
- //static
- void LLLoadedCallbackEntry::cleanUpCallbackList(uuid_list_t* cb_list)
- {
- // Clear texture callbacks.
- if (cb_list && !cb_list->empty())
- {
- for (uuid_list_t::iterator it = cb_list->begin(), end = cb_list->end();
- it != end; ++it)
- {
- LLViewerFetchedTexture* tex = gTextureList.findImage(*it);
- if (tex)
- {
- tex->deleteCallbackEntry(cb_list);
- }
- }
- cb_list->clear();
- }
- }
- LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID& media_id,
- bool usemipmaps,
- LLImageGL* gl_image)
- {
- return new LLViewerMediaTexture(media_id, usemipmaps, gl_image);
- }
- LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id)
- {
- LLViewerTexture* tex;
- //search fetched texture list
- tex = gTextureList.findImage(id);
- // search media texture list
- if (!tex)
- {
- tex = LLViewerTextureManager::findMediaTexture(id);
- }
- return tex;
- }
- LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID& media_id)
- {
- return LLViewerMediaTexture::findMediaTexture(media_id);
- }
- LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id,
- LLImageGL* gl_image)
- {
- LLViewerMediaTexture* texp = LLViewerMediaTexture::findMediaTexture(id);
- if (!texp)
- {
- texp = LLViewerTextureManager::createMediaTexture(id, false, gl_image);
- }
- texp->initVirtualSize();
- return texp;
- }
- LLViewerFetchedTexture* LLViewerTextureManager::staticCast(LLGLTexture* tex,
- bool report_error)
- {
- if (!tex)
- {
- return NULL;
- }
- S8 type = tex->getType();
- if (type == LLViewerTexture::FETCHED_TEXTURE ||
- type == LLViewerTexture::LOD_TEXTURE)
- {
- return (LLViewerFetchedTexture*)tex;
- }
- if (report_error)
- {
- llerrs << "Not a fetched texture type: " << type << llendl;
- }
- return NULL;
- }
- LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(bool usemipmaps,
- bool generate_gl_tex)
- {
- LLPointer<LLViewerTexture> tex = new LLViewerTexture(usemipmaps);
- if (generate_gl_tex)
- {
- tex->generateGLTexture();
- }
- return tex;
- }
- LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const LLUUID& id,
- bool usemipmaps,
- bool generate_gl_tex)
- {
- LLPointer<LLViewerTexture> tex = new LLViewerTexture(id, usemipmaps);
- if (generate_gl_tex)
- {
- tex->generateGLTexture();
- }
- return tex;
- }
- LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const LLImageRaw* rawp,
- bool usemipmaps)
- {
- LLPointer<LLViewerTexture> tex = new LLViewerTexture(rawp, usemipmaps);
- return tex;
- }
- LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(U32 width,
- U32 height,
- U8 components,
- bool usemipmaps,
- bool generate_gl_tex)
- {
- LLPointer<LLViewerTexture> tex = new LLViewerTexture(width, height,
- components,
- usemipmaps);
- if (generate_gl_tex)
- {
- tex->generateGLTexture();
- }
- return tex;
- }
- LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* rawp,
- FTType type,
- bool usemipmaps)
- {
- LLViewerFetchedTexture* texp = new LLViewerFetchedTexture(rawp, type,
- usemipmaps);
- gTextureList.addImage(texp);
- return texp;
- }
- LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLUUID& image_id,
- FTType f_type,
- bool usemipmaps,
- LLGLTexture::EBoostLevel boost_priority,
- S8 texture_type,
- S32 internal_format,
- U32 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,
- bool usemipmaps,
- LLGLTexture::EBoostLevel boost_priority,
- S8 texture_type,
- S32 internal_format,
- U32 primary_format,
- const LLUUID& force_id)
- {
- return gTextureList.getImageFromFile(filename, usemipmaps,
- boost_priority, texture_type,
- internal_format, primary_format,
- force_id);
- }
- //static
- LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url,
- FTType f_type,
- bool usemipmaps,
- LLGLTexture::EBoostLevel boost_priority,
- S8 texture_type,
- S32 internal_format,
- U32 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
- {
- LLPointer<LLGLTexture> getLocalTexture(bool usemipmaps = true,
- bool generate = true) override
- {
- return LLViewerTextureManager::getLocalTexture(usemipmaps, generate);
- }
- LLPointer<LLGLTexture> getLocalTexture(U32 width, U32 height,
- U8 components, bool usemipmaps,
- bool generate = true) override
- {
- return LLViewerTextureManager::getLocalTexture(width, height,
- components, usemipmaps,
- generate);
- }
- LLGLTexture* getFetchedTexture(const LLUUID& image_id) override
- {
- return LLViewerTextureManager::getFetchedTexture(image_id);
- }
- };
- void LLViewerTextureManager::init()
- {
- LLPointer<LLImageRaw> nullp = new LLImageRaw(1, 1, 3);
- nullp->clear(0x77, 0x77, 0x77, 0xFF);
- LLViewerTexture::sNullImagep = getLocalTexture(nullp.get(), true);
- LLViewerTexture::sCloudImagep =
- getFetchedTextureFromFile("cloud-particle.j2c");
- #if 1
- LLViewerFetchedTexture::sDefaultImagep = getFetchedTexture(IMG_DEFAULT);
- LLViewerFetchedTexture::sDefaultImagep->setBoostLevel(LLGLTexture::BOOST_UI);
- constexpr S32 dim = 128;
- LLPointer<LLImageRaw> rawp = new LLImageRaw(dim, dim, 3);
- U8* datap = rawp->getData();
- if (!datap)
- {
- return;
- }
- memset(datap, 0x7f, dim * dim * 3);
- LLViewerFetchedTexture::sDefaultImagep->createGLTexture(0, rawp);
- // Cache the raw image
- LLViewerFetchedTexture::sDefaultImagep->setCachedRawImage(0, rawp);
- rawp = NULL;
- #else
- LLViewerFetchedTexture::sDefaultImagep =
- getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, true,
- LLGLTexture::BOOST_UI);
- #endif
- LLViewerFetchedTexture::sSmokeImagep =
- getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, true,
- LLGLTexture::BOOST_UI);
- LLViewerTexture::initClass();
- // Create a texture manager bridge.
- gTextureManagerBridgep = new LLViewerTextureManagerBridge;
- }
- void LLViewerTextureManager::cleanup()
- {
- delete gTextureManagerBridgep;
- LLImageGL::sDefaultGLImagep = NULL;
- LLViewerTexture::sNullImagep = NULL;
- LLViewerTexture::sCloudImagep = NULL;
- LLViewerFetchedTexture::sDefaultImagep = NULL;
- LLViewerFetchedTexture::sSmokeImagep = NULL;
- LLViewerFetchedTexture::sWhiteImagep = NULL;
- LLViewerFetchedTexture::sFlatNormalImagep = NULL;
- LLViewerFetchedTexture::sDefaultIrradiancePBRp = NULL;
- LLViewerFetchedTexture::sDefaultSunImagep = NULL;
- LLViewerFetchedTexture::sDefaultMoonImagep = NULL;
- LLViewerFetchedTexture::sDefaultCloudsImagep = NULL;
- LLViewerFetchedTexture::sDefaultCloudNoiseImagep = NULL;
- LLViewerFetchedTexture::sBloomImagep = NULL;
- LLViewerFetchedTexture::sOpaqueWaterImagep = NULL;
- LLViewerFetchedTexture::sWaterImagep = NULL;
- LLViewerFetchedTexture::sWaterNormapMapImagep = NULL;
- LLViewerMediaTexture::cleanUpClass();
- }
- //-----------------------------------------------------------------------------
- // LLViewerTexture
- //-----------------------------------------------------------------------------
- // static
- void LLViewerTexture::initClass()
- {
- LLImageGL::sDefaultGLImagep =
- LLViewerFetchedTexture::sDefaultImagep->getGLImage();
- }
- // Tuning params
- constexpr F32 DISCARD_BIAS_DELTA = 0.25f; // Was .05f in v1
- constexpr F32 DISCARD_DELTA_TIME = 0.5f;
- // I rewrote and thoroughly tuned this method to try and cope with most
- // situations. It also uses an algorithm to anticipate the next memory check
- // so to prevent the VRAM from getting full. Of course, it only properly works
- // when GL calls for VRAM usage are properly supported, which sadly only covers
- // NVIDIA cards and, under Linux/Mesa only, AMD cards... HB
- //static
- bool LLViewerTexture::isMemoryForTextureLow(F32& discard,
- bool& can_decrease_discard)
- {
- // No need to bother at all when we cannot read the VRAM via GL !
- static bool can_do = gGLManager.mHasATIMemInfo ||
- gGLManager.mHasNVXMemInfo;
- if (!can_do)
- {
- return false;
- }
- // Keep an option to disable this check entirely, in case the reports by
- // the driver would be wrong/broken (could be the case with some APUs).
- static LLCachedControl<bool> disabled(gSavedSettings, "DisableVRAMCheck");
- if (disabled)
- {
- return false;
- }
- // When GL threading is disabled, LLImageGLThread::updateFreeVRAM() is
- // synchronous and immediately updates the value returned by
- // LLImageGLThread::getFreeVRAMMegabytes(), which is *NOT* the case when
- // threading is enabled (we then get the value requested at the moment
- // last check was done). HB
- bool asynchronous = LLImageGLThread::sEnabled;
- if (!asynchronous)
- {
- // Update now, synchronously.
- LLImageGLThread::updateFreeVRAM();
- }
- S32 free_vram = LLImageGLThread::getFreeVRAMMegabytes();
- if (asynchronous)
- {
- // Update for next check, asynchronously.
- LLImageGLThread::updateFreeVRAM();
- }
- if (free_vram < 0) // Negative denotes a failure to get any info
- {
- return false;
- }
- // Compute how much more or less we are using VRAM since last check.
- S32 delta = 0;
- if (sLastFreeVRAMMB >= 0)
- {
- delta = free_vram - sLastFreeVRAMMB;
- }
- sLastFreeVRAMMB = free_vram;
- // Set the low limit for the VRAM free for textures to below 10% of its
- // initial size (at viewer startup, as reported by GL), a minimum further
- // clamped between 10 and 1000 MB.
- static S32 min_free_texture_memory =
- llclamp(10 * gGLManager.mTexVRAM / 100, 10, 1000);
- if (free_vram < min_free_texture_memory &&
- free_vram + delta < min_free_texture_memory)
- {
- // EEEK ! Emergency action is required !
- discard = DESIRED_DISCARD_BIAS_MAX;
- can_decrease_discard = false;
- return true;
- }
- // Let's see if we will have still enough memory at next check. We use 1.5
- // times the min memory for comparison, so that we can start increasing the
- // bias a little already when getting close to the limit.
- if (free_vram + delta > 3 * min_free_texture_memory / 2)
- {
- return false; // Yes, should be fine...
- }
- // Do not let the discard bias decrease in these tight memory conditions.
- can_decrease_discard = false;
- // If we predict that more than 1.25 times the min memory will be available
- // at next check, then we still leave the discard bias unchanged for now.
- if (free_vram + delta >= 4 * min_free_texture_memory / 3)
- {
- return false; // Then, we should be fine...
- }
- F32 bias_delta;
- // How large is the delta, compared with the minimum ?
- F32 factor = (F32)delta / (F32)min_free_texture_memory;
- if (factor >= 1.5f)
- {
- // React strongly to try and avoid freezes due to texture memory
- // spilling into the RAM by lack of VRAM...
- bias_delta = DISCARD_BIAS_DELTA * 2.f;
- }
- else if (factor >= 1.f)
- {
- bias_delta = DISCARD_BIAS_DELTA * 1.5f;
- }
- else if (factor >= 0.5f)
- {
- bias_delta = DISCARD_BIAS_DELTA;
- }
- else
- {
- bias_delta = DISCARD_BIAS_DELTA * 0.5f;
- }
- LL_DEBUGS("TextureMemory") << "Increasing discard bias: low free VRAM."
- << LL_ENDL;
- discard = llclamp(discard + bias_delta, 0.f, DESIRED_DISCARD_BIAS_MAX);
- return true;
- }
- //static
- void LLViewerTexture::updateClass()
- {
- sCurrentTime = gFrameTimeSeconds;
- LLViewerMediaTexture::updateClass();
- // Everything in MB
- sBoundTexMemoryMB = BYTES2MEGABYTES(LLImageGL::sBoundTexMemBytes);
- sTotalTexMemoryMB = BYTES2MEGABYTES(LLImageGL::sGlobalTexMemBytes);
- sMaxBoundTexMemMB = gTextureList.getMaxResidentTexMem();
- sMaxTotalTexMemMB = gTextureList.getMaxTotalTextureMem();
- if (gUseWireframe)
- {
- // Max out the discard level, because the wireframe mode kills object
- // culling and causes all objects and textures in FOV to load at once.
- sDesiredDiscardBias = DESIRED_DISCARD_BIAS_MAX;
- return;
- }
- S32 bound_delta = 0;
- S32 total_delta = 0;
- bool is_check_time = sCurrentTime >= sNextDiscardBiasUpdateTime;
- if (is_check_time)
- {
- sNextDiscardBiasUpdateTime = sCurrentTime + DISCARD_DELTA_TIME;
- if (sLastBoundTexMemoryMB > 0)
- {
- bound_delta = sBoundTexMemoryMB - sLastBoundTexMemoryMB;
- }
- sLastBoundTexMemoryMB = sBoundTexMemoryMB;
- if (sLastTotalTexMemoryMB > 0)
- {
- total_delta = sTotalTexMemoryMB - sLastTotalTexMemoryMB;
- }
- sLastTotalTexMemoryMB = sTotalTexMemoryMB;
- }
- const F32 initial_discard = sDesiredDiscardBias;
- bool can_decrease_discard = true;
- bool increased_discard = false;
- // First check wether the system memory is low or not and adjust discard
- if (LLMemory::hasFailedAllocation())
- {
- // There has been a failure to allocate memory: the latter is either
- // too low or too fragmented ! Let's take radical measures... HB
- sDesiredDiscardBias = 5.f;
- increased_discard = true;
- can_decrease_discard = false;
- static LLCachedControl<F32> draw_dist(gSavedSettings, "RenderFarClip");
- if (draw_dist > 64.f)
- {
- gSavedSettings.setF32("RenderFarClip", 64.f);
- }
- static S32 last_failure = 0;
- if ((S32)sCurrentTime - last_failure > 3)
- {
- gAgent.resetView();
- }
- // Clear the error condition.
- LLMemory::resetFailedAllocation();
- // Warn the user, but do not spam them either...
- if ((S32)sCurrentTime - last_failure > 20)
- {
- gNotifications.add("GotAllocationFailure");
- }
- last_failure = (S32)sCurrentTime;
- LL_DEBUGS("TextureMemory") << "Maxing discard bias due to memory allocation failure."
- << LL_ENDL;
- }
- // Check VRAM usage: this is also a hard limit...
- else if (is_check_time &&
- isMemoryForTextureLow(sDesiredDiscardBias, can_decrease_discard))
- {
- increased_discard = true;
- // Make the next check sooner, to get better chances to catch high
- // VRAM usage increase rates and avoid filling up the VRAM. HB
- sNextDiscardBiasUpdateTime -= DISCARD_DELTA_TIME * 0.5f;
- }
- // If we are using (or soon going to use) more texture memory than we
- // should, scale up the desired discard level, but do not when the last
- // memory usage was larger than the current one (meaning we are in the
- // process of returning to the limit already). HB
- if ((is_check_time && !increased_discard) &&
- ((bound_delta >= 0 &&
- sBoundTexMemoryMB + bound_delta >= sMaxBoundTexMemMB) ||
- (total_delta >= 0 &&
- sTotalTexMemoryMB + total_delta >= sMaxTotalTexMemMB)))
- {
- LL_DEBUGS("TextureMemory") << "Increasing discard bias: too much texture memory used."
- << LL_ENDL;
- can_decrease_discard = false;
- increased_discard = true;
- sDesiredDiscardBias += DISCARD_BIAS_DELTA;
- }
- // If we are using less texture memory than what we could *and* the memory
- // usage is not larger than at last check time, scale down the desired
- // discard level. HB
- if (is_check_time && can_decrease_discard && sDesiredDiscardBias > 0.f &&
- bound_delta <= 0 && total_delta <= 0)
- {
- static LLCachedControl<F32> bias_mult(gSavedSettings,
- "TexBiasDecreaseDelayFactor");
- static LLCachedControl<F32> lower_bound(gSavedSettings,
- "TexMemLowerBoundScale");
- F32 texmem_lower_bound_scale = llclamp((F32)lower_bound, 0.75f, 0.9f);
- if (sBoundTexMemoryMB < sMaxBoundTexMemMB * texmem_lower_bound_scale &&
- sTotalTexMemoryMB < sMaxTotalTexMemMB * texmem_lower_bound_scale)
- {
- F32 factor = llmin((F32)bias_mult, 2.f);
- // Do not decrease the discard too fast: when, for example, the
- // agent avatar turns around, the texture memory usage can drop
- // dramatically fast, just to increase brutally again a couple
- // seconds later... HB
- if (sCurrentTime - sLastDiscardDecreaseTime >=
- sDesiredDiscardBias * factor)
- {
- // When using lower discard biases, decrease them slower, to
- // obtain finer memory usage adjustements and avoid entering
- // a decrease-increase yo-yo due to an overshoot. HB
- if (sDesiredDiscardBias <= 2.5f)
- {
- sDesiredDiscardBias -= DISCARD_BIAS_DELTA * 0.5f;
- }
- else
- {
- sDesiredDiscardBias -= DISCARD_BIAS_DELTA;
- }
- sLastDiscardDecreaseTime = sCurrentTime;
- }
- }
- }
- sDesiredDiscardBias = llclamp(sDesiredDiscardBias, 0.f,
- DESIRED_DISCARD_BIAS_MAX);
- if (sDesiredDiscardBias >= 3.f && sLastDiscardDecreaseTime > 0.f)
- {
- sLastLowMemCondTime = sCurrentTime;
- }
- // Decide whether or not we should increase the discard bias for ALM
- // textures based on the ratio of used bound texture memory (for toggling
- // it on) and on the desired discard bias (for toggling it off, providing
- // an adequate hysteresis). HB
- static LLCachedControl<F32> bratio(gSavedSettings,
- "BoundTexRatioToBiasALM");
- static LLCachedControl<F32> mdiscard(gSavedSettings,
- "MaxDiscardToUnbiasALM");
- if (F32(sBoundTexMemoryMB) >
- F32(sMaxBoundTexMemMB) * llmax(0.25f, bratio))
- {
- sALMTexPenalty = true;
- }
- else if (sALMTexPenalty &&
- sDesiredDiscardBias < llclamp((F32)mdiscard, 1.f, 4.f))
- {
- sALMTexPenalty = false;
- }
- // If we just changed the discard level, or it is already at the max, we
- // can also try and make room for textures by removing from memory the
- // ones not seen/used in a while. Note that freeing memory also when the
- // discard decreases helps avoiding a yo-yo effect, by making room for
- // the higher texture LODs that are going to be decoded. HB
- if (is_check_time &&
- (sDesiredDiscardBias == DESIRED_DISCARD_BIAS_MAX ||
- sDesiredDiscardBias != initial_discard))
- {
- gTextureList.flushOldImages();
- }
- }
- //static
- void LLViewerTexture::resetLowMemCondition(bool reset_bias)
- {
- // Reset with -LOW_MEM_COND_DURATION delta to avoid false positive on
- // login, i.e. when sCurrentTime < LOW_MEM_COND_DURATION. HB
- constexpr F32 LOW_MEM_COND_DURATION = 30.f;
- sLastLowMemCondTime = -LOW_MEM_COND_DURATION;
- sLastDiscardDecreaseTime = 0.f;
- if (reset_bias && sDesiredDiscardBias >= 3.f)
- {
- sDesiredDiscardBias = 2.5f;
- }
- }
- 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(U32 width, U32 height, U8 comp, bool mipmaps)
- : LLGLTexture(width, height, comp, mipmaps)
- {
- init(true);
- mID.generate();
- ++sImageCount;
- }
- LLViewerTexture::LLViewerTexture(const LLImageRaw* rawp, bool usemipmaps)
- : LLGLTexture(rawp, usemipmaps)
- {
- init(true);
- mID.generate();
- ++sImageCount;
- }
- LLViewerTexture::~LLViewerTexture()
- {
- cleanup();
- --sImageCount;
- }
- //virtual
- void LLViewerTexture::init(bool firstinit)
- {
- mMaxVirtualSize = 0.f;
- mMaxVirtualSizeResetInterval = 1;
- mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;
- mAdditionalDecodePriority = 0.f;
- mParcelMedia = NULL;
- for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
- {
- mNumFaces[i] = 0;
- mFaceList[i].clear();
- }
- memset(&mNumVolumes, 0,
- sizeof(U32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS);
- mVolumeList[LLRender::LIGHT_TEX].clear();
- mVolumeList[LLRender::SCULPT_TEX].clear();
- mLastReferencedTime = mLastFaceListUpdate = mLastVolumeListUpdate =
- gFrameTimeSeconds;
- }
- void LLViewerTexture::setNeedsAlphaAndPickMask(bool b)
- {
- if (mImageGLp)
- {
- mImageGLp->setNeedsAlphaAndPickMask(b);
- }
- }
- //virtual
- S8 LLViewerTexture::getType() const
- {
- return LLViewerTexture::LOCAL_TEXTURE;
- }
- void LLViewerTexture::cleanup()
- {
- #if LL_FIX_MAT_TRANSPARENCY
- notifyAboutMissingAsset();
- #endif
- 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();
- }
- #if LL_FIX_MAT_TRANSPARENCY
- void LLViewerTexture::notifyAboutCreatingTexture()
- {
- for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
- {
- for (U32 f = 0, count = mNumFaces[ch]; f < count; ++f)
- {
- mFaceList[ch][f]->notifyAboutCreatingTexture(this);
- }
- }
- }
- void LLViewerTexture::notifyAboutMissingAsset()
- {
- for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
- {
- for (U32 f = 0, count = mNumFaces[ch]; f < count; ++f)
- {
- mFaceList[ch][f]->notifyAboutMissingAsset(this);
- }
- }
- }
- #endif
- // virtual
- void LLViewerTexture::dump()
- {
- LLGLTexture::dump();
- llinfos << "LLViewerTexture mID: " << mID << llendl;
- }
- void LLViewerTexture::resetLastReferencedTime()
- {
- mLastReferencedTime = gFrameTimeSeconds;
- }
- F32 LLViewerTexture::getElapsedLastReferenceTime()
- {
- return gFrameTimeSeconds - mLastReferencedTime;
- }
- //virtual
- void LLViewerTexture::setBoostLevel(U32 level)
- {
- LLGLTexture::setBoostLevel(level);
- // Strongly encourage anything boosted to load at full res
- static LLCachedControl<bool> boost_full_res(gSavedSettings,
- "FullResBoostedTextures");
- if (mBoostLevel >= BOOST_HIGH && boost_full_res &&
- sDesiredDiscardBias < 3.f)
- {
- constexpr F32 max_size = 2048.f * 2048.f;
- mMaxVirtualSize = max_size;
- }
- }
- bool LLViewerTexture::bindDefaultImage(S32 stage)
- {
- if (stage < 0) return false;
- bool res = true;
- if (LLViewerFetchedTexture::sDefaultImagep.notNull() &&
- LLViewerFetchedTexture::sDefaultImagep.get() != this)
- {
- // Use default if we got it
- res = gGL.getTexUnit(stage)->bind(LLViewerFetchedTexture::sDefaultImagep);
- }
- if (!res && LLViewerTexture::sNullImagep.notNull() &&
- LLViewerTexture::sNullImagep != this)
- {
- res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sNullImagep);
- }
- if (!res)
- {
- llwarns << "Failed at stage: " << stage << llendl;
- }
- // Check if there is cached raw image and switch to it if possible
- switchToCachedImage();
- return res;
- }
- void LLViewerTexture::addTextureStats(F32 virtual_size,
- bool needs_gltexture) const
- {
- if (needs_gltexture)
- {
- mNeedsGLTexture = true;
- }
- // Do not allow the scaling down of do-not-discard textures ! HB
- if (mDontDiscard)
- {
- constexpr F32 MAX_AREA = 1024.f * 1024.f;
- virtual_size = MAX_AREA;
- }
- if (!mMaxVirtualSizeResetCounter)
- {
- // Flag to reset the values because the old values are used.
- resetMaxVirtualSizeResetCounter();
- mAdditionalDecodePriority = 0.f;
- }
- if (mMaxVirtualSize < virtual_size)
- {
- mMaxVirtualSize = virtual_size;
- }
- }
- void LLViewerTexture::resetTextureStats()
- {
- mMaxVirtualSizeResetCounter = 0;
- // Do not allow the scaling down of do-not-discard textures ! HB
- if (!mDontDiscard)
- {
- mMaxVirtualSize = 0.f;
- }
- mAdditionalDecodePriority = 0.f;
- }
- void LLViewerTexture::addFace(U32 ch, LLFace* facep)
- {
- if (!facep || ch >= LLRender::NUM_TEXTURE_CHANNELS)
- {
- llassert(false);
- return;
- }
- 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];
- mLastFaceListUpdate = gFrameTimeSeconds;
- }
- //virtual
- void LLViewerTexture::removeFace(U32 ch, LLFace* facep)
- {
- if (!facep || ch >= LLRender::NUM_TEXTURE_CHANNELS)
- {
- llassert(false);
- return;
- }
- if (mNumFaces[ch] > 1)
- {
- U32 index = facep->getIndexInTex(ch);
- if (index < (U32)mFaceList[ch].size() && index < mNumFaces[ch])
- {
- mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]];
- mFaceList[ch][index]->setIndexInTex(ch, index);
- }
- else
- {
- llwarns << "Index out of range !" << llendl;
- llassert(false);
- }
- }
- else
- {
- mFaceList[ch].clear();
- mNumFaces[ch] = 0;
- }
- mLastFaceListUpdate = gFrameTimeSeconds;
- }
- 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];
- }
- void LLViewerTexture::reorganizeFaceList()
- {
- constexpr F32 MAX_WAIT_TIME = 20.f; // seconds
- constexpr U32 MAX_EXTRA_BUFFER_SIZE = 4;
- if (gFrameTimeSeconds - mLastFaceListUpdate < 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());
- }
- mLastFaceListUpdate = gFrameTimeSeconds;
- }
- void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep)
- {
- 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];
- mLastVolumeListUpdate = gFrameTimeSeconds;
- }
- void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep)
- {
- if (mNumVolumes[ch] > 1)
- {
- S32 index = volumep->getIndexInTex(ch);
- llassert(index < (S32)mVolumeList[ch].size() &&
- index < (S32)mNumVolumes[ch]);
- mVolumeList[ch][index] = mVolumeList[ch][--mNumVolumes[ch]];
- mVolumeList[ch][index]->setIndexInTex(ch, index);
- }
- else
- {
- mVolumeList[ch].clear();
- mNumVolumes[ch] = 0;
- }
- mLastVolumeListUpdate = gFrameTimeSeconds;
- }
- void LLViewerTexture::reorganizeVolumeList()
- {
- constexpr F32 MAX_WAIT_TIME = 20.f; // seconds
- constexpr U32 MAX_EXTRA_BUFFER_SIZE = 4;
- if (gFrameTimeSeconds - mLastVolumeListUpdate < MAX_WAIT_TIME)
- {
- return;
- }
- for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i)
- {
- if (mNumVolumes[i] + MAX_EXTRA_BUFFER_SIZE > mVolumeList[i].size())
- {
- return;
- }
- }
- mLastVolumeListUpdate = gFrameTimeSeconds;
- for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i)
- {
- mVolumeList[i].erase(mVolumeList[i].begin() + mNumVolumes[i],
- mVolumeList[i].end());
- }
- }
- //-----------------------------------------------------------------------------
- // LLViewerFetchedTexture
- //-----------------------------------------------------------------------------
- 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;
- case FTT_DEFAULT:
- return ftt_default;
- case FTT_SERVER_BAKE:
- return ftt_server_bake;
- case FTT_HOST_BAKE:
- return ftt_host_bake;
- case FTT_MAP_TILE:
- return ftt_map_tile;
- case FTT_LOCAL_FILE:
- return ftt_local_file;
- }
- return ftt_error;
- }
- LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id,
- FTType f_type,
- const LLHost& host,
- bool usemipmaps)
- : LLViewerTexture(id, usemipmaps),
- mTargetHost(host)
- {
- init(true);
- mFTType = f_type;
- generateGLTexture();
- mImageGLp->setNeedsAlphaAndPickMask(true);
- if (!host.isInvalid())
- {
- // We must request the image from the provided host sim.
- mCanUseHTTP = false;
- }
- }
- LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* rawp,
- FTType f_type, bool usemipmaps)
- : LLViewerTexture(rawp, usemipmaps)
- {
- init(true);
- mFTType = f_type;
- // Make sure we are not going to enter the texture fetcher, since this is
- // just a fake "fetched" texture based on a local raw image, and there is
- // strictly nothing to be fetched from network, neither from a file ! HB
- mRawImage = const_cast<LLImageRaw*>(rawp); // Let's cheat...
- mFullWidth = mRawImage->getWidth();
- mFullHeight = mRawImage->getHeight();
- mSavedRawImage = mRawImage;
- mIsRawImageValid = true;
- mIsMissingAsset = mFullyLoaded = true;
- mCanUseHTTP = false;
- mDesiredSavedRawDiscardLevel = mDesiredDiscardLevel = 0;
- mDesiredSavedRawDiscardLevel = mSavedRawDiscardLevel = 0;
- }
- 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();
- mImageGLp->setNeedsAlphaAndPickMask(true);
- }
- void LLViewerFetchedTexture::init(bool firstinit)
- {
- mOrigWidth = 0;
- mOrigHeight = 0;
- mNeedsAux = mHasAux = false;
- mRequestedDiscardLevel = -1;
- mRequestedDownloadPriority = 0.f;
- mFullyLoaded = false;
- mCanUseHTTP = true;
- mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
- mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
- mKnownDrawWidth = 0;
- mKnownDrawHeight = 0;
- mKnownDrawSizeChanged = false;
- if (firstinit)
- {
- mDecodePriority = 0.f;
- mInImageList = false;
- }
- // Only set mIsMissingAsset true when we know for certain that the database
- // does not contain this image.
- mIsMissingAsset = false;
- // When force-deleting a request before it can complete, set this as true
- // to avoid false missing asset cases.
- mWasDeleted = false;
- mLoadedCallbackDesiredDiscardLevel = S8_MAX;
- mPauseLoadedCallBacks = true;
- 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;
- mCachedRawImage = NULL;
- mCachedRawDiscardLevel = -1;
- mCachedRawImageReady = false;
- mSavedRawImage = NULL;
- mForceToSaveRawImage = false;
- mSaveRawImage = false;
- mSavedRawDiscardLevel = -1;
- mDesiredSavedRawDiscardLevel = -1;
- mLastReferencedSavedRawImageTime = 0.f;
- mKeptSavedRawImageTime = 0.f;
- mLastCallBackActiveTime = 0.f;
- mForceCallbackFetch = false;
- mFTType = FTT_UNKNOWN;
- mLastPacketTime = mStopFetchingTime = gFrameTimeSeconds;
- }
- LLViewerFetchedTexture::~LLViewerFetchedTexture()
- {
- // NOTE: gTextureFetchp can be 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 && gTextureFetchp)
- {
- gTextureFetchp->deleteRequest(getID());
- }
- cleanup();
- }
- //virtual
- S8 LLViewerFetchedTexture::getType() const
- {
- return LLViewerTexture::FETCHED_TEXTURE;
- }
- void LLViewerFetchedTexture::cleanup()
- {
- for (callback_list_t::iterator iter = mLoadedCallbackList.begin();
- iter != mLoadedCallbackList.end(); )
- {
- LLLoadedCallbackEntry* entryp = *iter++;
- // We never finished loading the image, so indicate a 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;
- }
- void LLViewerFetchedTexture::setForSculpt()
- {
- constexpr S32 MAX_INTERVAL = 8; // In frames
- mForSculpt = true;
- setBoostLevel(LLGLTexture::BOOST_SCULPTED);
- #if !LL_IMPLICIT_SETNODELETE
- setNoDelete();
- #endif
- if (isForSculptOnly() && hasGLTexture() && !getBoundRecently())
- {
- destroyGLTexture(); // Sculpt image does not need GL texture.
- mTextureState = ACTIVE;
- }
- checkCachedRawSculptImage();
- setMaxVirtualSizeResetInterval(MAX_INTERVAL);
- }
- void LLViewerFetchedTexture::setDeletionCandidate()
- {
- if (mTextureState == INACTIVE)
- {
- mTextureState = DELETION_CANDIDATE;
- }
- }
- void LLViewerFetchedTexture::setInactive()
- {
- if (mTextureState == ACTIVE &&
- (mImageGLp.isNull() || !mImageGLp->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();
- llinfos << "Dump : " << mID
- << ", mIsMissingAsset = " << (S32)mIsMissingAsset
- << ", mFullWidth = " << mFullWidth
- << ", mFullHeight = " << mFullHeight
- << ", mOrigWidth = " << mOrigWidth
- << ", mOrigHeight = " << mOrigHeight
- << llendl;
- llinfos << " : "
- << " mFullyLoaded = " << (S32)mFullyLoaded
- << ", mFetchState = " << (S32)mFetchState
- << ", mFetchPriority = " << (S32)mFetchPriority
- << ", mDownloadProgress = " << (F32)mDownloadProgress
- << llendl;
- llinfos << " : "
- << " mHasFetcher = " << (S32)mHasFetcher
- << ", mIsFetching = " << (S32)mIsFetching
- << ", mWasDeleted = " << (S32)mWasDeleted
- << ", mBoostLevel = " << (S32)mBoostLevel
- << llendl;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // ONLY called from LLViewerFetchedTextureList
- bool LLViewerFetchedTexture::destroyTexture()
- {
- if (mNeedsCreateTexture)
- {
- // Return if in the process of generating a new texture.
- return false;
- }
- destroyGLTexture();
- mFullyLoaded = false;
- return true;
- }
- void LLViewerFetchedTexture::addToCreateTexture()
- {
- bool force_update = false;
- if (getComponents() != mRawImage->getComponents())
- {
- // We have changed the number of components, so we need to move any
- // object using this pool to a different pool.
- mComponents = mRawImage->getComponents();
- mImageGLp->setComponents(mComponents);
- force_update = true;
- for (U32 j = 0; j < LLRender::NUM_TEXTURE_CHANNELS; ++j)
- {
- U32 count = mNumFaces[j];
- U32 list_size = mFaceList[j].size();
- if (count > list_size)
- {
- llwarns_once << "Face count greater than face list size for texture channel: "
- << j << ". Clamping down." << llendl;
- count = list_size;
- }
- for (U32 i = 0; i < count; ++i)
- {
- LLFace* facep = mFaceList[j][i];
- if (facep)
- {
- facep->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
- {
- // LLImageRaw:scale() allows for a lower memory usage but also causes
- // memory fragmentation... This is a trade off ! HB
- static LLCachedControl<bool> rescale(gSavedSettings,
- "TextureRescaleFetched");
- // If mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the
- // required image res keeps going up, so do not scale down the over
- // qualified image. Note: scaling down image is expensensive. Do it
- // only when very necessary.
- if (rescale && !mForceToSaveRawImage &&
- mRequestedDiscardLevel <= mDesiredDiscardLevel)
- {
- 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:
- LLPointer<LLImageRaw> dup =
- mRawImage->scaled(w >> i, h >> i);
- if (dup.notNull())
- {
- mRawImage = std::move(dup);
- }
- }
- }
- }
- }
- scheduleCreateTexture();
- }
- }
- // ONLY called from LLViewerTextureList
- bool LLViewerFetchedTexture::preCreateTexture(S32 usename)
- {
- if (!mNeedsCreateTexture)
- {
- destroyRawImage();
- return false;
- }
- mNeedsCreateTexture = false;
- if (mRawImage.isNull())
- {
- llwarns << "Trying to create texture " << mID.asString()
- << " without raw image: aborting !" << llendl;
- destroyRawImage();
- return false;
- }
- LL_DEBUGS("ViewerTexture") << "Creating image " << mID.asString()
- << " - discard level = " << mRawDiscardLevel
- << " - Size: " << mRawImage->getWidth() << "x"
- << mRawImage->getHeight() << " pixels - "
- << mRawImage->getDataSize() << " bytes."
- << 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();
- const S32 max_size = gMaxImageSizeDefault * 2;
- #if 0
- if (mBoostLevel == BOOST_PREVIEW)
- {
- mRawImage->biasedScaleToPowerOfTwo(1024);
- }
- else
- {
- // Leave black border, do not scale image content
- mRawImage->expandToPowerOfTwo(max_size, false);
- }
- #else
- // Do not scale image content
- mRawImage->expandToPowerOfTwo(max_size, false);
- #endif
- mFullWidth = mRawImage->getWidth();
- mFullHeight = mRawImage->getHeight();
- setTexelsPerImage();
- }
- else
- {
- mOrigWidth = mFullWidth;
- mOrigHeight = mFullHeight;
- }
- bool size_okay = true;
- S32 discard_level = mRawDiscardLevel;
- if (discard_level < 0)
- {
- llwarns << "Trying to create texture " << mID.asString()
- << " with a negative discard level. Zeroing it." << llendl;
- discard_level = 0;
- }
- S32 raw_width = mRawImage->getWidth() << discard_level;
- S32 raw_height = mRawImage->getHeight() << discard_level;
- const S32 max_size = gMaxImageSizeDefault * 2;
- if (raw_width > max_size || raw_height > max_size)
- {
- llinfos << "Width or height is greater than " << max_size
- << ": (" << raw_width << "," << raw_height << ")" << llendl;
- size_okay = false;
- }
- if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
- {
- // A non power-of-two image was uploaded through a non standard client
- llinfos << "Non power of two width or height: (" << mRawImage->getWidth()
- << "," << mRawImage->getHeight() << ")" << llendl;
- 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.
- llwarns << "Image " << mID.asString()
- << " does not have an acceptable size, setting as missing."
- << llendl;
- setIsMissingAsset();
- destroyRawImage();
- return false;
- }
- if (mImageGLp->hasExplicitFormat())
- {
- U32 format = mImageGLp->getPrimaryFormat();
- S8 components = mRawImage->getComponents();
- if (((format == GL_RGBA && components < 4) ||
- (format == GL_RGB && components < 3)))
- {
- llwarns << "Cannot create texture " << mID
- << ": invalid image format: " << std::hex << format
- << std::dec << " - Number of components: " << components
- << llendl;
- // Was expecting specific format but raw texture has insufficient
- // components for such format, using such texture would result in a
- // crash or would display wrongly. Texture might be corrupted
- // server side, so just set as missing and clear cached texture.
- setIsMissingAsset();
- destroyRawImage();
- gTextureCachep->removeFromCache(mID);
- return false;
- }
- }
- return res;
- }
- bool LLViewerFetchedTexture::createTexture(S32 usename)
- {
- if (!mNeedsCreateTexture)
- {
- return false;
- }
- return mImageGLp->createGLTexture(mRawDiscardLevel, mRawImage, usename,
- true);
- }
- void LLViewerFetchedTexture::postCreateTexture()
- {
- if (!mNeedsCreateTexture)
- {
- return;
- }
- #if LL_FIX_MAT_TRANSPARENCY
- notifyAboutCreatingTexture();
- #endif
- setActive();
- if (!needsToSaveRawImage())
- {
- mNeedsAux = false;
- destroyRawImage();
- }
- mNeedsCreateTexture = false;
- }
- void LLViewerFetchedTexture::scheduleCreateTexture()
- {
- if (mNeedsCreateTexture)
- {
- return;
- }
- mNeedsCreateTexture = true;
- if (!preCreateTexture())
- {
- return;
- }
- // Reassert this since it was set to false in preCreateTexture()... HB
- mNeedsCreateTexture = true;
- // This will be set appropiately below.
- sImageThreadCreationsCapped = false;
- // First, see if we can queue anything: this is not the case when the GL
- // thread(s) is(are) not started (sEnabled is false);
- bool can_queue = LLImageGLThread::sEnabled && gMainloopWorkp;
- if (can_queue)
- {
- // ... finally, do not let the GL queue thread get trashed with too
- // many requests and process in the main thread any request that would
- // add beyond a reasonnable (and configurable) queue size. HB
- static LLCachedControl<U32> queue_size(gSavedSettings,
- "GLWorkerQueueSize");
- sImageThreadQueueSize = gMainloopWorkp->size();
- sImageThreadCreationsCapped = queue_size &&
- sImageThreadQueueSize > (U32)queue_size;
- if (!sImageThreadCreationsCapped)
- {
- ref();
- if (gMainloopWorkp->postTo(gImageQueuep,
- // Work to be done on worker thread
- [this]()
- {
- // Actually create the texture on a
- // background thread
- createTexture();
- },
- // Callback to be run on main thread
- [this]()
- {
- // Finalize on main thread
- postCreateTexture();
- unref();
- }))
- {
- // Success !
- ++sImageThreadCreations;
- return;
- }
- // Failed (gImageQueuep closed): fallback to main thread.
- unref();
- }
- }
- // In case we cannot thread the GL image creation, insert ourselves in
- // mCreateTextureList for a creation in the main thread.
- gTextureList.mCreateTextureList.insert(this);
- ++sMainThreadCreations;
- }
- // Call with 0,0 to turn this feature off.
- //virtual
- void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height)
- {
- if (mKnownDrawWidth < width || mKnownDrawHeight < height)
- {
- mKnownDrawWidth = llmax(mKnownDrawWidth, width);
- mKnownDrawHeight = llmax(mKnownDrawHeight, height);
- mKnownDrawSizeChanged = true;
- mFullyLoaded = false;
- }
- addTextureStats((F32)(mKnownDrawWidth * mKnownDrawHeight));
- }
- //virtual
- void LLViewerFetchedTexture::processTextureStats()
- {
- if (mFullyLoaded)
- {
- if (mDesiredDiscardLevel > mMinDesiredDiscardLevel)
- {
- // Need to load more
- mDesiredDiscardLevel = mMinDesiredDiscardLevel;
- mFullyLoaded = false;
- }
- }
- else
- {
- updateVirtualSize();
- static LLCachedControl<bool> textures_fullres(gSavedSettings,
- "TextureLoadFullRes");
- if (textures_fullres)
- {
- mDesiredDiscardLevel = 0;
- }
- else if (!LLPipeline::sRenderDeferred && mBoostLevel == BOOST_ALM)
- {
- mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
- }
- else if (!mFullWidth || !mFullHeight)
- {
- mDesiredDiscardLevel = llmin(getMaxDiscardLevel(),
- (S32)mLoadedCallbackDesiredDiscardLevel);
- }
- else
- {
- if (!mKnownDrawWidth || !mKnownDrawHeight ||
- mFullWidth <= mKnownDrawWidth ||
- mFullHeight <= mKnownDrawHeight)
- {
- mDesiredDiscardLevel = getMinDiscardLevel();
- }
- else if (mKnownDrawSizeChanged) // Known draw size is set
- {
- F32 ratio = llmin((F32)mFullWidth / (F32)mKnownDrawWidth,
- (F32)mFullHeight / (F32)mKnownDrawHeight);
- mDesiredDiscardLevel = (S8)logf(ratio / F_LN2);
- mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0,
- (S8)getMaxDiscardLevel());
- mDesiredDiscardLevel = llmin(mDesiredDiscardLevel,
- mMinDesiredDiscardLevel);
- }
- mKnownDrawSizeChanged = false;
- // If this texture is used for ALM (i.e. as a normal or specular
- // map, or as a light texture), and we are low on available bound
- // GL textures memory, scale it down. HB
- if (mBoostLevel == BOOST_ALM && sALMTexPenalty &&
- mDesiredDiscardLevel < MAX_DISCARD_LEVEL)
- {
- ++mDesiredDiscardLevel;
- }
- 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;
- }
- }
- }
- constexpr F32 MAX_PRIORITY_PIXEL = 999.f; // Pixel area
- constexpr F32 PRIORITY_BOOST_LEVEL_FACTOR = 1000.f; // Boost level
- constexpr F32 PRIORITY_DELTA_DISCARD_LEVEL_FACTOR = 100000.f; // Delta discard
- constexpr S32 MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY = 4;
- constexpr F32 PRIORITY_ADDITIONAL_FACTOR = 1000000.f; // Additional
- constexpr S32 MAX_ADDITIONAL_LEVEL_FOR_PRIORITY = 8;
- constexpr F32 PRIORITY_BOOST_HIGH_FACTOR = 10000000.f; // Boost high
- constexpr F32 MAX_DECODE_PRIORITY = PRIORITY_BOOST_HIGH_FACTOR +
- PRIORITY_ADDITIONAL_FACTOR *
- (MAX_ADDITIONAL_LEVEL_FOR_PRIORITY + 1) +
- PRIORITY_DELTA_DISCARD_LEVEL_FACTOR *
- (MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY + 1) +
- PRIORITY_BOOST_LEVEL_FACTOR *
- (LLGLTexture::BOOST_MAX_LEVEL - 1) +
- MAX_PRIORITY_PIXEL + 1.f;
- F32 LLViewerFetchedTexture::calcDecodePriority()
- {
- if (mNeedsCreateTexture)
- {
- return mDecodePriority; // No change while waiting to create
- }
- if (mFullyLoaded && !mForceToSaveRawImage)
- {
- return -1.f; // Already loaded for static texture
- }
- S32 cur_discard = getCurrentDiscardLevelForFetching();
- bool have_all_data = cur_discard >= 0 &&
- cur_discard <= mDesiredDiscardLevel;
- F32 pixel_priority = sqrtf(mMaxVirtualSize);
- F32 priority = 0.f;
- if (mIsMissingAsset || mWasDeleted)
- {
- priority = 0.f;
- }
- else if (mDesiredDiscardLevel >= cur_discard && cur_discard > -1)
- {
- priority = -2.f;
- }
- else if (mCachedRawDiscardLevel > -1 &&
- mDesiredDiscardLevel >= mCachedRawDiscardLevel)
- {
- priority = -3.f;
- }
- else if (mDesiredDiscardLevel > getMaxDiscardLevel())
- {
- // Do not decode anything we do not need
- priority = -4.f;
- }
- else if (!have_all_data && mBoostLevel == BOOST_UI)
- {
- priority = 1.f;
- }
- else if (pixel_priority < 0.001f && !have_all_data)
- {
- // Not on screen but we might want some data
- if (mBoostLevel > BOOST_HIGH)
- {
- // Always want high boosted images
- priority = 1.f;
- }
- else
- {
- priority = -5.f; // Stop fetching
- }
- }
- else if (cur_discard < 0)
- {
- // Texture does not have any data, so we do not know the size of the
- // image, treat it like 32 * 32. Priority range = 100,000 - 500,000
- F32 desired = (F32)(logf(32.f / pixel_priority) / F_LN2);
- S32 ddiscard = MAX_DISCARD_LEVEL - (S32)desired;
- ddiscard = llclamp(ddiscard, 0, MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY);
- priority = (ddiscard + 1) * PRIORITY_DELTA_DISCARD_LEVEL_FACTOR;
- // Boost the textures without any data so far
- setAdditionalDecodePriority(0.1f);
- }
- else if (mMinDiscardLevel > 0 && cur_discard <= mMinDiscardLevel)
- {
- // Larger mips are corrupted
- priority = -6.f;
- }
- else
- {
- // Priority range = 100,000 - 500,000
- S32 desired_discard = mDesiredDiscardLevel;
- if (!isJustBound() && mCachedRawImageReady)
- {
- if (mBoostLevel < BOOST_HIGH)
- {
- // We do not have rendered this in a while, de-prioritize it
- desired_discard += 2;
- }
- else
- {
- // We do not have rendered this in the last half second, and we
- // have a cached raw image, leave the desired discard as-is
- desired_discard = cur_discard;
- }
- }
- S32 ddiscard = cur_discard - desired_discard;
- ddiscard = llclamp(ddiscard, -1, MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY);
- priority = (ddiscard + 1) * PRIORITY_DELTA_DISCARD_LEVEL_FACTOR;
- }
- // Priority Formula:
- // BOOST_HIGH + ADDITIONAL PRI + DELTA DISCARD + BOOST LEVEL + PIXELS
- // [10,000,000] + [1,000,000-9,000,000] + [100,000-500,000] + [1-20,000] + [0-999]
- if (priority > 0.f)
- {
- bool large_enough = mCachedRawImageReady &&
- mTexelsPerImage > sMinLargeImageSize;
- if (large_enough)
- {
- // Note: to give small, low-priority textures some chance to be
- // fetched, cut the priority in half if the texture size is larger
- // than 256 * 256 and has a 64 * 64 ready.
- priority *= 0.5f;
- }
- pixel_priority = llclamp(pixel_priority, 0.f, MAX_PRIORITY_PIXEL);
- priority += pixel_priority + PRIORITY_BOOST_LEVEL_FACTOR * mBoostLevel;
- if (mBoostLevel > BOOST_HIGH)
- {
- if (mBoostLevel > BOOST_SUPER_HIGH)
- {
- // For very important textures, always grant the highest
- // priority.
- priority += PRIORITY_BOOST_HIGH_FACTOR;
- }
- else if (mCachedRawImageReady)
- {
- // Note: to give small, low-priority textures some chance to be
- // fetched, if high priority texture has a 64*64 ready, lower
- // its fetching priority.
- setAdditionalDecodePriority(0.5f);
- }
- else
- {
- priority += PRIORITY_BOOST_HIGH_FACTOR;
- }
- }
- if (mAdditionalDecodePriority > 0.f)
- {
- // Priority range += 1,000,000.f-9,000,000.f
- F32 additional = PRIORITY_ADDITIONAL_FACTOR *
- (1.f + mAdditionalDecodePriority *
- MAX_ADDITIONAL_LEVEL_FOR_PRIORITY);
- if (large_enough)
- {
- // Note: to give small, low-priority textures some chance to be
- // fetched, cut the additional priority to a quarter if the
- // texture size is larger than 256 * 256 and has a 64*64 ready.
- additional *= 0.25f;
- }
- priority += additional;
- }
- }
- return priority;
- }
- //static
- F32 LLViewerFetchedTexture::maxDecodePriority()
- {
- return MAX_DECODE_PRIORITY;
- }
- void LLViewerFetchedTexture::setDecodePriority(F32 priority)
- {
- mDecodePriority = priority;
- if (mDecodePriority < F_ALMOST_ZERO)
- {
- mStopFetchingTime = gFrameTimeSeconds;
- }
- }
- void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
- {
- priority = llclamp(priority, 0.f, 1.f);
- if (mAdditionalDecodePriority < priority)
- {
- mAdditionalDecodePriority = priority;
- }
- }
- void LLViewerFetchedTexture::updateVirtualSize()
- {
- if (!mMaxVirtualSizeResetCounter)
- {
- addTextureStats(0.f, false); // Reset
- }
- for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
- {
- U32 list_size = mFaceList[ch].size();
- for (U32 i = 0, count = llmin(mNumFaces[ch], list_size); i < count;
- ++i)
- {
- LLFace* facep = mFaceList[ch][i];
- if (!facep)
- {
- continue;
- }
- LLDrawable* drawable = facep->getDrawable();
- if (drawable && drawable->isRecentlyVisible())
- {
- addTextureStats(facep->getVirtualSize());
- setAdditionalDecodePriority(facep->getImportanceToCamera());
- }
- }
- }
- if (mMaxVirtualSizeResetCounter > 0)
- {
- --mMaxVirtualSizeResetCounter;
- }
- 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;
- }
- //virtual
- void LLViewerFetchedTexture::setBoostLevel(U32 level)
- {
- LLViewerTexture::setBoostLevel(level);
- // Strongly encourage anything boosted to load at full res
- static LLCachedControl<bool> boost_full_res(gSavedSettings,
- "FullResBoostedTextures");
- if (level >= BOOST_HIGH && boost_full_res &&
- LLViewerTexture::sDesiredDiscardBias < 3.f)
- {
- mDesiredDiscardLevel = 0;
- }
- }
- bool LLViewerFetchedTexture::updateFetch()
- {
- if (gUseWireframe && mBoostLevel != BOOST_SCULPTED &&
- mBoostLevel <= BOOST_SUPER_HIGH)
- {
- // Do not fetch the surface textures in wireframe mode.
- // Note: anything above BOOST_SUPER_HIGH level needs to keep being
- // fetched (this also includes avatar textures used to perform viewer-
- // side baking in OpenSim); in the same vein, BOOST_SCULPTED textures
- // are not displayed but used for sculpted object geometry and must
- // therefore keep being fetched. HB
- return false;
- }
- mFetchState = 0;
- mFetchPriority = 0;
- mFetchDeltaTime = mRequestDeltaTime = 999999.f;
- if (mNeedsCreateTexture)
- {
- // We may be fetching still (e.g. waiting on write) but do not check
- // until we have processed the raw data we have.
- return false;
- }
- if (mIsMissingAsset)
- {
- llassert_always(!mHasFetcher);
- return false; // Skip
- }
- if (!mLoadedCallbackList.empty() && mRawImage.notNull())
- {
- // Process any raw image data in callbacks before replacing
- return false;
- }
- S32 current_discard = getCurrentDiscardLevelForFetching();
- S32 desired_discard = getDesiredDiscardLevel();
- F32 decode_priority = llclamp(getDecodePriority(), 0.f,
- MAX_DECODE_PRIORITY);
- if (mIsFetching)
- {
- // Sets mRawDiscardLevel, mRawImage, mAuxRawImage
- S32 fetch_discard = current_discard;
- if (mRawImage.notNull())
- {
- --sRawCount;
- }
- if (mAuxRawImage.notNull())
- {
- --sAuxCount;
- }
- bool finished = gTextureFetchp->getRequestFinished(getID(),
- fetch_discard,
- mRawImage,
- mAuxRawImage,
- mLastHttpGetStatus);
- if (mRawImage.notNull())
- {
- ++sRawCount;
- }
- if (mAuxRawImage.notNull())
- {
- mHasAux = true;
- ++sAuxCount;
- }
- if (finished)
- {
- mIsFetching = false;
- mLastPacketTime = gFrameTimeSeconds;
- }
- else
- {
- mFetchState =
- gTextureFetchp->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())
- {
- mRawDiscardLevel = fetch_discard;
- if (mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0 &&
- (current_discard < 0 || mRawDiscardLevel < current_discard))
- {
- mFullWidth = mRawImage->getWidth() << mRawDiscardLevel;
- mFullHeight = mRawImage->getHeight() << mRawDiscardLevel;
- setTexelsPerImage();
- const S32 max_size = gMaxImageSizeDefault * 2;
- if (mFullWidth > max_size || mFullHeight > max_size)
- {
- // Discard all oversized textures.
- destroyRawImage();
- setIsMissingAsset();
- mRawDiscardLevel = INVALID_DISCARD_LEVEL;
- mIsFetching = false;
- mLastPacketTime = gFrameTimeSeconds;
- }
- else
- {
- mIsRawImageValid = true;
- addToCreateTexture();
- }
- return true;
- }
- else
- {
- // Data is ready but we do not need it (received it already
- // while the fetcher was writing to disk)
- destroyRawImage();
- return false; // done
- }
- }
- // Seconds to wait before cancelling fetching if decode_priority is 0
- constexpr F32 MAX_HOLD_TIME = 5.f;
- if (!mIsFetching)
- {
- if (decode_priority > 0 &&
- (mRawDiscardLevel < 0 ||
- mRawDiscardLevel == INVALID_DISCARD_LEVEL))
- {
- // We finished but received no data
- S32 actual_level = getDiscardLevel();
- if (actual_level < 0)
- {
- if (!mWasDeleted && getFTType() != FTT_MAP_TILE &&
- // Do not complain for an Id which is actually a PBR
- // terrain material one... HB
- !LLTerrain::isAsset(mID))
- {
- llwarns << "No data received for image " << mID
- << ", setting as missing. decode_priority = "
- << decode_priority << " - mRawDiscardLevel = "
- << mRawDiscardLevel << " - current_discard = "
- << current_discard << llendl;
- }
- setIsMissingAsset();
- desired_discard = -1;
- }
- else
- {
- LL_DEBUGS("ViewerTexture") << "Texture: " << mID
- << " - Setting min discard to "
- << current_discard << LL_ENDL;
- if (current_discard >= 0)
- {
- mMinDiscardLevel = current_discard;
- desired_discard = current_discard;
- }
- else
- {
- mMinDiscardLevel = actual_level;
- desired_discard = actual_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.
- LL_DEBUGS("ViewerTexture") << "Texture: " << mID
- << " - We have data but fetch failed to return raw data."
- << LL_ENDL;
- destroyRawImage();
- }
- }
- else if (decode_priority > 0.f ||
- gFrameTimeSeconds - mStopFetchingTime > MAX_HOLD_TIME)
- {
- mStopFetchingTime = gFrameTimeSeconds;
- gTextureFetchp->updateRequestPriority(mID, decode_priority);
- }
- }
- bool make_request = true;
- if (decode_priority <= 0)
- {
- make_request = false;
- }
- else if (mDesiredDiscardLevel > getMaxDiscardLevel())
- {
- make_request = false;
- }
- else if (mNeedsCreateTexture || mIsMissingAsset)
- {
- make_request = false;
- }
- else if (current_discard >= 0 && current_discard <= mMinDiscardLevel)
- {
- make_request = false;
- }
- else if (mCachedRawImage.notNull() && mCachedRawImageReady &&
- (current_discard < 0 || current_discard > mCachedRawDiscardLevel))
- {
- make_request = false;
- switchToCachedImage(); // Use the cached raw data first
- }
- #if 0
- else if (!isJustBound() && mCachedRawImageReady)
- {
- make_request = false;
- }
- #endif
- if (make_request)
- {
- if (mIsFetching)
- {
- if (mRequestedDiscardLevel <= desired_discard)
- {
- make_request = false;
- }
- }
- else if (current_discard >= 0 && current_discard <= desired_discard)
- {
- make_request = false;
- }
- }
- if (make_request)
- {
- mWasDeleted = false;
- S32 w = 0, h = 0, c = 0;
- if (getDiscardLevel() >= 0)
- {
- w = mImageGLp->getWidth(0);
- h = mImageGLp->getHeight(0);
- c = mComponents;
- }
- #if 0 // Not implemented in the Cool VL Viewer
- static LLCachedControl<U32> override_discard(gSavedSettings,
- "TextureDiscardLevel");
- if (override_discard != 0)
- {
- desired_discard = override_discard;
- }
- #endif
- // Bypass texturefetch directly by pulling from LLTextureCache
- bool fetch_request_created =
- gTextureFetchp->createRequest(mFTType, mUrl, getID(),
- getTargetHost(), decode_priority,
- w, h, c, desired_discard, needsAux(),
- mCanUseHTTP);
- if (fetch_request_created)
- {
- mHasFetcher = mIsFetching = true;
- mRequestedDiscardLevel = desired_discard;
- mFetchState =
- gTextureFetchp->getFetchState(mID, mDownloadProgress,
- mRequestedDownloadPriority,
- mFetchPriority, mFetchDeltaTime,
- mRequestDeltaTime, mCanUseHTTP);
- }
- // If createRequest() failed, either we are finishing up a request for
- // this UUID and should wait for it to complete, or we have failed a
- // request for this UUID and there is no need to create another.
- }
- else if (mHasFetcher && !mIsFetching)
- {
- // Only delete requests that do not have received any network data for
- // a while
- constexpr F32 FETCH_IDLE_TIME = 5.f;
- if (gFrameTimeSeconds - mLastPacketTime > FETCH_IDLE_TIME)
- {
- LL_DEBUGS("ViewerTexture") << "Exceeded idle time. Deleting request for texture "
- << mID << LL_ENDL;
- gTextureFetchp->deleteRequest(mID);
- mHasFetcher = false;
- }
- }
- if (mRawImage.isNull() && (mNeedsCreateTexture || mIsRawImageValid))
- {
- llwarns << "Incoherent fetcher state for texture " << mID
- << ": mRawImage is NULL while mNeedsCreateTexture is "
- << mNeedsCreateTexture << " and mIsRawImageValid is "
- << mIsRawImageValid << llendl;
- llassert(false);
- }
- return mIsFetching;
- }
- void LLViewerFetchedTexture::clearFetchedResults()
- {
- if (mNeedsCreateTexture || mIsFetching)
- {
- return;
- }
- cleanup();
- destroyGLTexture();
- if (getDiscardLevel() >= 0) // Sculpty texture; force to invalidate
- {
- mImageGLp->forceToInvalidateGLTexture();
- }
- }
- void LLViewerFetchedTexture::requestWasDeleted()
- {
- mWasDeleted = true;
- resetTextureStats();
- }
- void LLViewerFetchedTexture::setIsMissingAsset(bool is_missing)
- {
- if (is_missing && mWasDeleted)
- {
- mWasDeleted = false;
- LL_DEBUGS("ViewerTexture") << "Fetch request for texture " << mID
- << " was deleted in flight. Not marking as missing asset."
- << LL_ENDL;
- return;
- }
- if (is_missing == mIsMissingAsset)
- {
- // No change
- return;
- }
- if (is_missing)
- {
- #if LL_FIX_MAT_TRANSPARENCY
- notifyAboutMissingAsset();
- #endif
- if (!LLTerrain::isAsset(mID)) // PBR terrain... HB
- {
- if (mUrl.empty())
- {
- llwarns << mID << ": Marking image as missing" << llendl;
- }
- // It is normal to have no map tile on an empty region, but bad if
- // we are failing on a server bake texture.
- else if (getFTType() != FTT_MAP_TILE)
- {
- llwarns << mUrl << ": Marking image as missing" << llendl;
- }
- }
- if (mHasFetcher)
- {
- gTextureFetchp->deleteRequest(mID);
- mHasFetcher = false;
- mIsFetching = false;
- mLastPacketTime = gFrameTimeSeconds;
- mFetchState = 0;
- mFetchPriority = 0;
- }
- }
- else
- {
- llinfos << mID << ": un-flagging missing asset." << llendl;
- }
- mIsMissingAsset = is_missing;
- }
- void LLViewerFetchedTexture::setLoadedCallback(loaded_callback_func loaded_callback,
- S32 discard_level,
- bool keep_imageraw,
- bool needs_aux,
- void* userdata,
- uuid_list_t* src_cb_list,
- bool pause)
- {
- // Do not 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_cb_list);
- }
- }
- else if (pause)
- {
- pauseLoadedCallbacks(src_cb_list);
- }
- LLLoadedCallbackEntry* entryp =
- new LLLoadedCallbackEntry(loaded_callback, discard_level,
- keep_imageraw, userdata,
- src_cb_list, this, pause);
- mLoadedCallbackList.push_back(entryp);
- if (needs_aux)
- {
- mNeedsAux = true;
- }
- if (keep_imageraw)
- {
- mSaveRawImage = true;
- }
- if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)
- {
- if (mHasAux)
- {
- // Trigger a refetch
- forceToRefetchTexture();
- }
- else
- {
- // We need aux data but we have already loaded the image and it did
- // not have any. This is a common case with cached baked textures,
- // so make if an info message instead of a warning...
- llinfos_once << "No aux data available for callback for image: "
- << mID << llendl;
- }
- }
- mLastCallBackActiveTime = 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();
- }
- }
- void LLViewerFetchedTexture::deleteCallbackEntry(const uuid_list_t* cb_list)
- {
- if (mLoadedCallbackList.empty() || !cb_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 == cb_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 != BOOST_PREVIEW)
- {
- if (desired_raw_discard != INVALID_DISCARD_LEVEL)
- {
- mDesiredSavedRawDiscardLevel = desired_raw_discard;
- }
- else
- {
- destroySavedRawImage();
- }
- }
- }
- void LLViewerFetchedTexture::unpauseLoadedCallbacks(const uuid_list_t* cb_list)
- {
- if (!cb_list)
- {
- mPauseLoadedCallBacks = false;
- return;
- }
- bool need_raw = false;
- for (callback_list_t::iterator iter = mLoadedCallbackList.begin(),
- end = mLoadedCallbackList.end();
- iter != end; ++iter)
- {
- LLLoadedCallbackEntry* entryp = *iter;
- if (entryp->mSourceCallbackList == cb_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 uuid_list_t* cb_list)
- {
- if (!cb_list)
- {
- return;
- }
- bool paused = true;
- for (callback_list_t::iterator iter = mLoadedCallbackList.begin(),
- end = mLoadedCallbackList.end();
- iter != end; )
- {
- LLLoadedCallbackEntry* entryp = *iter++;
- if (entryp->mSourceCallbackList == cb_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()
- {
- constexpr F32 MAX_INACTIVE_TIME = 180.f; // In seconds
- constexpr F32 MAX_IDLE_WAIT_TIME = 5.f; // In seconds
- if (mNeedsCreateTexture)
- {
- return false;
- }
- if (mPauseLoadedCallBacks)
- {
- destroyRawImage();
- return false; // Paused
- }
- if (!mIsFetching &&
- sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME)
- {
- clearCallbackEntryList(); // Remove all callbacks.
- return false;
- }
- bool res = false;
- if (isMissingAsset())
- {
- 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 do not 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.
- //
- // We can always do a readback to get a raw discard:
- S32 current_raw_discard = MAX_DISCARD_LEVEL + 1;
- // Current GL quality level:
- S32 best_raw_discard = gl_discard;
- 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);
- // We always decode the aux when we decode the base raw
- best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel);
- 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;
- }
- }
- // Needs just GL
- else 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);
- if (mRawImage.isNull())
- {
- llwarns << "mRawImage is null. Removing callbacks."
- << llendl;
- clearCallbackEntryList();
- mNeedsCreateTexture = mIsRawImageValid = false;
- return false;
- }
- if (mNeedsAux && mAuxRawImage.isNull())
- {
- llwarns << "mAuxRawImage is null. Removing callbacks."
- << llendl;
- clearCallbackEntryList();
- return false;
- }
- }
- // Run raw/auxiliary data callbacks
- if (run_raw_callbacks && mIsRawImageValid &&
- mRawDiscardLevel <= getMaxDiscardLevel())
- {
- // Do callbacks which require raw image data; 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 have loaded all the data there is to load or we have
- // loaded enough to satisfy the interested party, then this is
- // the last time that we are going to call them.
- mLastCallBackActiveTime = sCurrentTime;
- if (mNeedsAux && mAuxRawImage.isNull())
- {
- // This is a very common and normal case for baked
- // textures, so let's make it a llinfos instead of a
- // llwarns... HB
- llinfos << "Raw Image with no Aux Data for callback"
- << llendl;
- }
- bool is_final = mRawDiscardLevel <= entryp->mDesiredDiscard;
- entryp->mLastUsedDiscard = mRawDiscardLevel;
- entryp->mCallback(true, this, mRawImage, mAuxRawImage,
- mRawDiscardLevel, is_final,
- entryp->mUserData);
- if (is_final)
- {
- iter = mLoadedCallbackList.erase(curiter);
- delete entryp;
- }
- res = true;
- }
- }
- }
- // Run GL callbacks
- if (run_gl_callbacks && gl_discard <= getMaxDiscardLevel())
- {
- // 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 is_final = gl_discard <= entryp->mDesiredDiscard;
- entryp->mLastUsedDiscard = gl_discard;
- entryp->mCallback(true, this, NULL, NULL, gl_discard, is_final,
- entryp->mUserData);
- if (is_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 callback, take us off of the image callback list.
- if (mLoadedCallbackList.empty())
- {
- gTextureList.mCallbackList.erase(this);
- }
- else if (!res && !mIsFetching && mForceCallbackFetch &&
- sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME)
- {
- // Waited for long enough but no fetching request issued, force one.
- forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f);
- mForceCallbackFetch = false;
- }
- 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 && mDecodePriority == MAX_DECODE_PRIORITY)
- {
- return;
- }
- gTextureList.forceImmediateUpdate(this);
- }
- LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level)
- {
- llassert_always(mImageGLp.notNull() && discard_level >= 0 &&
- 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)
- {
- mRawImage = new LLImageRaw(getWidth(discard_level),
- getHeight(discard_level),
- getComponents());
- if (mRawImage)
- {
- mRawImage->copy(getSavedRawImage());
- mRawDiscardLevel = discard_level;
- }
- else
- {
- llwarns << "Cannot create a new raw image (out of memory ?)"
- << llendl;
- mRawImage = getSavedRawImage();
- mRawDiscardLevel = mSavedRawDiscardLevel;
- }
- }
- else
- {
- mRawImage = getSavedRawImage();
- mRawDiscardLevel = discard_level;
- }
- }
- else if (mCachedRawDiscardLevel >= discard_level)
- {
- mRawImage = mCachedRawImage;
- mRawDiscardLevel = mCachedRawDiscardLevel;
- }
- else // Cached raw image is good enough, copy it.
- {
- mRawImage = new LLImageRaw(getWidth(discard_level),
- getHeight(discard_level),
- getComponents());
- if (mRawImage)
- {
- mRawImage->copy(mCachedRawImage);
- mRawDiscardLevel = discard_level;
- }
- else
- {
- llwarns << "Cannot create a new raw image (out of memory ?)"
- << llendl;
- mRawImage = mCachedRawImage;
- mRawDiscardLevel = mCachedRawDiscardLevel;
- }
- }
- mIsRawImageValid = true;
- ++sRawCount;
- return mRawImage;
- }
- void LLViewerFetchedTexture::destroyRawImage()
- {
- if (mAuxRawImage.notNull())
- {
- --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()
- {
- // Note: we test for !mNeedsCreateTexture so that if a creation is pending
- // we do not step on it.
- if (!mNeedsCreateTexture && mCachedRawImage.notNull())
- {
- mRawImage = mCachedRawImage;
- if (getComponents() != mRawImage->getComponents())
- {
- // We have changed the number of components, so we need to move any
- // object using this pool to a different pool.
- mComponents = mRawImage->getComponents();
- mImageGLp->setComponents(mComponents);
- gTextureList.dirtyImage(this);
- }
- mIsRawImageValid = true;
- mRawDiscardLevel = mCachedRawDiscardLevel;
- scheduleCreateTexture();
- }
- }
- // Cache the imageraw forcefully.
- //virtual
- void LLViewerFetchedTexture::setCachedRawImage(S32 discard, LLImageRaw* rawp)
- {
- if (rawp != mRawImage.get())
- {
- mCachedRawImage = rawp;
- mCachedRawDiscardLevel = discard;
- mCachedRawImageReady = true;
- }
- }
- void LLViewerFetchedTexture::setCachedRawImage()
- {
- if (mRawImage == mCachedRawImage || !mIsRawImageValid ||
- 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 (mBoostLevel == BOOST_TERRAIN)
- {
- 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;
- }
- if (mRawImage->getComponents() == 5)
- {
- llwarns << "Trying to scale an image (" << mID
- << ") with 5 components !" << llendl;
- mIsRawImageValid = false;
- return;
- }
- // Make a duplicate in case somebody else is using this raw image:
- LLPointer<LLImageRaw> dup = mRawImage->scaled(w >> i, h >> i);
- if (dup.notNull())
- {
- mRawImage = std::move(dup);
- }
- }
- 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()
- {
- if (mRawImage.isNull() || mRawImage == mSavedRawImage ||
- (mSavedRawDiscardLevel >= 0 &&
- mSavedRawDiscardLevel <= mRawDiscardLevel))
- {
- return;
- }
- // This should not happen, but it did on Snowglobe 1.5. Better safe than
- // sorry...
- if (!mRawImage->getData())
- {
- llwarns << "mRawImage->getData() returns NULL" << llendl;
- return;
- }
- mSavedRawDiscardLevel = mRawDiscardLevel;
- mSavedRawImage = new LLImageRaw(mRawImage->getData(),
- mRawImage->getWidth(),
- mRawImage->getHeight(),
- mRawImage->getComponents());
- if (mForceToSaveRawImage &&
- mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
- {
- mForceToSaveRawImage = false;
- }
- mLastReferencedSavedRawImageTime = sCurrentTime;
- }
- void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time)
- {
- mKeptSavedRawImageTime = kept_time;
- mLastReferencedSavedRawImageTime = sCurrentTime;
- if (mSavedRawDiscardLevel > -1 && mSavedRawDiscardLevel <= desired_discard)
- {
- return; // Raw image 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 = mSaveRawImage = false;
- clearCallbackEntryList();
- mSavedRawImage = NULL;
- mForceToSaveRawImage = mSaveRawImage = false;
- mSavedRawDiscardLevel = mDesiredSavedRawDiscardLevel = -1;
- mLastReferencedSavedRawImageTime = mKeptSavedRawImageTime = 0.f;
- }
- LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()
- {
- mLastReferencedSavedRawImageTime = sCurrentTime;
- return mSavedRawImage;
- }
- F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const
- {
- return sCurrentTime - mLastReferencedSavedRawImageTime;
- }
- // Forces 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;
- }
- // This method is a hack to allow reloading manually staled, blurry (i.e.
- // corrupted in cache), or "missing" textures. HB
- void LLViewerFetchedTexture::forceRefetch()
- {
- if (mFTType == FTT_LOCAL_FILE)
- {
- // Cannot "fetch" a file, just reload it. HB
- // *TODO: allow reloading textures on file.
- return;
- }
- // Remove the cache entry
- gTextureCachep->removeFromCache(getID());
- S32 current_discard = getDiscardLevel();
- S32 w = 0, h = 0, c = 0;
- if (current_discard >= 0)
- {
- w = getWidth(0);
- h = getHeight(0);
- c = getComponents();
- }
- if (mHasFetcher)
- {
- gTextureFetchp->deleteRequest(getID());
- }
- cleanup();
- mIsMissingAsset = mWasDeleted = false;
- mDesiredSavedRawDiscardLevel = 0;
- if (mImageGLp)
- {
- mImageGLp->forceToInvalidateGLTexture();
- }
- bool success = gTextureFetchp->createRequest(mFTType, mUrl, getID(),
- getTargetHost(),
- MAX_DECODE_PRIORITY, w, h, c,
- mDesiredSavedRawDiscardLevel,
- needsAux(), mCanUseHTTP);
- if (!success)
- {
- return;
- }
- mHasFetcher = mIsFetching = true;
- gTextureList.forceImmediateUpdate(this);
- mRequestedDiscardLevel = mDesiredSavedRawDiscardLevel;
- mFetchState = gTextureFetchp->getFetchState(mID, mDownloadProgress,
- mRequestedDownloadPriority,
- mFetchPriority,
- mFetchDeltaTime,
- mRequestDeltaTime,
- mCanUseHTTP);
- }
- //-----------------------------------------------------------------------------
- // 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 * 64;
- mDiscardVirtualSize = 0.f;
- mCalculatedDiscardLevel = -1.f;
- }
- //virtual
- S8 LLViewerLODTexture::getType() const
- {
- return LLViewerTexture::LOD_TEXTURE;
- }
- // This is guaranteed to get called periodically for every texture
- //virtual
- void LLViewerLODTexture::processTextureStats()
- {
- updateVirtualSize();
- // Restrict texture resolution to download based on user settings: level 0
- // is 512x512, level 1 is 1024x1024, level 2 is 2048x2048.
- static LLCachedControl<U32> level(gSavedSettings, "TextureMaxResLevel");
- U32 max_size = 1024; // Default.
- if ((level > 1 || mIsMegaTexture) && gMaxImageSizeDefault > 1024)
- {
- max_size = 2048;
- }
- else if (level == 0)
- {
- max_size = 512;
- }
- mMaxVirtualSize = llmin(mMaxVirtualSize, max_size * max_size);
- static LLCachedControl<bool> textures_fullres(gSavedSettings,
- "TextureLoadFullRes");
- static LLCachedControl<U32> min_vsize_discard(gSavedSettings,
- "TextureMinVirtualSizeDiscard");
- F32 min_virtual_size = llmax((F32)min_vsize_discard, 10.f);
- if (textures_fullres)
- {
- mDesiredDiscardLevel = 0;
- }
- // Generate the request priority and render priority
- else if (mDontDiscard || !mUseMipMaps)
- {
- mDesiredDiscardLevel = getMinDiscardLevel();
- }
- else if (mBoostLevel == BOOST_ALM && !LLPipeline::sRenderDeferred)
- {
- mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
- }
- else if (mBoostLevel < BOOST_HIGH && mMaxVirtualSize <= min_virtual_size)
- {
- // If the image has not been significantly visible in a while, we do
- // not want it
- mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,
- MAX_DISCARD_LEVEL + 1);
- }
- else if (!mFullWidth || !mFullHeight)
- {
- mDesiredDiscardLevel = getMaxDiscardLevel();
- }
- else
- {
- static const F32 inv_log_4 = 1.f / logf(4.f);
- 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)
- {
- F32 draw_texels = llclamp(mKnownDrawWidth * mKnownDrawHeight,
- MIN_IMAGE_AREA, max_size * max_size);
- // Use log_4 because we are in square-pixel space, so an image with
- // twice the width and twice the height will have mTexelsPerImage =
- // 4 * draw_size
- discard_level = logf(F32(mTexelsPerImage) / draw_texels) *
- inv_log_4;
- }
- else
- {
- #if 1
- if (isLargeImage() && !isJustBound() &&
- mAdditionalDecodePriority < 0.3f)
- {
- // If it is a big image and not being used recently, nor close
- // to the view point, do not load hi-res data.
- mMaxVirtualSize =
- llmin(mMaxVirtualSize,
- (F32)LLViewerTexture::sMinLargeImageSize);
- }
- #endif
- #if 0
- if (mCalculatedDiscardLevel >= 0.f &&
- fabsf(mMaxVirtualSize - mDiscardVirtualSize) <
- mMaxVirtualSize * 0.2f)
- {
- // < 20% change in virtual size = no change in desired discard
- discard_level = mCalculatedDiscardLevel;
- }
- else
- #endif
- {
- // Calculate the required scale factor of the image using pixels
- // per texel
- discard_level = logf(mTexelsPerImage / mMaxVirtualSize) *
- inv_log_4;
- mDiscardVirtualSize = mMaxVirtualSize;
- mCalculatedDiscardLevel = discard_level;
- }
- }
- if (mBoostLevel < BOOST_HIGH)
- {
- constexpr F32 BIAS_SCALE = 1.1f;
- discard_level += sDesiredDiscardBias;
- discard_level *= BIAS_SCALE;
- }
- discard_level = floorf(discard_level);
- F32 min_discard = getMinDiscardLevel();
- discard_level = llclamp(discard_level, min_discard,
- (F32)MAX_DISCARD_LEVEL);
- // Cannot 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 have 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 do not.
- S32 current_discard = getDiscardLevel();
- if (sDesiredDiscardBias > 0.f && current_discard >= 0 &&
- mBoostLevel < BOOST_HIGH)
- {
- static LLCachedControl<F32> lower_bound(gSavedSettings,
- "TexMemLowerBoundScale");
- F32 texmem_middle_bound_scale =
- 1.f - (1.f - llclamp((F32)lower_bound, 0.75f, 0.9f)) * 0.75f;
- if (!mForceToSaveRawImage &&
- sDesiredDiscardBias >= DESIRED_DISCARD_BIAS_MAX)
- {
- // We need to release texture memory urgently
- scaleDown();
- }
- else if (sBoundTexMemoryMB >
- sMaxBoundTexMemMB * texmem_middle_bound_scale
- && (!getBoundRecently() ||
- mDesiredDiscardLevel >= mCachedRawDiscardLevel))
- {
- // Limit the amount of GL memory bound each frame
- scaleDown();
- }
- else if (sTotalTexMemoryMB >
- sMaxTotalTexMemMB * texmem_middle_bound_scale
- && (!getBoundRecently() ||
- mDesiredDiscardLevel >= mCachedRawDiscardLevel))
- {
- // Only allow GL to have 2x the video card memory
- scaleDown();
- }
- }
- }
- if (mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0)
- {
- mDesiredDiscardLevel = llmin(mDesiredDiscardLevel,
- (S8)mDesiredSavedRawDiscardLevel);
- }
- }
- bool LLViewerLODTexture::scaleDown()
- {
- if (hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())
- {
- switchToCachedImage();
- return true;
- }
- return false;
- }
- //-----------------------------------------------------------------------------
- // LLViewerMediaTexture
- //-----------------------------------------------------------------------------
- //static
- void LLViewerMediaTexture::updateClass()
- {
- static LLCachedControl<U32> lazy_flush_timeout(gSavedSettings,
- "TextureLazyFlushTimeout");
- F32 max_inactive_time = llmax((F32)(lazy_flush_timeout / 2), 5.f);
- #if 0
- // Force to play media.
- gSavedSettings.setBool("EnableStreamingMedia", true);
- #endif
- for (media_map_t::iterator iter = sMediaMap.begin(), end = sMediaMap.end();
- iter != end; )
- {
- media_map_t::iterator cur = iter++;
- LLViewerMediaTexture* mediap = cur->second.get();
- if (mediap && mediap->getNumRefs() == 1) // one reference by sMediaMap
- {
- // Delay some time to delete the media textures to stop endlessly
- // creating and immediately removing media texture.
- if (mediap->getElapsedLastReferenceTime() > max_inactive_time)
- {
- sMediaMap.erase(cur);
- }
- }
- }
- }
- //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.get();
- if (media_tex)
- {
- media_tex->setMediaImpl();
- media_tex->resetLastReferencedTime();
- }
- return media_tex;
- }
- LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, bool usemipmaps,
- LLImageGL* gl_image)
- : LLViewerTexture(id, usemipmaps),
- mMediaImplp(NULL),
- mUpdateVirtualSizeTime(0)
- {
- sMediaMap[id] = this;
- mImageGLp = gl_image;
- if (mImageGLp.isNull())
- {
- generateGLTexture();
- }
- mImageGLp->setAllowCompression(false);
- mImageGLp->setNeedsAlphaAndPickMask(false);
- mIsPlaying = false;
- setMediaImpl();
- setBoostLevel(BOOST_MEDIA);
- LLViewerTexture* tex = gTextureList.findImage(mID);
- if (tex)
- {
- // This media is a parcel media for tex.
- tex->setParcelMedia(this);
- }
- }
- //virtual
- LLViewerMediaTexture::~LLViewerMediaTexture()
- {
- LLViewerTexture* tex = gTextureList.findImage(mID);
- if (tex)
- {
- // This media is a parcel media for tex.
- tex->setParcelMedia(NULL);
- }
- }
- void LLViewerMediaTexture::reinit(bool usemipmaps)
- {
- mUseMipMaps = usemipmaps;
- resetLastReferencedTime();
- if (mImageGLp.notNull())
- {
- mImageGLp->setUseMipMaps(usemipmaps);
- mImageGLp->setNeedsAlphaAndPickMask(false);
- }
- }
- void LLViewerMediaTexture::setUseMipMaps(bool mipmap)
- {
- mUseMipMaps = mipmap;
- if (mImageGLp.notNull())
- {
- mImageGLp->setUseMipMaps(mipmap);
- }
- }
- //virtual
- S8 LLViewerMediaTexture::getType() const
- {
- return LLViewerTexture::MEDIA_TEXTURE;
- }
- void LLViewerMediaTexture::invalidateMediaImpl()
- {
- mMediaImplp = NULL;
- }
- void LLViewerMediaTexture::setMediaImpl()
- {
- if (!mMediaImplp)
- {
- mMediaImplp = LLViewerMedia::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);
- 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)
- {
- LLFace* facep = (*face_list)[i];
- if (facep->isMediaAllowed())
- {
- mMediaFaceList.push_back((*face_list)[i]);
- }
- }
- }
- }
- if (!mMediaImplp)
- {
- return true;
- }
- // For media on a face.
- const std::list<LLVOVolume*>* obj_list = mMediaImplp->getObjectList();
- for (std::list<LLVOVolume*>::const_iterator iter = obj_list->begin(),
- end = obj_list->end();
- iter != end; ++iter)
- {
- LLVOVolume* obj = *iter;
- if (obj->mDrawable.isNull())
- {
- 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(),
- end = mMediaFaceList.end();
- iter != end; ++iter)
- {
- addTextureStats((*iter)->getVirtualSize());
- }
- }
- void LLViewerMediaTexture::addMediaToFace(LLFace* facep)
- {
- if (facep)
- {
- facep->setHasMedia(true);
- }
- if (!mIsPlaying)
- {
- // No need to remove the face because the media is not playing.
- return;
- }
- switchTexture(LLRender::DIFFUSE_MAP, facep);
- }
- void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep)
- {
- if (!facep)
- {
- return;
- }
- facep->setHasMedia(false);
- if (!mIsPlaying)
- {
- // No need to remove the face because the media is not playing.
- return;
- }
- 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());
- if (tex)
- {
- // Increase the reference number by one for tex to avoid deleting
- // it.
- mTextureList.push_back(tex);
- 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.
- }
- // Note: there was a llerrs here, that crashed when the texture was not
- // found in gTextureList, but this is a normal occurrence now (i.e. the
- // texture could have just been pushed in the creation queue and thus not
- // yet present in gTextureList). HB
- }
- //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());
- if (tex)
- {
- for (std::list<LLPointer<LLViewerTexture> >::iterator
- iter = mTextureList.begin();
- iter != mTextureList.end(); ++iter)
- {
- if (*iter == tex)
- {
- // decrease the reference number for tex by one.
- mTextureList.erase(iter);
- return;
- }
- }
- // 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.
- std::vector<const LLTextureEntry*> te_list;
- for (U32 ch = 0; ch < 3; ++ch)
- {
- U32 count = mNumFaces[ch];
- U32 list_size = mFaceList[ch].size();
- if (count > list_size)
- {
- llwarns_once << "Face count greater than face list size for texture channel: "
- << ch << ". Clamping down." << llendl;
- count = list_size;
- }
- for (U32 j = 0; j < count; ++j)
- {
- // All textures are in use.
- te_list.push_back(mFaceList[ch][j]->getTextureEntry());
- }
- }
- if (te_list.empty())
- {
- mTextureList.clear();
- return;
- }
- S32 end = te_list.size();
- for (std::list< LLPointer<LLViewerTexture> >::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.
- {
- // Decrease the reference number for tex by one.
- mTextureList.erase(iter);
- return;
- }
- }
- }
- }
- // Check if it is a parcel media
- for (std::list< LLPointer<LLViewerTexture> >::iterator
- iter = mTextureList.begin();
- iter != mTextureList.end(); ++iter)
- {
- if ((*iter)->getID() == mID)
- {
- // Decrease the reference number for tex by one.
- mTextureList.erase(iter);
- return;
- }
- }
- if (te && te->getID().notNull()) // Should have a texture
- {
- llwarns_sparse << "mTextureList texture reference number is corrupted !"
- << llendl;
- llassert(false);
- }
- }
- void LLViewerMediaTexture::stopPlaying()
- {
- #if 0 // Do not stop the media impl playing here: this breaks non-inworld
- // media (login screen, search, and media browser).
- if (mMediaImplp)
- {
- mMediaImplp->stop();
- }
- #endif
- mIsPlaying = false;
- }
- void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep)
- {
- if (!facep) return;
- // Check if another media is playing on this face and if this is a parcel
- // media, let the prim media win.
- LLViewerTexture* tex = facep->getTexture();
- if (tex && tex != this &&
- tex->getType() == LLViewerTexture::MEDIA_TEXTURE &&
- tex->getID() == mID)
- {
- return;
- }
- if (mIsPlaying)
- {
- // Old textures switch to the media texture
- facep->switchTexture(ch, this);
- return;
- }
- // Switch to old textures.
- const LLTextureEntry* tep = facep->getTextureEntry();
- if (tep)
- {
- LLViewerTexture* texp = NULL;
- if (tep->getID().notNull())
- {
- texp = gTextureList.findImage(tep->getID());
- }
- if (!texp && tep->getID() != mID) // Try parcel media.
- {
- texp = gTextureList.findImage(mID);
- }
- if (!texp)
- {
- texp = LLViewerFetchedTexture::sDefaultImagep;
- }
- facep->switchTexture(ch, texp);
- }
- }
- 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) // We are 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;
- U32 count = mNumFaces[ch];
- U32 list_size = mFaceList[ch].size();
- if (count > list_size)
- {
- llwarns_once << "Face count greater than face list size for texture channel: "
- << ch << ". Clamping down." << llendl;
- count = list_size;
- }
- for (U32 i = count; i; --i)
- {
- // Current face could be removed in this function.
- switchTexture(ch, mFaceList[ch][i - 1]);
- }
- }
- }
- //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)
- {
- U32 count = mNumFaces[ch];
- U32 list_size = mFaceList[ch].size();
- if (count > list_size)
- {
- llwarns_once << "Face count greater than face list size for texture channel: "
- << ch << ". Clamping down." << llendl;
- count = list_size;
- }
- for (U32 i = 0 ; i < count ; ++i)
- {
- LLFace* facep = mFaceList[ch][i];
- if (facep && facep->getDrawable()->isRecentlyVisible())
- {
- addTextureStats(facep->getVirtualSize());
- }
- }
- }
- }
- else // Media is not in playing
- {
- findFaces();
- if (!mMediaFaceList.empty())
- {
- for (std::list<LLFace*>::iterator iter = mMediaFaceList.begin(),
- end = mMediaFaceList.end();
- iter!= end; ++iter)
- {
- LLFace* facep = *iter;
- if (facep && facep->getDrawable() &&
- facep->getDrawable()->isRecentlyVisible())
- {
- addTextureStats(facep->getVirtualSize());
- }
- }
- }
- }
- if (mMaxVirtualSizeResetCounter > 0)
- {
- --mMaxVirtualSizeResetCounter;
- }
- reorganizeFaceList();
- reorganizeVolumeList();
- return mMaxVirtualSize;
- }
|