lltexturefetch.cpp 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176
  1. /**
  2. * @file lltexturefetch.cpp
  3. * @brief Object which fetches textures from the cache and/or network
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewergpl$
  6. *
  7. * Copyright (c) 2000-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include <iostream>
  34. #include "lltexturefetch.h"
  35. #include "llcorebufferarray.h"
  36. #include "llcorebufferstream.h"
  37. #include "llcorehttputil.h"
  38. #include "lldir.h"
  39. #include "llhttpconstants.h"
  40. #include "llhttpretrypolicy.h"
  41. #include "llimage.h"
  42. #include "llimagedecodethread.h"
  43. #include "llimagej2c.h"
  44. #include "llsdutil.h"
  45. #include "llworkerthread.h"
  46. #include "llmessage.h"
  47. #include "llagent.h"
  48. #include "llappviewer.h" // For gFrameTimeSeconds
  49. #include "llgridmanager.h"
  50. #include "llstartup.h"
  51. #include "lltexturecache.h"
  52. #include "llviewercontrol.h"
  53. #include "llviewertexturelist.h"
  54. #include "llviewerregion.h"
  55. #include "llvlcomposition.h" // For LLTerrain::isAsset()
  56. #include "llworld.h"
  57. // Global variable.
  58. LLTextureFetch* gTextureFetchp = NULL;
  59. // Introduction
  60. //
  61. // This is an attempt to document what's going on in here after-the-fact. It is
  62. // a sincere attempt to be accurate but there will be mistakes.
  63. //
  64. //
  65. // Purpose
  66. //
  67. // What is this module trying to do? It accepts requests to load textures at a
  68. // given priority and discard level and notifies the caller when done
  69. // (successfully or not). Additional constraints are:
  70. //
  71. // * Support a local texture cache. Do not hit network when possible to avoid
  72. // it.
  73. // * Use UDP or HTTP as directed or as fallback. HTTP is tried when not
  74. // disabled and a URL is available. UDP when a URL is not available or HTTP
  75. // attempts fail.
  76. // * Asynchronous (using threads). Main thread is not to be blocked or
  77. // burdened.
  78. // * High concurrency. Many requests need to be in-flight and at various stages
  79. // of completion.
  80. // * Tolerate frequent re-prioritizations of requests. Priority is a reflection
  81. // of a camera's viewpoint and as that viewpoint changes, objects and
  82. // textures become more and less relevant and that is expressed at this level
  83. // by priority changes and request cancelations.
  84. //
  85. // The caller interfaces that fall out of the above and shape the
  86. // implementation are:
  87. // * createRequest - Load j2c image via UDP or HTTP at given discard level and
  88. // priority
  89. // * deleteRequest - Request removal of prior request
  90. // * getRequestFinished - Test if request is finished returning data to caller
  91. // * updateRequestPriority - Change priority of existing request
  92. // * getFetchState - Retrieve progress on existing request
  93. //
  94. // Everything else in here is mostly plumbing, metrics and debug.
  95. //
  96. //
  97. // The Work Queue
  98. //
  99. // The two central classes are LLTextureFetch and LLTextureFetchWorker.
  100. // LLTextureFetch combines threading with a priority queue of work requests.
  101. // The priority queue is sorted by a U32 priority derived from the F32 priority
  102. // in the APIs. The *only* work request that receives service time by this
  103. // thread is the highest priority request. All others wait until it is complete
  104. // or a dynamic priority change has re-ordered work.
  105. //
  106. // LLTextureFetchWorker implements the work request and is 1:1 with texture
  107. // fetch requests. Embedded in each is a state machine that walks it through
  108. // the cache, HTTP, UDP, image decode and retry steps of texture acquisition.
  109. //
  110. //
  111. // Threads
  112. //
  113. // Several threads are actively invoking code in this module. They include:
  114. //
  115. // 1. Tmain Main thread of execution
  116. // 2. Ttf LLTextureFetch's worker thread provided by LLQueuedThread
  117. // 3. Ttc LLTextureCache's worker thread
  118. // 4. Tid Image decoder's worker thread
  119. // 5. Thl HTTP library's worker thread
  120. //
  121. //
  122. // Mutexes/Condition Variables
  123. //
  124. // 1. Mt Mutex defined for LLThread's condition variable (base class of
  125. // LLTextureFetch)
  126. // 2. Ct Condition variable for LLThread and used by lock/unlockData().
  127. // 3. Mwtd Special LLWorkerThread mutex used for request deletion
  128. // operations (base class of LLTextureFetch)
  129. // 4. Mfq LLTextureFetch's mutex covering request and command queue
  130. // data.
  131. // 5. Mfnq LLTextureFetch's mutex covering udp and http request
  132. // queue data.
  133. // 6. Mwc Mutex covering LLWorkerClass's members (base class of
  134. // LLTextureFetchWorker). One per request.
  135. // 7. Mw LLTextureFetchWorker's mutex. One per request.
  136. //
  137. //
  138. // Lock Ordering Rules
  139. //
  140. // Not an exhaustive list but shows the order of lock acquisition needed to
  141. // prevent deadlocks. 'A < B' means acquire 'A' before acquiring 'B'.
  142. //
  143. // 1. Mw < Mfnq
  144. // (there are many more...)
  145. //
  146. //
  147. // Method and Member Definitions
  148. //
  149. // With the above, we will try to document what threads can call what methods
  150. // (using T* for any), what locks must be held on entry and are taken out
  151. // during execution and what data is covered by which lock (if any). This
  152. // latter category will be especially prone to error so be skeptical.
  153. //
  154. // A line like: "// Locks: M<xxx>" indicates a method that must be invoked by
  155. // a caller holding the 'M<xxx>' lock. Similarly, "// Threads: T<xxx>" means
  156. // that a caller should be running in the indicated thread.
  157. //
  158. // For data members, a trailing comment like "// M<xxx>" means that the data
  159. // member is covered by the specified lock. Absence of a comment can mean the
  160. // member is unlocked or that I did not bother to do the archaeology. In the
  161. // case of LLTextureFetchWorker, most data members added by the leaf class are
  162. // actually covered by the Mw lock. You may also see "// T<xxx>" which means
  163. // that the member's usage is restricted to one thread (except for perhaps
  164. // construction and destruction) and so explicit locking is not used.
  165. //
  166. // In code, a trailing comment like "// [-+]M<xxx>" indicates a lock acquision
  167. // or release point.
  168. //
  169. //
  170. // Worker Lifecycle
  171. //
  172. // The threading and responder model makes it very likely that other components
  173. // are holding on to a pointer to a worker request. So, uncoordinated deletions
  174. // of requests is a guarantee of memory corruption in a short time. So
  175. // destroying a request involves invocations's of LLQueuedThread/LLWorkerThread
  176. // abort/stop logic that removes workers and puts them on a delete queue for
  177. // 2-phase destruction. That second phase is deferrable by calls to deleteOK()
  178. // which only allow final destruction (via dtor) once deleteOK has determined
  179. // that the request is in a safe state.
  180. //
  181. //
  182. // Worker State Machine
  183. //
  184. // (ASCII art needed)
  185. //
  186. //
  187. // Priority Scheme
  188. //
  189. // [PRIORITY_LOW, PRIORITY_NORMAL) - for WAIT_HTTP_RESOURCE state
  190. // and other wait states
  191. // [PRIORITY_HIGH, PRIORITY_URGENT) - External event delivered,
  192. // rapidly transitioning through states,
  193. // no waiting allowed
  194. //
  195. // By itself, the above work queue model would fail the concurrency and
  196. // liveness requirements of the interface. A high priority request could find
  197. // itself on the head and stalled for external reasons (see VWR-28996). So a
  198. // few additional constraints are required to keep things running:
  199. // * Anything that can make forward progress must be kept at a higher priority
  200. // than anything that cannot.
  201. // * On completion of external events, the associated request needs to be
  202. // elevated beyond the normal range to handle any data delivery and release
  203. // any external resource.
  204. //
  205. // This effort is made to keep higher-priority entities moving forward in their
  206. // state machines at every possible step of processing. It is not entirely
  207. // proven that this produces the experiencial benefits promised.
  208. namespace
  209. {
  210. // The NoOpDeletor is used when passing certain objects (generally the
  211. // LLTextureFetchWorker) in a smart pointer below for passage into the
  212. // LLCore::Http libararies. When the smart pointer is destroyed, no action
  213. // will be taken since we do not in these cases want the object to be
  214. // destroyed at the end of the call.
  215. LL_INLINE void NoOpDeletor(LLCore::HttpHandler*)
  216. {
  217. }
  218. }
  219. static const char* e_state_name[] =
  220. {
  221. "INVALID",
  222. "INIT",
  223. "LOAD_FROM_TEXTURE_CACHE",
  224. "CACHE_POST",
  225. "LOAD_FROM_NETWORK",
  226. "LOAD_FROM_SIMULATOR",
  227. "WAIT_HTTP_RESOURCE",
  228. "WAIT_HTTP_RESOURCE2",
  229. "SEND_HTTP_REQ",
  230. "WAIT_HTTP_REQ",
  231. "DECODE_IMAGE",
  232. "DECODE_IMAGE_UPDATE",
  233. "WRITE_TO_CACHE",
  234. "WAIT_ON_WRITE",
  235. "DONE"
  236. };
  237. class LLTextureFetchWorker final : public LLWorkerClass,
  238. public LLCore::HttpHandler
  239. {
  240. friend class LLTextureFetch;
  241. protected:
  242. LOG_CLASS(LLTextureFetchWorker);
  243. private:
  244. class CacheReadResponder final : public LLTextureCache::ReadResponder
  245. {
  246. protected:
  247. LOG_CLASS(LLTextureFetchWorker::CacheReadResponder);
  248. public:
  249. // Threads: Ttf
  250. LL_INLINE CacheReadResponder(const LLUUID& id, LLImageFormatted* image)
  251. : mID(id),
  252. mStartTime(0.f)
  253. {
  254. setImage(image);
  255. }
  256. LL_INLINE void started() override { mStartTime = gFrameTimeSeconds; }
  257. // Threads: Ttc
  258. void completed(bool success) override
  259. {
  260. if (gTextureFetchp)
  261. {
  262. LLTextureFetchWorker* worker = gTextureFetchp->getWorker(mID);
  263. if (worker)
  264. {
  265. worker->callbackCacheRead(success, mFormattedImage,
  266. mImageSize, mImageLocal);
  267. }
  268. }
  269. }
  270. LL_INLINE bool expired() const
  271. {
  272. constexpr F32 read_timeout = 3.f; // In seconds
  273. return mStartTime > 0.f &&
  274. gFrameTimeSeconds - mStartTime > read_timeout;
  275. }
  276. private:
  277. LLUUID mID;
  278. F32 mStartTime;
  279. };
  280. class CacheWriteResponder final : public LLTextureCache::WriteResponder
  281. {
  282. protected:
  283. LOG_CLASS(LLTextureFetchWorker::CacheWriteResponder);
  284. public:
  285. // Threads: Ttf
  286. LL_INLINE CacheWriteResponder(const LLUUID& id)
  287. : mID(id),
  288. mStartTime(0.f)
  289. {
  290. }
  291. LL_INLINE void started() override { mStartTime = gFrameTimeSeconds; }
  292. // Threads: Ttc
  293. void completed(bool success) override
  294. {
  295. if (gTextureFetchp)
  296. {
  297. LLTextureFetchWorker* worker = gTextureFetchp->getWorker(mID);
  298. if (worker)
  299. {
  300. worker->callbackCacheWrite(success);
  301. }
  302. }
  303. }
  304. LL_INLINE bool expired() const
  305. {
  306. constexpr F32 write_timeout = 3.f; // In seconds
  307. return mStartTime > 0.f &&
  308. gFrameTimeSeconds - mStartTime > write_timeout;
  309. }
  310. private:
  311. LLUUID mID;
  312. F32 mStartTime;
  313. };
  314. class DecodeResponder final : public LLImageDecodeThread::Responder
  315. {
  316. protected:
  317. LOG_CLASS(LLTextureFetchWorker::DecodeResponder);
  318. public:
  319. // Threads: Ttf
  320. DecodeResponder(const LLUUID& id)
  321. : mID(id)
  322. {
  323. }
  324. // Threads: Tid
  325. void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) override
  326. {
  327. if (gTextureFetchp)
  328. {
  329. LLTextureFetchWorker* worker = gTextureFetchp->getWorker(mID);
  330. if (worker)
  331. {
  332. worker->callbackDecoded(success, raw, aux);
  333. }
  334. }
  335. }
  336. private:
  337. LLUUID mID;
  338. };
  339. struct Compare
  340. {
  341. // lhs < rhs
  342. LL_INLINE bool operator()(const LLTextureFetchWorker* lhs,
  343. const LLTextureFetchWorker* rhs) const
  344. {
  345. // Greater priority is "less"
  346. return lhs->mImagePriority > rhs->mImagePriority;
  347. }
  348. };
  349. public:
  350. // Called from LLWorkerThread::processRequest()
  351. // Threads: Ttf
  352. bool doWork(S32 param) override;
  353. // Called from finishRequest() (WORK THREAD)
  354. // Threads: Ttf
  355. void finishWork(S32, bool) override;
  356. // Called from update()
  357. // Threads: Tmain
  358. bool deleteOK() override;
  359. ~LLTextureFetchWorker();
  360. // Threads: Ttf
  361. // Locks: Mw
  362. S32 callbackHttpGet(LLCore::HttpResponse* response, bool partial,
  363. bool success);
  364. // Threads: Ttc
  365. void callbackCacheRead(bool success, LLImageFormatted* image,
  366. S32 imagesize, bool islocal);
  367. // Threads: Ttc
  368. void callbackCacheWrite(bool success);
  369. // Threads: Tid
  370. void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
  371. // Threads: T*
  372. const std::string& setGetStatus(LLCore::HttpStatus status)
  373. {
  374. LLMutexLock lock(mWorkMutex);
  375. mGetStatus = status;
  376. mGetReason = status.toString();
  377. return mGetReason;
  378. }
  379. LL_INLINE void setUrl(const std::string& url)
  380. {
  381. mUrl = url;
  382. }
  383. LL_INLINE void setCanUseHTTP(bool b) { mCanUseHTTP = b; }
  384. LL_INLINE bool getCanUseHTTP() const { return mCanUseHTTP; }
  385. // Inherited from LLCore::HttpHandler
  386. // Threads: Ttf
  387. void onCompleted(LLCore::HttpHandle h, LLCore::HttpResponse* r) override;
  388. protected:
  389. LLTextureFetchWorker(FTType f_type, const std::string& url,
  390. const LLUUID& id, const LLHost& host, F32 priority,
  391. S32 discard, S32 size);
  392. private:
  393. // called from addWork() (MAIN THREAD)
  394. // Threads: Tmain
  395. void startWork(S32 param) override;
  396. // called from doWork() (MAIN THREAD)
  397. // Threads: Tmain
  398. void endWork(S32 param, bool aborted) override;
  399. // Locks: Mw
  400. void resetFormattedData();
  401. // Locks: Mw
  402. void setImagePriority(F32 priority);
  403. // Locks: Mw (ctor invokes without lock)
  404. void setDesiredDiscard(S32 discard, S32 size);
  405. // Threads: T*
  406. // Locks: Mw
  407. bool insertPacket(S32 index, U8* data, S32 size);
  408. // Locks: Mw
  409. void clearPackets();
  410. // Locks: Mw
  411. void setupPacketData();
  412. // Locks: Mw
  413. void removeFromCache();
  414. // Threads: Ttf
  415. // Locks: Mw
  416. bool processSimulatorPackets();
  417. LL_INLINE void lockWorkMutex() { mWorkMutex.lock(); }
  418. LL_INLINE void unlockWorkMutex() { mWorkMutex.unlock(); }
  419. // Locks: Mw
  420. bool acquireHttpSemaphore()
  421. {
  422. llassert(!mHttpHasResource);
  423. if (!gTextureFetchp ||
  424. gTextureFetchp->mHttpSemaphore >= gTextureFetchp->mHttpHighWater)
  425. {
  426. return false;
  427. }
  428. mHttpHasResource = true;
  429. ++gTextureFetchp->mHttpSemaphore;
  430. return true;
  431. }
  432. // Locks: Mw
  433. void releaseHttpSemaphore()
  434. {
  435. llassert(mHttpHasResource);
  436. mHttpHasResource = false;
  437. if (gTextureFetchp)
  438. {
  439. --gTextureFetchp->mHttpSemaphore;
  440. }
  441. }
  442. void calcWorkPriority();
  443. LL_INLINE U32 getStartingPriority()
  444. {
  445. return mWorkPriority | LLQueuedThread::PRIORITY_HIGH;
  446. }
  447. LL_INLINE void setLowPriority()
  448. {
  449. setPriority(mWorkPriority | LLQueuedThread::PRIORITY_LOW);
  450. }
  451. LL_INLINE void setHighPriority()
  452. {
  453. setPriority(mWorkPriority | LLQueuedThread::PRIORITY_HIGH);
  454. }
  455. private:
  456. enum e_state // mState
  457. {
  458. // *NOTE: do not change the order/value of state variables, some code
  459. // depends upon specific ordering/adjacency.
  460. // NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
  461. INVALID = 0,
  462. INIT,
  463. LOAD_FROM_TEXTURE_CACHE,
  464. CACHE_POST,
  465. LOAD_FROM_NETWORK,
  466. LOAD_FROM_SIMULATOR,
  467. WAIT_HTTP_RESOURCE, // Waiting for HTTP resources
  468. WAIT_HTTP_RESOURCE2, // Waiting for HTTP resources
  469. SEND_HTTP_REQ, // Commit to sending as HTTP
  470. WAIT_HTTP_REQ, // Request sent, wait for completion
  471. DECODE_IMAGE,
  472. DECODE_IMAGE_UPDATE,
  473. WRITE_TO_CACHE,
  474. WAIT_ON_WRITE,
  475. DONE
  476. };
  477. enum e_request_state // mSentRequest
  478. {
  479. UNSENT = 0,
  480. QUEUED = 1,
  481. SENT_SIM = 2
  482. };
  483. enum e_write_to_cache_state //mWriteToCacheState
  484. {
  485. NOT_WRITE = 0,
  486. CAN_WRITE = 1,
  487. SHOULD_WRITE = 2
  488. };
  489. e_state mState;
  490. e_write_to_cache_state mWriteToCacheState;
  491. LLPointer<LLImageFormatted> mFormattedImage;
  492. LLPointer<LLImageRaw> mRawImage;
  493. LLPointer<LLImageRaw> mAuxImage;
  494. LLPointer<CacheReadResponder> mReadResponder;
  495. LLPointer<CacheWriteResponder> mWriteResponder;
  496. FTType mFTType;
  497. LLUUID mID;
  498. LLHost mHost;
  499. std::string mUrl;
  500. U8 mType;
  501. F32 mImagePriority;
  502. F32 mRequestedPriority;
  503. U32 mWorkPriority;
  504. S32 mDesiredDiscard;
  505. S32 mSimRequestedDiscard;
  506. S32 mRequestedDiscard;
  507. S32 mLoadedDiscard;
  508. S32 mDecodedDiscard;
  509. LLFrameTimer mRequestedTimer;
  510. LLFrameTimer mFetchTimer;
  511. S32 mRequestedSize;
  512. S32 mRequestedOffset;
  513. S32 mDesiredSize;
  514. S32 mFileSize;
  515. S32 mCachedSize;
  516. e_request_state mSentRequest;
  517. bool mDecoding;
  518. bool mLoaded;
  519. bool mDecoded;
  520. bool mWritten;
  521. bool mNeedsAux;
  522. bool mHaveAllData;
  523. bool mInLocalCache;
  524. bool mCanUseHTTP;
  525. // Set to true when we get the texture via UDP from sim server
  526. bool mCanUseNET;
  527. S32 mRetryAttempt;
  528. S32 mActiveCount;
  529. LLCore::HttpStatus mGetStatus;
  530. std::string mGetReason;
  531. LLAdaptiveRetryPolicy mFetchRetryPolicy;
  532. // Work Data
  533. LLMutex mWorkMutex;
  534. struct PacketData
  535. {
  536. PacketData(U8* data, S32 size)
  537. : mData(data),
  538. mSize(size)
  539. {
  540. }
  541. ~PacketData() { clearData(); }
  542. void clearData() { delete[] mData; mData = NULL; }
  543. U8* mData;
  544. U32 mSize;
  545. };
  546. std::vector<PacketData*> mPackets;
  547. S32 mFirstPacket;
  548. S32 mLastPacket;
  549. U16 mTotalPackets;
  550. U8 mImageCodec;
  551. // Handle of any active request
  552. LLCore::HttpHandle mHttpHandle;
  553. // Refcounted pointer to response data
  554. LLCore::BufferArray* mHttpBufferArray;
  555. S32 mHttpPolicyClass;
  556. // Actual received data size
  557. U32 mHttpReplySize;
  558. // Actual received data offset
  559. U32 mHttpReplyOffset;
  560. // Active request to HTTP library
  561. bool mHttpActive;
  562. // Counts against Fetcher's mHttpSemaphore
  563. bool mHttpHasResource;
  564. };
  565. LLTextureFetchWorker::LLTextureFetchWorker(FTType f_type, // Fetched image type
  566. const std::string& url, // Optional URL
  567. const LLUUID& id, // Image UUID
  568. const LLHost& host, // Simulator host
  569. F32 priority, // Priority
  570. S32 discard, // Desired discard
  571. S32 size) // Desired size
  572. : LLWorkerClass(gTextureFetchp, "TextureFetch"),
  573. LLCore::HttpHandler(),
  574. mState(INIT),
  575. mWriteToCacheState(NOT_WRITE),
  576. mFTType(f_type),
  577. mID(id),
  578. mHost(host),
  579. mUrl(url),
  580. mImagePriority(priority),
  581. mRequestedPriority(0.f),
  582. mWorkPriority(0),
  583. mDesiredDiscard(-1),
  584. mSimRequestedDiscard(-1),
  585. mRequestedDiscard(-1),
  586. mLoadedDiscard(-1),
  587. mDecodedDiscard(-1),
  588. mRequestedSize(0),
  589. mRequestedOffset(0),
  590. mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
  591. mFileSize(0),
  592. mCachedSize(0),
  593. mSentRequest(UNSENT),
  594. mDecoding(false),
  595. mLoaded(false),
  596. mDecoded(false),
  597. mWritten(false),
  598. mNeedsAux(false),
  599. mHaveAllData(false),
  600. mInLocalCache(false),
  601. mCanUseHTTP(true),
  602. mRetryAttempt(0),
  603. mActiveCount(0),
  604. mFirstPacket(0),
  605. mLastPacket(-1),
  606. mTotalPackets(0),
  607. mImageCodec(IMG_CODEC_INVALID),
  608. mHttpHandle(LLCORE_HTTP_HANDLE_INVALID),
  609. mHttpBufferArray(NULL),
  610. mHttpPolicyClass(gTextureFetchp->mHttpPolicyClass),
  611. mHttpActive(false),
  612. mHttpReplySize(0U),
  613. mHttpReplyOffset(0U),
  614. mHttpHasResource(false),
  615. mFetchRetryPolicy(10.0, 3600.0, 2.0, 10)
  616. {
  617. mCanUseNET = !gIsInSecondLife && mUrl.empty();
  618. mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE
  619. : LLImageBase::TYPE_NORMAL;
  620. calcWorkPriority();
  621. if (!gTextureFetchp->mDebugPause)
  622. {
  623. addWork(0, getStartingPriority());
  624. }
  625. setDesiredDiscard(discard, size);
  626. }
  627. LLTextureFetchWorker::~LLTextureFetchWorker()
  628. {
  629. llassert_always(!haveWork());
  630. mWorkMutex.lock();
  631. if (mHttpHasResource)
  632. {
  633. releaseHttpSemaphore();
  634. }
  635. if (gTextureFetchp && mHttpActive)
  636. {
  637. // Issue a cancel on a live request...
  638. gTextureFetchp->getHttpRequest().requestCancel(
  639. mHttpHandle, LLCore::HttpHandler::ptr_t());
  640. }
  641. mFormattedImage = NULL;
  642. clearPackets();
  643. if (mHttpBufferArray)
  644. {
  645. mHttpBufferArray->release();
  646. mHttpBufferArray = NULL;
  647. }
  648. mWorkMutex.unlock();
  649. if (gTextureFetchp)
  650. {
  651. gTextureFetchp->removeFromHTTPQueue(mID);
  652. gTextureFetchp->removeHttpWaiter(mID);
  653. }
  654. }
  655. // Locks: Mw
  656. void LLTextureFetchWorker::clearPackets()
  657. {
  658. for_each(mPackets.begin(), mPackets.end(), DeletePointer());
  659. mPackets.clear();
  660. mTotalPackets = 0;
  661. mLastPacket = -1;
  662. mFirstPacket = 0;
  663. }
  664. // Locks: Mw
  665. void LLTextureFetchWorker::setupPacketData()
  666. {
  667. S32 data_size = 0;
  668. if (mFormattedImage.notNull())
  669. {
  670. data_size = mFormattedImage->getDataSize();
  671. }
  672. if (data_size <= 0)
  673. {
  674. return;
  675. }
  676. // Only used for simulator requests
  677. mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
  678. if (FIRST_PACKET_SIZE +
  679. (mFirstPacket - 1) * MAX_IMG_PACKET_SIZE != data_size)
  680. {
  681. LL_DEBUGS("TextureFetch") << "Bad cached texture size (texture probably cached after an UDP fetch fallback): "
  682. << data_size << " removing " << mID
  683. << LL_ENDL;
  684. removeFromCache();
  685. resetFormattedData();
  686. clearPackets();
  687. }
  688. else if (mFileSize > 0)
  689. {
  690. mLastPacket = mFirstPacket - 1;
  691. mTotalPackets = (mFileSize - FIRST_PACKET_SIZE +
  692. MAX_IMG_PACKET_SIZE - 1) / MAX_IMG_PACKET_SIZE + 1;
  693. }
  694. else
  695. {
  696. // This file was cached using HTTP so we have to refetch the first
  697. // packet
  698. resetFormattedData();
  699. clearPackets();
  700. }
  701. }
  702. // Locks: Mw (ctor invokes without lock)
  703. void LLTextureFetchWorker::calcWorkPriority()
  704. {
  705. static const F32 PRIORITY_SCALE =
  706. (F32)LLQueuedThread::PRIORITY_LOWBITS /
  707. LLViewerFetchedTexture::maxDecodePriority();
  708. mWorkPriority = llmin((U32)LLQueuedThread::PRIORITY_LOWBITS,
  709. (U32)(mImagePriority * PRIORITY_SCALE));
  710. }
  711. // Locks: Mw (ctor invokes without lock)
  712. void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size)
  713. {
  714. if (!gTextureFetchp) return;
  715. bool prioritize = false;
  716. if (mDesiredDiscard != discard)
  717. {
  718. if (!haveWork())
  719. {
  720. calcWorkPriority();
  721. if (!gTextureFetchp->mDebugPause)
  722. {
  723. addWork(0, getStartingPriority());
  724. }
  725. }
  726. else if (mDesiredDiscard < discard)
  727. {
  728. prioritize = true;
  729. }
  730. mDesiredDiscard = discard;
  731. mDesiredSize = size;
  732. }
  733. else if (size > mDesiredSize)
  734. {
  735. mDesiredSize = size;
  736. prioritize = true;
  737. }
  738. mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
  739. if (mState == DONE || (prioritize && mState == INIT))
  740. {
  741. mState = INIT;
  742. setHighPriority();
  743. }
  744. }
  745. // Locks: Mw
  746. void LLTextureFetchWorker::setImagePriority(F32 priority)
  747. {
  748. mImagePriority = priority;
  749. if (mState == DONE ||
  750. fabsf(priority - mImagePriority) > mImagePriority * .05f)
  751. {
  752. calcWorkPriority();
  753. U32 work_priority = mWorkPriority |
  754. (getPriority() &
  755. LLQueuedThread::PRIORITY_HIGHBITS);
  756. setPriority(work_priority);
  757. }
  758. }
  759. // Locks: Mw
  760. void LLTextureFetchWorker::resetFormattedData()
  761. {
  762. if (mHttpBufferArray)
  763. {
  764. mHttpBufferArray->release();
  765. mHttpBufferArray = NULL;
  766. }
  767. if (mFormattedImage.notNull())
  768. {
  769. mFormattedImage->deleteData();
  770. }
  771. mHttpReplySize = 0;
  772. mHttpReplyOffset = 0;
  773. mHaveAllData = false;
  774. }
  775. // Threads: Tmain
  776. void LLTextureFetchWorker::startWork(S32 param)
  777. {
  778. llassert(mFormattedImage.isNull());
  779. }
  780. // Threads: Ttf
  781. bool LLTextureFetchWorker::doWork(S32 param)
  782. {
  783. if (!gTextureFetchp) return true;
  784. LLMutexLock lock(mWorkMutex);
  785. if (mState < DECODE_IMAGE &&
  786. (gTextureFetchp->isQuitting() ||
  787. getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
  788. {
  789. return true; // Aborted fetch
  790. }
  791. if (mImagePriority < F_ALMOST_ZERO &&
  792. (mState == INIT || mState == LOAD_FROM_NETWORK ||
  793. mState == LOAD_FROM_SIMULATOR))
  794. {
  795. return true; // Zero priority, abort
  796. }
  797. if (mState > CACHE_POST && !mCanUseHTTP &&
  798. // NOTE: in SL mCanUseNET is always false, but local textures still
  799. // need to be fetched on pre-caching...
  800. !(gIsInSecondLife || mCanUseNET))
  801. {
  802. return true; // Nowhere to get data, abort.
  803. }
  804. if (gTextureFetchp->mDebugPause)
  805. {
  806. return false; // Debug: pause all work and keep spinning
  807. }
  808. if (mState != DONE)
  809. {
  810. mFetchTimer.reset();
  811. }
  812. if (mState == INIT)
  813. {
  814. mRawImage = NULL ;
  815. mRequestedDiscard = mLoadedDiscard = mDecodedDiscard = -1;
  816. mRequestedSize = mRequestedOffset = mFileSize = mCachedSize = 0;
  817. mLoaded = mDecoded = mWritten = mHaveAllData = false;
  818. mReadResponder = NULL;
  819. mWriteResponder = NULL;
  820. mSentRequest = UNSENT;
  821. if (mHttpBufferArray)
  822. {
  823. mHttpBufferArray->release();
  824. mHttpBufferArray = NULL;
  825. }
  826. mHttpReplySize = mHttpReplyOffset = 0;
  827. clearPackets(); // *TODO: Should not be necessary
  828. mState = LOAD_FROM_TEXTURE_CACHE;
  829. // Minimum desired size is TEXTURE_CACHE_ENTRY_SIZE
  830. mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
  831. LL_DEBUGS("TextureFetch") << mID << ": Priority: "
  832. << llformat("%8.0f", mImagePriority)
  833. << " Desired Discard: " << mDesiredDiscard
  834. << " Desired Size: " << mDesiredSize
  835. << LL_ENDL;
  836. // Fall through
  837. }
  838. if (mState == LOAD_FROM_TEXTURE_CACHE)
  839. {
  840. if (!gTextureCachep)
  841. {
  842. mState = DONE; // We are likely shutting down at this point...
  843. return false;
  844. }
  845. if (mReadResponder.notNull()) // Still waiting for the cache...
  846. {
  847. if (mReadResponder->expired())
  848. {
  849. mLoaded = false;
  850. mReadResponder = NULL;
  851. removeFromCache();
  852. if (mUrl.compare(0, 7, "file://") == 0)
  853. {
  854. llwarns << "Texture " << mID
  855. << " corresponds to an unreadable disk file: "
  856. << mUrl << llendl;
  857. mState = DONE; // Cannot retry a missing file...
  858. return true;
  859. }
  860. LL_DEBUGS("TextureFetch") << "Texture " << mID
  861. << ": cache read timeout; fetching from network."
  862. << LL_ENDL;
  863. mState = LOAD_FROM_NETWORK;
  864. setHighPriority();
  865. }
  866. else
  867. {
  868. // Wait for the cache reply
  869. setLowPriority();
  870. }
  871. return false;
  872. }
  873. // Ask the texture from the cache.
  874. S32 offset = mFormattedImage.isNull() ? 0
  875. : mFormattedImage->getDataSize();
  876. S32 size = mDesiredSize - offset;
  877. if (size > 0)
  878. {
  879. mFileSize = 0;
  880. mLoaded = false;
  881. // Set priority first since Responder may change it
  882. setLowPriority();
  883. bool reading;
  884. mReadResponder = new CacheReadResponder(mID, mFormattedImage);
  885. if (mUrl.compare(0, 7, "file://") == 0)
  886. {
  887. // Read file from local disk
  888. std::string filename = mUrl.substr(7);
  889. reading = gTextureCachep->readFromFile(filename, mID, offset,
  890. size, mReadResponder);
  891. }
  892. else
  893. {
  894. reading = gTextureCachep->readFromCache(mID, offset, size,
  895. mReadResponder);
  896. }
  897. if (reading)
  898. {
  899. // Wait for the cache reply
  900. setLowPriority();
  901. return false;
  902. }
  903. // Failed to post a read to the cache thread queue
  904. mReadResponder = NULL;
  905. }
  906. mState = CACHE_POST;
  907. // Fall through
  908. }
  909. if (mState == CACHE_POST)
  910. {
  911. mCachedSize =
  912. mFormattedImage.isNull() ? 0 : mFormattedImage->getDataSize();
  913. // Successfully loaded
  914. if (mCachedSize >= mDesiredSize || mHaveAllData)
  915. {
  916. // We have enough data, decode it
  917. llassert_always(mFormattedImage->getDataSize() > 0);
  918. mLoadedDiscard = mDesiredDiscard;
  919. if (mLoadedDiscard < 0)
  920. {
  921. llwarns << "Texture " << mID << " mLoadedDiscard is "
  922. << mLoadedDiscard << ", should be >= 0" << llendl;
  923. }
  924. mState = DECODE_IMAGE;
  925. mWriteToCacheState = NOT_WRITE;
  926. LL_DEBUGS("TextureFetch") << mID << ": Cached. Bytes: "
  927. << mFormattedImage->getDataSize()
  928. << ". Size: "
  929. << llformat("%dx%d",
  930. mFormattedImage->getWidth(),
  931. mFormattedImage->getHeight())
  932. << ". Desired discard: "
  933. << mDesiredDiscard
  934. << ". Desired size: " << mDesiredSize
  935. << LL_ENDL;
  936. // Fall through
  937. }
  938. else if (mUrl.compare(0, 7, "file://") == 0)
  939. {
  940. // Failed to load local file, we are done.
  941. llwarns << "Texture " << mID
  942. << " corresponds to an unreadable disk file: " << mUrl
  943. << llendl;
  944. mState = DONE;
  945. return true;
  946. }
  947. else
  948. {
  949. // Need more data
  950. LL_DEBUGS("TextureFetch") << "Texture " << mID << ": not in cache"
  951. << LL_ENDL;
  952. mState = LOAD_FROM_NETWORK;
  953. // Fall through
  954. }
  955. }
  956. if (mState == LOAD_FROM_NETWORK)
  957. {
  958. static LLCachedControl<bool> use_http(gSavedSettings,
  959. "ImagePipelineUseHTTP");
  960. if ((use_http || gIsInSecondLife) && mCanUseHTTP && mUrl.empty())
  961. {
  962. LLViewerRegion* region = NULL;
  963. if (mHost.isInvalid())
  964. {
  965. region = gAgent.getRegion();
  966. }
  967. else
  968. {
  969. region = gWorld.getRegion(mHost);
  970. }
  971. if (!region)
  972. {
  973. // This will happen if not logged in
  974. LL_DEBUGS("TextureFetch") << "Texture " << mID
  975. << ". Region not found for host: "
  976. << mHost << LL_ENDL;
  977. mCanUseHTTP = false;
  978. }
  979. else if (!region->capabilitiesReceived())
  980. {
  981. // Bail till we have received the capabilities
  982. return false;
  983. }
  984. else
  985. {
  986. const std::string& http_url = region->getTextureUrl();
  987. if (http_url.empty())
  988. {
  989. mCanUseHTTP = false;
  990. }
  991. else
  992. {
  993. mUrl = http_url + "?texture_id=" + mID.asString();
  994. // Because this texture has a fixed texture id:
  995. mWriteToCacheState = CAN_WRITE;
  996. }
  997. }
  998. }
  999. // Check for retries to previous server failures.
  1000. F32 wait_seconds;
  1001. if (mFetchRetryPolicy.shouldRetry(wait_seconds))
  1002. {
  1003. if (wait_seconds <= 0.f)
  1004. {
  1005. llinfos <<"Retrying fecth now for texture: " << mID << llendl;
  1006. }
  1007. else
  1008. {
  1009. LL_DEBUGS("TextureFetch") << "Texture " << mID
  1010. << " waiting to retry for "
  1011. << wait_seconds << " seconds"
  1012. << LL_ENDL;
  1013. return false;
  1014. }
  1015. }
  1016. if (mCanUseHTTP && !mUrl.empty())
  1017. {
  1018. mState = WAIT_HTTP_RESOURCE;
  1019. setHighPriority();
  1020. if (mWriteToCacheState != NOT_WRITE)
  1021. {
  1022. mWriteToCacheState = CAN_WRITE;
  1023. }
  1024. // Do not return, fall through to next state
  1025. }
  1026. // NOTE: in SL mCanUseNET is always false, but local textures still
  1027. // need to be fetched on pre-caching...
  1028. else if (mSentRequest == UNSENT && (mCanUseNET || gIsInSecondLife))
  1029. {
  1030. // Add this to the network queue and sit here.
  1031. // LLTextureFetch::sendRequestListToSimulators() will send off a
  1032. // request which, when replied to by the simulator, will cause our
  1033. // state to change to LOAD_FROM_SIMULATOR via
  1034. // LLTextureFetch::receiveImageHeader().
  1035. mWriteToCacheState = CAN_WRITE;
  1036. mRequestedSize = mDesiredSize;
  1037. mRequestedDiscard = mDesiredDiscard;
  1038. mSentRequest = QUEUED;
  1039. gTextureFetchp->addToNetworkQueue(this);
  1040. setLowPriority();
  1041. return false;
  1042. }
  1043. else
  1044. {
  1045. return false;
  1046. }
  1047. }
  1048. if (mState == LOAD_FROM_SIMULATOR)
  1049. {
  1050. if (mFormattedImage.isNull())
  1051. {
  1052. mFormattedImage = new LLImageJ2C;
  1053. }
  1054. if (processSimulatorPackets())
  1055. {
  1056. LL_DEBUGS("TextureFetch") << mID << ": loaded from sim. Bytes: "
  1057. << mFormattedImage->getDataSize()
  1058. << LL_ENDL;
  1059. gTextureFetchp->removeFromNetworkQueue(this, false);
  1060. if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
  1061. {
  1062. LL_DEBUGS("TextureFetch") << "processSimulatorPackets() failed to load buffer"
  1063. << LL_ENDL;
  1064. return true; // Failed
  1065. }
  1066. setHighPriority();
  1067. if (mLoadedDiscard < 0)
  1068. {
  1069. llwarns << "Texture " << mID << " mLoadedDiscard is "
  1070. << mLoadedDiscard << ", should be >= 0" << llendl;
  1071. }
  1072. mState = DECODE_IMAGE;
  1073. mWriteToCacheState = SHOULD_WRITE;
  1074. // Fall through
  1075. }
  1076. else
  1077. {
  1078. gTextureFetchp->addToNetworkQueue(this); // Fail-safe
  1079. setLowPriority();
  1080. return false;
  1081. }
  1082. }
  1083. if (mState == WAIT_HTTP_RESOURCE)
  1084. {
  1085. // NOTE: control the number of the http requests issued to:
  1086. // 1.- avoid opening too many file descriptors at the same time;
  1087. // 2.- control the traffic of http so udp gets bandwidth.
  1088. //
  1089. // If it looks like we are busy, keep this request here. Otherwise,
  1090. // advance into the HTTP states.
  1091. if (!acquireHttpSemaphore())
  1092. {
  1093. mState = WAIT_HTTP_RESOURCE2;
  1094. setLowPriority();
  1095. gTextureFetchp->addHttpWaiter(mID);
  1096. return false;
  1097. }
  1098. mState = SEND_HTTP_REQ;
  1099. // *NOTE: You must invoke releaseHttpSemaphore() if you transition
  1100. // to a state other than SEND_HTTP_REQ or WAIT_HTTP_REQ or abort
  1101. // the request.
  1102. }
  1103. if (mState == WAIT_HTTP_RESOURCE2)
  1104. {
  1105. // Just idle it if we make it to the head...
  1106. return false;
  1107. }
  1108. if (mState == SEND_HTTP_REQ)
  1109. {
  1110. static LLCachedControl<bool> disable_range_req(gSavedSettings,
  1111. "HttpRangeRequestsDisable");
  1112. if (!mCanUseHTTP)
  1113. {
  1114. releaseHttpSemaphore();
  1115. llwarns << "Texture " << mID
  1116. << " got to SEND_HTTP_REQ state but cannot use HTTP; aborting."
  1117. << llendl;
  1118. return true; // Abort
  1119. }
  1120. gTextureFetchp->removeFromNetworkQueue(this, false);
  1121. S32 cur_size = 0;
  1122. if (mFormattedImage.notNull())
  1123. {
  1124. // Amount of data we already have:
  1125. cur_size = mFormattedImage->getDataSize();
  1126. if (mFormattedImage->getDiscardLevel() == 0)
  1127. {
  1128. if (cur_size > 0)
  1129. {
  1130. // We already have all the data, just decode it
  1131. mLoadedDiscard = mFormattedImage->getDiscardLevel();
  1132. setHighPriority();
  1133. if (mLoadedDiscard < 0)
  1134. {
  1135. llwarns << "Texture " << mID << " mLoadedDiscard is "
  1136. << mLoadedDiscard << ", should be >= 0"
  1137. << llendl;
  1138. }
  1139. mState = DECODE_IMAGE;
  1140. releaseHttpSemaphore();
  1141. goto decode_image; // Fall through
  1142. }
  1143. else
  1144. {
  1145. releaseHttpSemaphore();
  1146. llwarns << "Texture " << mID
  1147. << " SEND_HTTP_REQ aborted due to negative or null size: "
  1148. << cur_size << llendl;
  1149. return true; // Abort.
  1150. }
  1151. }
  1152. }
  1153. mRequestedSize = mDesiredSize;
  1154. mRequestedDiscard = mDesiredDiscard;
  1155. mRequestedSize -= cur_size;
  1156. mRequestedOffset = cur_size;
  1157. if (mRequestedOffset)
  1158. {
  1159. // Texture fetching often issues 'speculative' loads that start
  1160. // beyond the end of the actual asset. Some cache/web systems, e.g.
  1161. // Varnish, will respond to this not with a 416 but with a 200 and
  1162. // the entire asset in the response body. By ensuring that we
  1163. // always have a partially satisfiable Range request, we avoid that
  1164. // hit to the network. We just have to deal with the overlapping
  1165. // data which is made somewhat harder by the fact that grid
  1166. // services do not necessarily return the Content-Range header on
  1167. // 206 responses. *Sigh*
  1168. mRequestedOffset -= 1;
  1169. mRequestedSize += 1;
  1170. }
  1171. mHttpHandle = LLCORE_HTTP_HANDLE_INVALID;
  1172. if (!mUrl.empty())
  1173. {
  1174. mRequestedTimer.reset();
  1175. mLoaded = false;
  1176. mGetStatus = LLCore::HttpStatus();
  1177. mGetReason.clear();
  1178. LL_DEBUGS("TextureFetch") << "HTTP GET: " << mID << ". Offset: "
  1179. << mRequestedOffset << ". Bytes: "
  1180. << mRequestedSize << LL_ENDL;
  1181. // For now, in SL, only server bake images use the returned headers
  1182. // to specify a retry-after field. This said, it does not really
  1183. // hurt to check for such a field in all replies (it involves
  1184. // LLCore copying the header field for all replies, but it is a
  1185. // very small time and memory penalty when compared to the rest of
  1186. // the HTTP texture fetching code). RC server channels may soon be
  1187. // using retry-after fields for all textures in SL...
  1188. // *TODO: after the retry-after field will be generalized in SL,
  1189. // make this an option (off by default) for OpenSim grids.
  1190. static LLCachedControl<bool> check_all(gSavedSettings,
  1191. "TextureRetryDelayFromHeader");
  1192. bool with_headers = check_all ||
  1193. (gIsInSecondLife &&
  1194. mFTType == FTT_SERVER_BAKE);
  1195. LLCore::HttpOptions::ptr_t options;
  1196. options = with_headers ? gTextureFetchp->mHttpOptionsWithHeaders
  1197. : gTextureFetchp->mHttpOptions;
  1198. if (disable_range_req)
  1199. {
  1200. // 'Range:' requests may be disabled in which case all HTTP
  1201. // texture fetches result in full fetches. This can be used by
  1202. // people with questionable ISPs or networking gear that do not
  1203. // handle these well.
  1204. mHttpHandle =
  1205. gTextureFetchp->mHttpRequest->requestGet(
  1206. mHttpPolicyClass, mUrl, options,
  1207. gTextureFetchp->mHttpHeaders,
  1208. LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
  1209. }
  1210. else
  1211. {
  1212. // *NOTE: This is an empirical value. Texture fetches have a
  1213. // habit of using a value of 32MB to indicate 'get the rest of
  1214. // the image'. Certain ISPs and network equipments get confused
  1215. // when they see this in a Range: header. So, if the request
  1216. // end is beyond this value, we issue an open-ended
  1217. // "Range: request" (e.g. 'Range: <start>-') which seems to fix
  1218. // the problem.
  1219. constexpr S32 HTTP_REQUESTS_RANGE_END_MAX = 20000000;
  1220. S32 req_size = mRequestedOffset + mRequestedSize >
  1221. HTTP_REQUESTS_RANGE_END_MAX ? 0
  1222. : mRequestedSize;
  1223. // Will call callbackHttpGet when curl request completes
  1224. mHttpHandle =
  1225. gTextureFetchp->mHttpRequest->requestGetByteRange(
  1226. mHttpPolicyClass, mUrl, mRequestedOffset, req_size,
  1227. options, gTextureFetchp->mHttpHeaders,
  1228. LLCore::HttpHandler::ptr_t(this, &NoOpDeletor));
  1229. }
  1230. }
  1231. if (mHttpHandle == LLCORE_HTTP_HANDLE_INVALID)
  1232. {
  1233. LLCore::HttpStatus status =
  1234. gTextureFetchp->mHttpRequest->getStatus();
  1235. llwarns << "HTTP GET request failed for " << mID << ", status: "
  1236. << status.toTerseString() << " - reason: "
  1237. << status.toString() << llendl;
  1238. resetFormattedData();
  1239. // Fallback and try UDP
  1240. if (mCanUseNET)
  1241. {
  1242. llinfos << "Falling back to UDP sim fetch for texture: "
  1243. << mID << llendl;
  1244. mState = INIT;
  1245. mCanUseHTTP = false;
  1246. mUrl.clear();
  1247. setHighPriority();
  1248. }
  1249. releaseHttpSemaphore();
  1250. return !mCanUseNET;
  1251. }
  1252. mHttpActive = true;
  1253. gTextureFetchp->addToHTTPQueue(mID);
  1254. setLowPriority();
  1255. mState = WAIT_HTTP_REQ;
  1256. // Fall through
  1257. }
  1258. if (mState == WAIT_HTTP_REQ)
  1259. {
  1260. // *NOTE: As stated above, all transitions out of this state should
  1261. // call releaseHttpSemaphore().
  1262. if (!mLoaded)
  1263. {
  1264. // *HISTORY: there was a texture timeout test here originally that
  1265. // would cancel a request that was over 120 seconds old. This is
  1266. // probably not a good idea. Particularly rich regions can take an
  1267. // enormous amount of time to load textures. We will revisit the
  1268. // various possible timeout components (total request time,
  1269. // connection time, I/O time, with and without retries, etc) in the
  1270. // future.
  1271. setLowPriority();
  1272. return false;
  1273. }
  1274. S32 cur_size =
  1275. mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
  1276. if (mRequestedSize < 0)
  1277. {
  1278. bool may_be_missing = LLTerrain::isAsset(mID);
  1279. if (mGetStatus == gStatusNotFound)
  1280. {
  1281. if (mWriteToCacheState == NOT_WRITE)
  1282. {
  1283. // Map tiles or server bakes. For map tiles, failed means
  1284. // empty region, which is normal and expected.
  1285. mState = DONE;
  1286. releaseHttpSemaphore();
  1287. if (mFTType != FTT_MAP_TILE)
  1288. {
  1289. llwarns << "Texture missing from server (404): "
  1290. << mUrl << llendl;
  1291. }
  1292. return true;
  1293. }
  1294. // Fallback and try UDP
  1295. if (mCanUseNET && !may_be_missing)
  1296. {
  1297. llinfos << "Falling back to UDP sim fetch for texture: "
  1298. << mID << llendl;
  1299. mState = INIT;
  1300. mCanUseHTTP = false;
  1301. mUrl.clear();
  1302. setHighPriority();
  1303. releaseHttpSemaphore();
  1304. return false;
  1305. }
  1306. }
  1307. else if (mGetStatus == gStatusUnavailable)
  1308. {
  1309. llinfos_once << "Texture server busy (503): " << mUrl
  1310. << llendl;
  1311. }
  1312. else if (mGetStatus == gStatusNotSatisfiable)
  1313. {
  1314. // Allowed, we will accept whatever data we have as complete.
  1315. mHaveAllData = true;
  1316. }
  1317. else
  1318. {
  1319. llinfos << "HTTP GET failed for: " << mUrl << " - Status: "
  1320. << mGetStatus.toTerseString() << " - Reason: "
  1321. << mGetReason << llendl;
  1322. }
  1323. // Fallback and try UDP
  1324. if (mCanUseNET && mFTType != FTT_LOCAL_FILE && !may_be_missing)
  1325. {
  1326. llinfos << "Falling back to UDP sim fetch for texture: " << mID
  1327. << llendl;
  1328. mState = INIT;
  1329. mCanUseHTTP = false;
  1330. mUrl.clear();
  1331. setHighPriority();
  1332. releaseHttpSemaphore();
  1333. return false;
  1334. }
  1335. #if 0 // This causes issues with failures to retry some textures (e.g.
  1336. // for land patches). HB
  1337. if (mFTType != FTT_SERVER_BAKE && mFTType != FTT_MAP_TILE)
  1338. #endif
  1339. {
  1340. mUrl.clear();
  1341. }
  1342. if (cur_size > 0)
  1343. {
  1344. // Use available data
  1345. mLoadedDiscard = mFormattedImage->getDiscardLevel();
  1346. setHighPriority();
  1347. if (mLoadedDiscard < 0)
  1348. {
  1349. llwarns << "Texture " << mID << " mLoadedDiscard is "
  1350. << mLoadedDiscard << ", should be >= 0" << llendl;
  1351. }
  1352. mState = DECODE_IMAGE;
  1353. releaseHttpSemaphore();
  1354. goto decode_image; // Fall through
  1355. }
  1356. // Fail harder
  1357. resetFormattedData();
  1358. mState = DONE;
  1359. releaseHttpSemaphore();
  1360. if (!may_be_missing)
  1361. {
  1362. llwarns << "Texture " << mID << ": failed harder" << llendl;
  1363. }
  1364. return true; // Failed
  1365. }
  1366. if (mWriteToCacheState != NOT_WRITE)
  1367. {
  1368. // Clear the url since we are done with the fetch. Note: mUrl is
  1369. // used to check is fetching is required so failure to clear it
  1370. // will force an http fetch next time the texture is requested,
  1371. // even if the data have already been fetched.
  1372. mUrl.clear();
  1373. }
  1374. if (!mHttpBufferArray || !mHttpBufferArray->size())
  1375. {
  1376. // No data received.
  1377. if (mHttpBufferArray)
  1378. {
  1379. mHttpBufferArray->release();
  1380. mHttpBufferArray = NULL;
  1381. }
  1382. // Abort.
  1383. mState = DONE;
  1384. llwarns << "Texture " << mID << ": no data received" << llendl;
  1385. releaseHttpSemaphore();
  1386. return true;
  1387. }
  1388. S32 append_size = mHttpBufferArray->size();
  1389. S32 total_size = cur_size + append_size;
  1390. S32 src_offset = 0;
  1391. llassert_always(append_size == mRequestedSize);
  1392. if (mHttpReplyOffset && (S32)mHttpReplyOffset != cur_size)
  1393. {
  1394. // In case of a partial response, our offset may not be trivially
  1395. // contiguous with the data we have. Get back into alignment.
  1396. if ((S32)mHttpReplyOffset > cur_size ||
  1397. cur_size > (S32)mHttpReplyOffset + append_size)
  1398. {
  1399. llwarns << "Partial HTTP response produces break in image data for texture "
  1400. << mID << ". Retrying load." << llendl;
  1401. #if LL_CURL_BUG // *HACK: HTTP pipelining is buggy in libcurl versions after
  1402. // v7.47 and is causing this kind of issue, so let's turn it
  1403. // off, the time for the pipelined connection to get closed, so
  1404. // that we can restart with fresh ones later... HB
  1405. if (gAppViewerp->getAppCoreHttp().isPipeliningOn())
  1406. {
  1407. gAppViewerp->getAppCoreHttp().setPipelinedTempOff();
  1408. }
  1409. #endif
  1410. removeFromCache();
  1411. resetFormattedData();
  1412. if (mCanUseNET)
  1413. {
  1414. // Fallback and try UDP
  1415. llinfos << "Falling back to UDP sim fetch for texture: "
  1416. << mID << llendl;
  1417. mCanUseHTTP = false;
  1418. mUrl.clear();
  1419. }
  1420. mState = INIT;
  1421. setHighPriority();
  1422. releaseHttpSemaphore();
  1423. return false;
  1424. }
  1425. src_offset = cur_size - mHttpReplyOffset;
  1426. append_size -= src_offset;
  1427. total_size -= src_offset;
  1428. // Make requested values reflect useful part:
  1429. mRequestedSize -= src_offset;
  1430. mRequestedOffset += src_offset;
  1431. }
  1432. if (mFormattedImage.isNull())
  1433. {
  1434. // For now, create formatted image based on extension
  1435. std::string extension = gDirUtil.getExtension(mUrl);
  1436. mFormattedImage =
  1437. LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension));
  1438. if (mFormattedImage.isNull())
  1439. {
  1440. mFormattedImage = new LLImageJ2C; // Default
  1441. }
  1442. }
  1443. if (mHaveAllData) // The image file is fully loaded.
  1444. {
  1445. mFileSize = total_size;
  1446. }
  1447. else // The file size is unknown.
  1448. {
  1449. // Flag the file is not fully loaded.
  1450. mFileSize = total_size + 1;
  1451. }
  1452. U8* buffer = (U8*)allocate_texture_mem(total_size);
  1453. if (!buffer)
  1454. {
  1455. // Fail because of out of memory error
  1456. resetFormattedData();
  1457. mState = DONE;
  1458. llwarns << "Out of memory: could not complete texture fetch for "
  1459. << mID << llendl;
  1460. releaseHttpSemaphore();
  1461. return true; // Failed
  1462. }
  1463. if (cur_size > 0)
  1464. {
  1465. memcpy(buffer, mFormattedImage->getData(), cur_size);
  1466. }
  1467. mHttpBufferArray->read(src_offset, (char*)buffer + cur_size,
  1468. append_size);
  1469. // NOTE: setData releases current data and owns new data (buffer)
  1470. mFormattedImage->setData(buffer, total_size);
  1471. // Done with buffer array
  1472. mHttpBufferArray->release();
  1473. mHttpBufferArray = NULL;
  1474. mHttpReplySize = 0;
  1475. mHttpReplyOffset = 0;
  1476. mLoadedDiscard = mRequestedDiscard;
  1477. if (mLoadedDiscard < 0)
  1478. {
  1479. llwarns << "Texture " << mID << " mLoadedDiscard is "
  1480. << mLoadedDiscard << ", should be >= 0" << llendl;
  1481. }
  1482. mState = DECODE_IMAGE;
  1483. if (mWriteToCacheState != NOT_WRITE)
  1484. {
  1485. mWriteToCacheState = SHOULD_WRITE;
  1486. }
  1487. setHighPriority();
  1488. releaseHttpSemaphore();
  1489. // Fall through
  1490. }
  1491. decode_image:
  1492. if (mState == DECODE_IMAGE)
  1493. {
  1494. // Set priority first since Responder may change it
  1495. setLowPriority();
  1496. if (mDesiredDiscard < 0 || mFormattedImage.isNull() ||
  1497. mFormattedImage->getDataSize() <= 0 ||
  1498. mLoadedDiscard < 0 || !gImageDecodeThreadp)
  1499. {
  1500. // We aborted, or decode entered with invalid mFormattedImage,
  1501. // or decode entered with invalid mLoadedDiscard: do not decode.
  1502. mState = DONE;
  1503. goto fetch_done; // Fall through
  1504. }
  1505. mRawImage = NULL;
  1506. mAuxImage = NULL;
  1507. S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
  1508. mDecoded = false;
  1509. mState = DECODE_IMAGE_UPDATE;
  1510. LL_DEBUGS("TextureFetch") << "Decoding " << mID << ". Bytes: "
  1511. << mFormattedImage->getDataSize()
  1512. << ". Discard: " << discard << ". All data: "
  1513. << mHaveAllData << LL_ENDL;
  1514. mDecoding =
  1515. gImageDecodeThreadp->decodeImage(mFormattedImage, discard,
  1516. mNeedsAux,
  1517. new DecodeResponder(mID));
  1518. // Fall through
  1519. }
  1520. if (mState == DECODE_IMAGE_UPDATE)
  1521. {
  1522. if (!mDecoded)
  1523. {
  1524. return false;
  1525. }
  1526. if (mDecodedDiscard < 0)
  1527. {
  1528. LL_DEBUGS("TextureFetch") << "Failed to decode " << mID << LL_ENDL;
  1529. if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)
  1530. {
  1531. // Cache file should be deleted, try again
  1532. LL_DEBUGS("TextureFetch") << "Texture" << mID
  1533. << ": decode of cached file failed (removed), retrying."
  1534. << LL_ENDL;
  1535. llassert_always(!mDecoding);
  1536. mFormattedImage = NULL;
  1537. ++mRetryAttempt;
  1538. setHighPriority();
  1539. mState = INIT;
  1540. return false;
  1541. }
  1542. LL_DEBUGS("TextureFetch") << "Unable to load texture " << mID
  1543. << " after " << mRetryAttempt
  1544. << " retries." << LL_ENDL;
  1545. mState = DONE; // Failed
  1546. // Fall through
  1547. }
  1548. else
  1549. {
  1550. llassert_always(mRawImage.notNull());
  1551. LL_DEBUGS("TextureFetch") << mID << " decoded. Discard: "
  1552. << mDecodedDiscard << ". Raw image: "
  1553. << llformat("%dx%d",
  1554. mRawImage->getWidth(),
  1555. mRawImage->getHeight())
  1556. << LL_ENDL;
  1557. setHighPriority();
  1558. mState = WRITE_TO_CACHE;
  1559. }
  1560. // Fall through
  1561. }
  1562. if (mState == WRITE_TO_CACHE)
  1563. {
  1564. if (!gTextureCachep || mWriteToCacheState != SHOULD_WRITE ||
  1565. mFormattedImage.isNull())
  1566. {
  1567. // If the cache is destroyed, or we are a local texture or we did
  1568. // not actually receive any new data, or we failed to load
  1569. // anything, skip.
  1570. mState = DONE;
  1571. goto fetch_done; // Fall through
  1572. }
  1573. S32 datasize = mFormattedImage->getDataSize();
  1574. if (datasize <= 0)
  1575. {
  1576. // This should not happen... But has been seen happening once by
  1577. // one user, who then hit the llassert_always(datasize) that used
  1578. // to be there... Use proper fallback code (skip) instead. HB
  1579. mState = DONE;
  1580. goto fetch_done; // Fall through
  1581. }
  1582. // Set priority first since Responder may change it:
  1583. setLowPriority();
  1584. if (mFileSize < datasize)
  1585. {
  1586. // This could happen when http fetching and sim fetching mixed.
  1587. if (mHaveAllData)
  1588. {
  1589. mFileSize = datasize;
  1590. }
  1591. else
  1592. {
  1593. mFileSize = datasize + 1; // flag not fully loaded.
  1594. }
  1595. }
  1596. mWritten = false;
  1597. mState = WAIT_ON_WRITE;
  1598. mWriteResponder = new CacheWriteResponder(mID);
  1599. if (!gTextureCachep->writeToCache(mID, mFormattedImage->getData(),
  1600. datasize, mFileSize, mRawImage,
  1601. mDecodedDiscard, mWriteResponder))
  1602. {
  1603. // Failed to post to the cache write queue, or read-only cache
  1604. mWriteResponder = NULL;
  1605. mState = DONE;
  1606. }
  1607. // Fall through
  1608. }
  1609. if (mState == WAIT_ON_WRITE)
  1610. {
  1611. if (mWritten)
  1612. {
  1613. mState = DONE;
  1614. // Fall through
  1615. }
  1616. else if (!gTextureCachep || mWriteResponder.isNull() ||
  1617. mWriteResponder->expired())
  1618. {
  1619. llwarns << "Failed to cache texture " << mID << llendl;
  1620. mWriteResponder = NULL;
  1621. mState = DONE;
  1622. // Fall through
  1623. }
  1624. else
  1625. {
  1626. // We are waiting for this write to complete before we can receive
  1627. // more data (we cannot touch mFormattedImage until the write
  1628. // completes).
  1629. return false;
  1630. }
  1631. }
  1632. fetch_done:
  1633. if (mState == DONE)
  1634. {
  1635. if (mDecodedDiscard > 0 && mDesiredDiscard < mDecodedDiscard)
  1636. {
  1637. // More data was requested, return to INIT
  1638. mState = INIT;
  1639. setHighPriority();
  1640. return false;
  1641. }
  1642. setLowPriority();
  1643. return true;
  1644. }
  1645. return false;
  1646. }
  1647. // Threads: Ttf
  1648. //virtual
  1649. void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle,
  1650. LLCore::HttpResponse* response)
  1651. {
  1652. mWorkMutex.lock();
  1653. mHttpActive = false;
  1654. bool success = true;
  1655. bool partial = false;
  1656. LLCore::HttpStatus status(response->getStatus());
  1657. if (!status && mFTType == FTT_SERVER_BAKE)
  1658. {
  1659. llinfos << mID << " state " << e_state_name[mState] << llendl;
  1660. mFetchRetryPolicy.onFailure(response);
  1661. F32 retry_after;
  1662. if (gTextureFetchp && mFetchRetryPolicy.shouldRetry(retry_after))
  1663. {
  1664. llinfos << "Texture: " << mID << " - State: "
  1665. << e_state_name[mState] << ". Will retry after "
  1666. << retry_after
  1667. << " seconds, resetting state to LOAD_FROM_NETWORK"
  1668. << llendl;
  1669. gTextureFetchp->removeFromHTTPQueue(mID, 0);
  1670. setGetStatus(status);
  1671. releaseHttpSemaphore();
  1672. mState = LOAD_FROM_NETWORK;
  1673. mWorkMutex.unlock();
  1674. return;
  1675. }
  1676. else
  1677. {
  1678. llwarns << "Texture: " << mID << " - State: "
  1679. << e_state_name[mState] << ". Will not retry" << llendl;
  1680. }
  1681. }
  1682. else
  1683. {
  1684. mFetchRetryPolicy.onSuccess();
  1685. }
  1686. if (!status)
  1687. {
  1688. success = false;
  1689. // Missing map tiles and local files are normal, do not complain about
  1690. // them. Also, do not complain if the Id was a "terrain asset" which is
  1691. // in the end a material and not a texture. HB
  1692. if (mFTType != FTT_MAP_TILE && mFTType != FTT_LOCAL_FILE &&
  1693. !LLTerrain::isAsset(mID))
  1694. {
  1695. llwarns << "Texture: " << mID << " CURL GET FAILED, status: "
  1696. << status.toTerseString() << " - reason: "
  1697. << setGetStatus(status) << llendl;
  1698. }
  1699. }
  1700. else
  1701. {
  1702. LL_DEBUGS("TextureFetch") << "HTTP complete: " << mID
  1703. << " status: " << status.toTerseString()
  1704. << " '" << setGetStatus(status) << "'"
  1705. << LL_ENDL;
  1706. // A warning about partial (HTTP 206) data. Some grid services do *not*
  1707. // return a 'Content-Range' header in the response to Range requests
  1708. // with a 206 status. We are forced to assume we get what we asked for
  1709. // in these cases until we can fix the services.
  1710. partial = status == gStatusPartialContent;
  1711. }
  1712. S32 data_size = callbackHttpGet(response, partial, success);
  1713. if (gTextureFetchp)
  1714. {
  1715. gTextureFetchp->removeFromHTTPQueue(mID, data_size);
  1716. }
  1717. mWorkMutex.unlock();
  1718. }
  1719. // Threads: Tmain
  1720. void LLTextureFetchWorker::endWork(S32 param, bool aborted)
  1721. {
  1722. mFormattedImage = NULL;
  1723. }
  1724. // Threads: Ttf
  1725. //virtual
  1726. void LLTextureFetchWorker::finishWork(S32, bool)
  1727. {
  1728. mDecoding = false;
  1729. mReadResponder = NULL;
  1730. mWriteResponder = NULL;
  1731. }
  1732. // LLQueuedThread's update() method is asking if it is okay to delete this
  1733. // worker. You will notice we are not locking in here which is a slight
  1734. // concern. Caller is expected to have made this request 'quiet' by whatever
  1735. // means...
  1736. // Threads: Tmain
  1737. //virtual
  1738. bool LLTextureFetchWorker::deleteOK()
  1739. {
  1740. if (!gTextureFetchp)
  1741. {
  1742. return true;
  1743. }
  1744. if (mHttpActive || mDecoding || mReadResponder.notNull() ||
  1745. mWriteResponder.notNull())
  1746. {
  1747. // HTTP library has a pointer to this worker and will dereference it to
  1748. // do notification. Also, the image decoder thread and texture cache
  1749. // pools cannot cancel a queued decode request.
  1750. return false;
  1751. }
  1752. if (mState == WAIT_HTTP_RESOURCE2 && gTextureFetchp->isHttpWaiter(mID))
  1753. {
  1754. // Do not delete the worker out from under the releaseHttpWaiters()
  1755. // method. Keep the pointers valid, clean up after that method has
  1756. // recognized the cancelation and removed the UUID from the waiter
  1757. // list.
  1758. return false;
  1759. }
  1760. if (haveWork() &&
  1761. // Not ok to delete from these states
  1762. (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))
  1763. {
  1764. return false;
  1765. }
  1766. return true;
  1767. }
  1768. // Threads: Ttf
  1769. void LLTextureFetchWorker::removeFromCache()
  1770. {
  1771. if (!mInLocalCache && gTextureCachep)
  1772. {
  1773. gTextureCachep->removeFromCache(mID);
  1774. }
  1775. }
  1776. // Threads: Ttf
  1777. // Locks: Mw
  1778. bool LLTextureFetchWorker::processSimulatorPackets()
  1779. {
  1780. if (mFormattedImage.isNull() || mRequestedSize < 0)
  1781. {
  1782. // Not sure how we got here, but not a valid state, abort !
  1783. llassert_always(!mDecoding);
  1784. mFormattedImage = NULL;
  1785. return true;
  1786. }
  1787. if (mLastPacket >= mFirstPacket)
  1788. {
  1789. S32 buffer_size = mFormattedImage->getDataSize();
  1790. for (S32 i = mFirstPacket; i <= mLastPacket; ++i)
  1791. {
  1792. llassert_always(mPackets[i]);
  1793. buffer_size += mPackets[i]->mSize;
  1794. }
  1795. bool have_all_data = mLastPacket >= mTotalPackets - 1;
  1796. if (mRequestedSize <= 0)
  1797. {
  1798. // We received a packed but did not issue a request yet (edge
  1799. // case). Return true (we are "done") since we did not request
  1800. // anything.
  1801. return true;
  1802. }
  1803. if (buffer_size >= mRequestedSize || have_all_data)
  1804. {
  1805. /// We have enough (or all) data
  1806. if (have_all_data)
  1807. {
  1808. mHaveAllData = true;
  1809. }
  1810. S32 cur_size = mFormattedImage->getDataSize();
  1811. if (buffer_size > cur_size)
  1812. {
  1813. /// We have new data
  1814. U8* buffer = (U8*)allocate_texture_mem(buffer_size);
  1815. if (!buffer)
  1816. {
  1817. // Out of memory: abort
  1818. mHaveAllData = false;
  1819. mFormattedImage = NULL;
  1820. llwarns << "Out of memory: could not complete texture fetch for "
  1821. << mID << llendl;
  1822. return true;
  1823. }
  1824. S32 offset = 0;
  1825. if (cur_size > 0 && mFirstPacket > 0)
  1826. {
  1827. memcpy(buffer, mFormattedImage->getData(), cur_size);
  1828. offset = cur_size;
  1829. }
  1830. for (S32 i = mFirstPacket; i <= mLastPacket; ++i)
  1831. {
  1832. memcpy(buffer + offset, mPackets[i]->mData,
  1833. mPackets[i]->mSize);
  1834. offset += mPackets[i]->mSize;
  1835. }
  1836. // NOTE: setData releases current data
  1837. mFormattedImage->setData(buffer, buffer_size);
  1838. }
  1839. mLoadedDiscard = mRequestedDiscard;
  1840. return true;
  1841. }
  1842. }
  1843. return false;
  1844. }
  1845. bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)
  1846. {
  1847. mRequestedTimer.reset();
  1848. if (index >= mTotalPackets)
  1849. {
  1850. LL_DEBUGS("TextureFetch") << "Received image packet " << index
  1851. << " > max: " << mTotalPackets
  1852. << " for image: " << mID << LL_ENDL;
  1853. return false;
  1854. }
  1855. if (index > 0 && index < mTotalPackets - 1 && size != MAX_IMG_PACKET_SIZE)
  1856. {
  1857. LL_DEBUGS("TextureFetch") << "Received bad sized packet: " << index
  1858. << ", " << size << " != "
  1859. << MAX_IMG_PACKET_SIZE << " for image: "
  1860. << mID << LL_ENDL;
  1861. return false;
  1862. }
  1863. if (index >= (S32)mPackets.size())
  1864. {
  1865. // Initialize v to NULL pointers
  1866. mPackets.resize(index + 1, NULL);
  1867. }
  1868. else if (mPackets[index])
  1869. {
  1870. LL_DEBUGS("TextureFetch") << "Received duplicate packet: " << index
  1871. << " for image: " << mID << LL_ENDL;
  1872. return false;
  1873. }
  1874. mPackets[index] = new PacketData(data, size);
  1875. while (mLastPacket + 1 < (S32)mPackets.size() && mPackets[mLastPacket + 1])
  1876. {
  1877. ++mLastPacket;
  1878. }
  1879. return true;
  1880. }
  1881. // Threads: Ttf
  1882. // Locks: Mw
  1883. S32 LLTextureFetchWorker::callbackHttpGet(LLCore::HttpResponse* response,
  1884. bool partial, bool success)
  1885. {
  1886. S32 data_size = 0;
  1887. if (mState != WAIT_HTTP_REQ)
  1888. {
  1889. llwarns << "Called for an unrequested fetch worker: " << mID
  1890. << " - req = " << mSentRequest << " - state = " << mState
  1891. << llendl;
  1892. return data_size;
  1893. }
  1894. if (mLoaded)
  1895. {
  1896. llwarns << "Ignoring duplicate callback for " << mID << llendl;
  1897. return data_size;
  1898. }
  1899. if (success)
  1900. {
  1901. // Get length of stream:
  1902. LLCore::BufferArray * body(response->getBody());
  1903. data_size = body ? body->size() : 0;
  1904. LL_DEBUGS("TextureFetch") << "HTTP received " << mID << ": "
  1905. << data_size << " bytes." << LL_ENDL;
  1906. if (data_size > 0)
  1907. {
  1908. // *TODO: set the formatted image data here directly to avoid the
  1909. // copy
  1910. // Hold on to body for later copy
  1911. llassert_always(!mHttpBufferArray);
  1912. body->addRef();
  1913. mHttpBufferArray = body;
  1914. if (partial)
  1915. {
  1916. unsigned int offset(0), length(0), full_length(0);
  1917. response->getRange(&offset, &length, &full_length);
  1918. if (!offset && !length)
  1919. {
  1920. // This is the case where we receive a 206 status but there
  1921. // was not a useful Content-Range header in the response.
  1922. // This could be because it was badly formatted but is more
  1923. // likely due to capabilities services which scrub headers
  1924. // from responses. Assume we got what we asked for...
  1925. mHttpReplySize = data_size;
  1926. mHttpReplyOffset = mRequestedOffset;
  1927. }
  1928. else
  1929. {
  1930. mHttpReplySize = length;
  1931. mHttpReplyOffset = offset;
  1932. }
  1933. }
  1934. if (!partial)
  1935. {
  1936. // Response indicates this is the entire asset regardless of
  1937. // our asking for a byte range. Mark it so and drop any partial
  1938. // data we might have so that the current response body becomes
  1939. // the entire dataset.
  1940. if (data_size <= mRequestedOffset)
  1941. {
  1942. llwarns << "Fetched entire texture " << mID
  1943. << " when it was expected to be marked complete. mImageSize: "
  1944. << mFileSize << " - datasize: "
  1945. << mFormattedImage->getDataSize() << llendl;
  1946. }
  1947. mHaveAllData = true;
  1948. llassert_always(!mDecoding);
  1949. mFormattedImage = NULL; // Discard any previous data we had
  1950. }
  1951. else if (data_size < mRequestedSize)
  1952. {
  1953. mHaveAllData = true;
  1954. }
  1955. else if (data_size > mRequestedSize)
  1956. {
  1957. // *TODO: This should not be happening any more (REALLY do not
  1958. // expect this anymore)
  1959. llwarns << "data_size = " << data_size << " > requested: "
  1960. << mRequestedSize << llendl;
  1961. mHaveAllData = true;
  1962. llassert_always(!mDecoding);
  1963. mFormattedImage = NULL; // Discard any previous data we had
  1964. }
  1965. }
  1966. else
  1967. {
  1968. // We requested data but received none (and no error), so
  1969. // presumably we have all of it.
  1970. mHaveAllData = true;
  1971. }
  1972. mRequestedSize = data_size;
  1973. }
  1974. else
  1975. {
  1976. mRequestedSize = -1; // Error
  1977. }
  1978. mLoaded = true;
  1979. setHighPriority();
  1980. return data_size;
  1981. }
  1982. // Threads: Ttc
  1983. void LLTextureFetchWorker::callbackCacheRead(bool success,
  1984. LLImageFormatted* image,
  1985. S32 imagesize, bool islocal)
  1986. {
  1987. mWorkMutex.lock();
  1988. if (mState != LOAD_FROM_TEXTURE_CACHE)
  1989. {
  1990. LL_DEBUGS("TextureFetch") << "Unexpected read callback for " << mID
  1991. << " with state = " << mState << LL_ENDL;
  1992. mReadResponder = NULL;
  1993. mWorkMutex.unlock();
  1994. return;
  1995. }
  1996. if (success)
  1997. {
  1998. llassert_always(imagesize >= 0);
  1999. mFileSize = imagesize;
  2000. mFormattedImage = image;
  2001. mImageCodec = image->getCodec();
  2002. mInLocalCache = islocal;
  2003. mLoaded = true;
  2004. if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize)
  2005. {
  2006. mHaveAllData = true;
  2007. }
  2008. }
  2009. mReadResponder = NULL;
  2010. mState = CACHE_POST;
  2011. setHighPriority();
  2012. mWorkMutex.unlock();
  2013. }
  2014. // Threads: Ttc
  2015. void LLTextureFetchWorker::callbackCacheWrite(bool success)
  2016. {
  2017. mWorkMutex.lock();
  2018. if (mState != WAIT_ON_WRITE)
  2019. {
  2020. LL_DEBUGS("TextureFetch") << "Unexpected write callback for " << mID
  2021. << " with state = " << mState << LL_ENDL;
  2022. mWriteResponder = NULL;
  2023. mWorkMutex.unlock();
  2024. return;
  2025. }
  2026. mWriteResponder = NULL;
  2027. mWritten = true;
  2028. setHighPriority();
  2029. mWorkMutex.unlock();
  2030. }
  2031. // Threads: Tid
  2032. void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw,
  2033. LLImageRaw* aux)
  2034. {
  2035. mWorkMutex.lock();
  2036. if (!mDecoding)
  2037. {
  2038. LL_DEBUGS("TextureFetch") << "Aborted decode (null handle) for " << mID
  2039. << LL_ENDL;
  2040. mWorkMutex.unlock();
  2041. return; // Aborted, ignore
  2042. }
  2043. mDecoding = false;
  2044. if (mState != DECODE_IMAGE_UPDATE)
  2045. {
  2046. LL_DEBUGS("TextureFetch") << "Unexpected decode callback for " << mID
  2047. << " with state = " << mState << LL_ENDL;
  2048. mWorkMutex.unlock();
  2049. return;
  2050. }
  2051. llassert_always(mFormattedImage.notNull());
  2052. if (success)
  2053. {
  2054. llassert_always(raw);
  2055. mRawImage = raw;
  2056. mAuxImage = aux;
  2057. mDecodedDiscard = mFormattedImage->getDiscardLevel();
  2058. LL_DEBUGS("TextureFetch") << "Decode finished for " << mID
  2059. << ". Discard: " << mDecodedDiscard
  2060. << ". Raw image: "
  2061. << llformat("%dx%d", mRawImage->getWidth(),
  2062. mRawImage->getHeight())
  2063. << LL_ENDL;
  2064. }
  2065. else
  2066. {
  2067. llwarns << "Decode failed: " << mID << " Discard: "
  2068. << (S32)mFormattedImage->getDiscardLevel() << llendl;
  2069. removeFromCache();
  2070. mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
  2071. }
  2072. mDecoded = true;
  2073. setHighPriority();
  2074. mWorkMutex.unlock();
  2075. }
  2076. // Tuning/Parameterization Constants
  2077. // Maximum requests to have active in HTTP:
  2078. S32 LLTextureFetch::sMaxRequestsInQueue = 64;
  2079. // Active level at which to refill:
  2080. S32 LLTextureFetch::sMinRequestsInQueue = 32;
  2081. LLTextureFetch::LLTextureFetch()
  2082. : LLWorkerThread("Texture fetch"),
  2083. mDebugPause(false),
  2084. mApproxNumRequests(0),
  2085. mNumHTTPRequests(0),
  2086. mTextureBandwidth(0),
  2087. mHTTPTextureBits(0),
  2088. mHttpSemaphore(0),
  2089. mHttpLowWater(sMinRequestsInQueue),
  2090. mHttpHighWater(sMaxRequestsInQueue)
  2091. {
  2092. mHttpRequest = new LLCore::HttpRequest;
  2093. mHttpOptions = DEFAULT_HTTP_OPTIONS;
  2094. mHttpOptionsWithHeaders = DEFAULT_HTTP_OPTIONS;
  2095. mHttpOptionsWithHeaders->setWantHeaders(true);
  2096. mHttpHeaders = DEFAULT_HTTP_HEADERS;
  2097. mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT,
  2098. HTTP_CONTENT_IMAGE_X_J2C);
  2099. LLAppCoreHttp& app_core_http = gAppViewerp->getAppCoreHttp();
  2100. mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_TEXTURE);
  2101. }
  2102. LLTextureFetch::~LLTextureFetch()
  2103. {
  2104. clearDeleteList();
  2105. mHttpWaitResource.clear();
  2106. delete mHttpRequest;
  2107. mHttpRequest = NULL;
  2108. }
  2109. bool LLTextureFetch::createRequest(FTType f_type, const std::string& url,
  2110. const LLUUID& id, const LLHost& host,
  2111. F32 priority, S32 w, S32 h, S32 c,
  2112. S32 desired_discard, bool needs_aux,
  2113. bool can_use_http)
  2114. {
  2115. if (mDebugPause)
  2116. {
  2117. return false;
  2118. }
  2119. if (id.isNull())
  2120. {
  2121. LL_DEBUGS("TextureFetch") << "Null ID texture fetch request. Ignored."
  2122. << LL_ENDL;
  2123. return false;
  2124. }
  2125. if (f_type == FTT_SERVER_BAKE)
  2126. {
  2127. LL_DEBUGS("Avatar") << "Requesting " << id << " " << w << "x" << h
  2128. << " discard " << desired_discard << LL_ENDL;
  2129. }
  2130. LLTextureFetchWorker* worker = getWorker(id);
  2131. if (worker && worker->mHost != host)
  2132. {
  2133. llwarns << "Request creation for " << id
  2134. << " called with multiple hosts: " << host << " != "
  2135. << worker->mHost << llendl;
  2136. deleteRequest(id);
  2137. worker = NULL;
  2138. return false;
  2139. }
  2140. S32 desired_size;
  2141. std::string exten = gDirUtil.getExtension(url);
  2142. if (!url.empty() && !exten.empty() &&
  2143. LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)
  2144. {
  2145. // Only do partial requests for J2C at the moment
  2146. desired_size = MAX_IMAGE_DATA_SIZE;
  2147. desired_discard = 0;
  2148. }
  2149. else if (desired_discard == 0)
  2150. {
  2151. // If we want the entire image, and we know its size, then get it all
  2152. // (calcDataSizeJ2C() below makes assumptions about how the image was
  2153. // compressed - this code ensures that when we request the entire
  2154. // image, we really do get it).
  2155. desired_size = MAX_IMAGE_DATA_SIZE;
  2156. }
  2157. else if (w * h * c > 0)
  2158. {
  2159. // If the requester knows the dimensions of the image, this will
  2160. // calculate how much data we need without having to parse the header.
  2161. desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard);
  2162. }
  2163. else
  2164. {
  2165. // If the requester knows nothing about the file, we fetch the smallest
  2166. // amount of data at the lowest resolution (highest discard level)
  2167. // possible.
  2168. desired_size = TEXTURE_CACHE_ENTRY_SIZE;
  2169. desired_discard = MAX_DISCARD_LEVEL;
  2170. }
  2171. if (worker)
  2172. {
  2173. if (worker->wasAborted())
  2174. {
  2175. // Need to wait for previous aborted request to complete
  2176. return false;
  2177. }
  2178. worker->lockWorkMutex();
  2179. #if 0 // This causes issues with failures to retry some textures (e.g. for
  2180. // land patches). HB
  2181. if (worker->mState == LLTextureFetchWorker::DONE &&
  2182. worker->mDesiredDiscard == desired_discard &&
  2183. worker->mDesiredSize == llmax(desired_size,
  2184. TEXTURE_CACHE_ENTRY_SIZE))
  2185. {
  2186. // Similar request has failed or is in a transitional state
  2187. worker->unlockWorkMutex();
  2188. return false;
  2189. }
  2190. #endif
  2191. ++worker->mActiveCount;
  2192. worker->mNeedsAux = needs_aux;
  2193. worker->setImagePriority(priority);
  2194. worker->setDesiredDiscard(desired_discard, desired_size);
  2195. worker->setCanUseHTTP(can_use_http);
  2196. if (can_use_http && !url.empty())
  2197. {
  2198. worker->setUrl(url);
  2199. }
  2200. if (worker->haveWork())
  2201. {
  2202. worker->unlockWorkMutex();
  2203. }
  2204. else
  2205. {
  2206. worker->mState = LLTextureFetchWorker::INIT;
  2207. worker->unlockWorkMutex();
  2208. worker->addWork(0, worker->getStartingPriority());
  2209. }
  2210. }
  2211. else
  2212. {
  2213. worker = new LLTextureFetchWorker(f_type, url, id, host, priority,
  2214. desired_discard, desired_size);
  2215. mQueueMutex.lock();
  2216. mRequestMap[id] = worker;
  2217. mApproxNumRequests = (U32)mRequestMap.size();
  2218. mQueueMutex.unlock();
  2219. worker->lockWorkMutex();
  2220. ++worker->mActiveCount;
  2221. worker->mNeedsAux = needs_aux;
  2222. worker->setCanUseHTTP(can_use_http);
  2223. worker->unlockWorkMutex();
  2224. }
  2225. LL_DEBUGS("TextureFetch") << "Requested: " << id << ". f_type: "
  2226. << fttype_to_string(f_type) << ". Discard: "
  2227. << desired_discard << ". Size: " << desired_size
  2228. << LL_ENDL;
  2229. return true;
  2230. }
  2231. void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
  2232. {
  2233. mQueueMutex.lock();
  2234. bool in_request_map = mRequestMap.count(worker->mID) != 0;
  2235. mQueueMutex.unlock();
  2236. mNetworkQueueMutex.lock();
  2237. if (in_request_map)
  2238. {
  2239. // Only add to the queue if in the request map, i.e. a delete has not
  2240. // been requested.
  2241. mNetworkQueue.emplace(worker->mID);
  2242. }
  2243. for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(),
  2244. end = mCancelQueue.end();
  2245. iter1 != end; ++iter1)
  2246. {
  2247. iter1->second.erase(worker->mID);
  2248. }
  2249. mNetworkQueueMutex.unlock();
  2250. }
  2251. void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker,
  2252. bool cancel)
  2253. {
  2254. mNetworkQueueMutex.lock();
  2255. size_t erased = mNetworkQueue.erase(worker->mID);
  2256. if (cancel && erased > 0)
  2257. {
  2258. mCancelQueue[worker->mHost].emplace(worker->mID);
  2259. }
  2260. mNetworkQueueMutex.unlock();
  2261. }
  2262. // Threads: T*
  2263. //
  2264. // protected
  2265. void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
  2266. {
  2267. mNetworkQueueMutex.lock();
  2268. mHTTPTextureQueue.emplace(id); // May be insert (if not already there)
  2269. mNumHTTPRequests = mHTTPTextureQueue.size();
  2270. mNetworkQueueMutex.unlock();
  2271. }
  2272. // Threads: T*
  2273. void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
  2274. {
  2275. mNetworkQueueMutex.lock();
  2276. mHTTPTextureQueue.erase(id); // May be remove (if actually there)
  2277. mNumHTTPRequests = mHTTPTextureQueue.size();
  2278. // Approximate - does not include header bits:
  2279. mHTTPTextureBits += received_size * 8;
  2280. mNetworkQueueMutex.unlock();
  2281. }
  2282. bool LLTextureFetch::deleteRequest(const LLUUID& id, bool force)
  2283. {
  2284. mQueueMutex.lock();
  2285. LLTextureFetchWorker* worker = getWorkerAfterLock(id);
  2286. if (worker && (force || worker->deleteOK()))
  2287. {
  2288. mRequestMap.erase(worker->mID);
  2289. mApproxNumRequests = (U32)mRequestMap.size();
  2290. mQueueMutex.unlock();
  2291. removeFromNetworkQueue(worker, true);
  2292. llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)));
  2293. worker->scheduleDelete();
  2294. return true;
  2295. }
  2296. mQueueMutex.unlock();
  2297. return false;
  2298. }
  2299. uuid_list_t LLTextureFetch::deleteAllRequests()
  2300. {
  2301. llinfos << "Deleting all requests..." << llendl;
  2302. // Pause the fetcher to avoid race conditions between locking and unlocking
  2303. // of the queue.
  2304. mDebugPause = true;
  2305. // First create a vector of all texture UUIDs associated with a worker
  2306. uuid_vec_t fetching_ids;
  2307. fetching_ids.resize(mRequestMap.size());
  2308. mQueueMutex.lock();
  2309. for (map_t::const_iterator it = mRequestMap.begin(),
  2310. end = mRequestMap.end();
  2311. it != end; ++it)
  2312. {
  2313. LLTextureFetchWorker* worker = it->second;
  2314. if (worker) // Paranoia
  2315. {
  2316. fetching_ids.emplace_back(it->first);
  2317. }
  2318. }
  2319. mQueueMutex.unlock();
  2320. uuid_list_t deleted_ids;
  2321. fetching_ids.resize(fetching_ids.size());
  2322. // Then, delete all workers that are still around and are in a state
  2323. // where they can actually be deleted...
  2324. for (U32 i = 0, count = fetching_ids.size(); i < count; ++i)
  2325. {
  2326. const LLUUID& tex_id = fetching_ids[i];
  2327. LLViewerFetchedTexture* texp = gTextureList.findImage(tex_id);
  2328. if (texp &&
  2329. (texp->getDontDiscard() ||
  2330. texp->getBoostLevel() >= LLGLTexture::BOOST_SUPER_HIGH))
  2331. {
  2332. // Do not interrupt the fetching of important images ! HB
  2333. continue;
  2334. }
  2335. mQueueMutex.lock();
  2336. map_t::iterator iter = mRequestMap.find(tex_id);
  2337. bool can_delete = iter != mRequestMap.end();
  2338. mQueueMutex.unlock();
  2339. if (!can_delete)
  2340. {
  2341. // Request worker is already gone
  2342. continue;
  2343. }
  2344. if (deleteRequest(tex_id, false)) // false = do not force
  2345. {
  2346. LL_DEBUGS("TextureFetch") << "Deleted the request for texture: "
  2347. << tex_id << LL_ENDL;
  2348. deleted_ids.emplace(tex_id);
  2349. }
  2350. else
  2351. {
  2352. LL_DEBUGS("TextureFetch") << "Request for texture " << tex_id
  2353. << " cannot be deleted now." << LL_ENDL;
  2354. }
  2355. }
  2356. mDebugPause = false; // Un-pause
  2357. llinfos << "All requests deleted." << llendl;
  2358. return deleted_ids;
  2359. }
  2360. U32 LLTextureFetch::getNumRequests()
  2361. {
  2362. mQueueMutex.lock();
  2363. U32 size = (U32)mRequestMap.size();
  2364. mQueueMutex.unlock();
  2365. return size;
  2366. }
  2367. // Call mQueueMutex.lock() first !
  2368. // Threads: T*
  2369. // Locks: Mfq
  2370. LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id)
  2371. {
  2372. map_t::iterator iter = mRequestMap.find(id);
  2373. return iter == mRequestMap.end() ? NULL : iter->second;
  2374. }
  2375. // Threads: T*
  2376. LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
  2377. {
  2378. mQueueMutex.lock();
  2379. LLTextureFetchWorker* worker = getWorkerAfterLock(id);
  2380. mQueueMutex.unlock();
  2381. return worker;
  2382. }
  2383. bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
  2384. LLPointer<LLImageRaw>& raw,
  2385. LLPointer<LLImageRaw>& aux,
  2386. LLCore::HttpStatus& last_http_get_status)
  2387. {
  2388. LLTextureFetchWorker* worker = getWorker(id);
  2389. if (!worker || worker->wasAborted())
  2390. {
  2391. return true;
  2392. }
  2393. if (!worker->haveWork())
  2394. {
  2395. // Should only happen if we set mDebugPause...
  2396. if (!mDebugPause)
  2397. {
  2398. LL_DEBUGS("TextureFetch") << "Adding work for inactive worker: "
  2399. << id << LL_ENDL;
  2400. worker->addWork(0, worker->getStartingPriority());
  2401. }
  2402. return false;
  2403. }
  2404. if (worker->checkWork())
  2405. {
  2406. worker->lockWorkMutex();
  2407. last_http_get_status = worker->mGetStatus;
  2408. discard_level = worker->mDecodedDiscard;
  2409. raw = worker->mRawImage;
  2410. aux = worker->mAuxImage;
  2411. LL_DEBUGS("TextureFetch") << id << ": request finished. State: "
  2412. << worker->mState << ". Discard: "
  2413. << discard_level << LL_ENDL;
  2414. worker->unlockWorkMutex();
  2415. return true;
  2416. }
  2417. worker->lockWorkMutex();
  2418. if (worker->mDecodedDiscard >= 0 &&
  2419. (worker->mDecodedDiscard < discard_level || discard_level < 0) &&
  2420. worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE)
  2421. {
  2422. // Not finished, but data is ready
  2423. discard_level = worker->mDecodedDiscard;
  2424. raw = worker->mRawImage;
  2425. aux = worker->mAuxImage;
  2426. }
  2427. worker->unlockWorkMutex();
  2428. return false;
  2429. }
  2430. bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
  2431. {
  2432. LLTextureFetchWorker* worker = getWorker(id);
  2433. if (worker)
  2434. {
  2435. worker->lockWorkMutex();
  2436. worker->setImagePriority(priority);
  2437. worker->unlockWorkMutex();
  2438. return true;
  2439. }
  2440. return false;
  2441. }
  2442. // Overridden since we also need to lock mQueueMutex for this operation.
  2443. // Threads: T*
  2444. //virtual
  2445. size_t LLTextureFetch::getPending()
  2446. {
  2447. mQueueMutex.lock();
  2448. size_t res = LLQueuedThread::getPending();
  2449. mQueueMutex.unlock();
  2450. return res;
  2451. }
  2452. // WORKER THREAD
  2453. //virtual
  2454. void LLTextureFetch::threadedUpdate()
  2455. {
  2456. llassert_always(mHttpRequest);
  2457. LLAppCoreHttp& app_core_http = gAppViewerp->getAppCoreHttp();
  2458. if (app_core_http.isPipelined(LLAppCoreHttp::AP_TEXTURE))
  2459. {
  2460. mHttpHighWater = 4 * sMaxRequestsInQueue;
  2461. mHttpLowWater = 4 * sMinRequestsInQueue;
  2462. }
  2463. else
  2464. {
  2465. mHttpHighWater = sMaxRequestsInQueue;
  2466. mHttpLowWater = sMinRequestsInQueue;
  2467. }
  2468. // Release waiters
  2469. releaseHttpWaiters();
  2470. // Deliver all completion notifications
  2471. LLCore::HttpStatus status = mHttpRequest->update(0);
  2472. if (!status)
  2473. {
  2474. llinfos_once << "Problem during HTTP servicing. Reason: "
  2475. << status.toString() << llendl;
  2476. }
  2477. }
  2478. // MAIN THREAD
  2479. //virtual
  2480. size_t LLTextureFetch::update()
  2481. {
  2482. mNetworkQueueMutex.lock();
  2483. gTextureList.sTextureBits += mHTTPTextureBits;
  2484. mHTTPTextureBits = 0;
  2485. mNetworkQueueMutex.unlock();
  2486. size_t res = LLWorkerThread::update();
  2487. if (!mDebugPause && LLStartUp::getStartupState() > STATE_AGENT_SEND)
  2488. {
  2489. // STATE_AGENT_SEND is the startup state when
  2490. // send_complete_agent_movement() message is sent. Before this, the
  2491. // RequestImages message sent by sendRequestListToSimulators would not
  2492. // work, so do not bother trying.
  2493. sendRequestListToSimulators();
  2494. }
  2495. return res;
  2496. }
  2497. // Threads: Tmain
  2498. void LLTextureFetch::sendRequestListToSimulators()
  2499. {
  2500. // All requests
  2501. constexpr F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps
  2502. // Sim requests
  2503. constexpr S32 IMAGES_PER_REQUEST = 50;
  2504. constexpr F32 SIM_LAZY_FLUSH_TIMEOUT = 10.f; // temp
  2505. constexpr F32 MIN_REQUEST_TIME = 1.f;
  2506. constexpr F32 MIN_DELTA_PRIORITY = 1000.f;
  2507. // Periodically, gather the list of textures that need data from the network
  2508. // And send the requests out to the simulators
  2509. static LLFrameTimer timer;
  2510. if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME)
  2511. {
  2512. return;
  2513. }
  2514. timer.reset();
  2515. // Send requests
  2516. typedef std::set<LLTextureFetchWorker*,
  2517. LLTextureFetchWorker::Compare> request_list_t;
  2518. typedef std::map<LLHost, request_list_t> work_request_map_t;
  2519. work_request_map_t requests;
  2520. mNetworkQueueMutex.lock();
  2521. for (uuid_list_t::iterator iter = mNetworkQueue.begin();
  2522. iter != mNetworkQueue.end(); )
  2523. {
  2524. uuid_list_t::iterator curiter = iter++;
  2525. LLTextureFetchWorker* req = getWorker(*curiter);
  2526. if (!req)
  2527. {
  2528. mNetworkQueue.erase(curiter);
  2529. continue; // paranoia
  2530. }
  2531. if (req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK &&
  2532. req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
  2533. {
  2534. // We already received our URL, remove from the queue
  2535. llwarns << "Worker: " << req->mID
  2536. << " in mNetworkQueue but in wrong state: " << req->mState
  2537. << llendl;
  2538. mNetworkQueue.erase(curiter);
  2539. continue;
  2540. }
  2541. if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM &&
  2542. req->mTotalPackets > 0 &&
  2543. req->mLastPacket >= req->mTotalPackets - 1)
  2544. {
  2545. // We have all the packets.
  2546. continue;
  2547. }
  2548. F32 elapsed = req->mRequestedTimer.getElapsedTimeF32();
  2549. F32 delta_priority = fabsf(req->mRequestedPriority -
  2550. req->mImagePriority);
  2551. if (req->mSimRequestedDiscard != req->mDesiredDiscard ||
  2552. elapsed >= SIM_LAZY_FLUSH_TIMEOUT ||
  2553. (elapsed >= MIN_REQUEST_TIME &&
  2554. delta_priority > MIN_DELTA_PRIORITY))
  2555. {
  2556. requests[req->mHost].insert(req);
  2557. }
  2558. }
  2559. mNetworkQueueMutex.unlock();
  2560. LLMessageSystem* msg = gMessageSystemp;
  2561. for (work_request_map_t::iterator iter1 = requests.begin(),
  2562. end1 = requests.end();
  2563. iter1 != end1; ++iter1)
  2564. {
  2565. LLHost host = iter1->first;
  2566. // Invalid host = use agent host
  2567. if (host.isInvalid())
  2568. {
  2569. host = gAgent.getRegionHost();
  2570. }
  2571. S32 sim_request_count = 0;
  2572. for (request_list_t::iterator iter2 = iter1->second.begin(),
  2573. end2 = iter1->second.end();
  2574. iter2 != end2; ++iter2)
  2575. {
  2576. LLTextureFetchWorker* req = *iter2;
  2577. if (msg)
  2578. {
  2579. if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM)
  2580. {
  2581. // Initialize packet data based on data read from cache
  2582. req->lockWorkMutex();
  2583. req->setupPacketData();
  2584. req->unlockWorkMutex();
  2585. }
  2586. if (0 == sim_request_count)
  2587. {
  2588. msg->newMessageFast(_PREHASH_RequestImage);
  2589. msg->nextBlockFast(_PREHASH_AgentData);
  2590. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  2591. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  2592. }
  2593. S32 packet = req->mLastPacket + 1;
  2594. msg->nextBlockFast(_PREHASH_RequestImage);
  2595. msg->addUUIDFast(_PREHASH_Image, req->mID);
  2596. msg->addS8Fast(_PREHASH_DiscardLevel,
  2597. (S8)req->mDesiredDiscard);
  2598. msg->addF32Fast(_PREHASH_DownloadPriority,
  2599. req->mImagePriority);
  2600. msg->addU32Fast(_PREHASH_Packet, packet);
  2601. msg->addU8Fast(_PREHASH_Type, req->mType);
  2602. req->lockWorkMutex();
  2603. req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
  2604. req->mSimRequestedDiscard = req->mDesiredDiscard;
  2605. req->mRequestedPriority = req->mImagePriority;
  2606. req->mRequestedTimer.reset();
  2607. req->unlockWorkMutex();
  2608. if (++sim_request_count >= IMAGES_PER_REQUEST)
  2609. {
  2610. msg->sendSemiReliable(host, NULL, NULL);
  2611. sim_request_count = 0;
  2612. }
  2613. }
  2614. }
  2615. if (msg && sim_request_count > 0 &&
  2616. sim_request_count < IMAGES_PER_REQUEST)
  2617. {
  2618. msg->sendSemiReliable(host, NULL, NULL);
  2619. sim_request_count = 0;
  2620. }
  2621. }
  2622. // Send cancelations
  2623. mNetworkQueueMutex.lock();
  2624. if (msg && !mCancelQueue.empty())
  2625. {
  2626. for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(),
  2627. end1 = mCancelQueue.end();
  2628. iter1 != end1; ++iter1)
  2629. {
  2630. LLHost host = iter1->first;
  2631. if (host.isInvalid())
  2632. {
  2633. host = gAgent.getRegionHost();
  2634. }
  2635. S32 request_count = 0;
  2636. for (uuid_list_t::iterator iter2 = iter1->second.begin(),
  2637. end2 = iter1->second.end();
  2638. iter2 != end2; ++iter2)
  2639. {
  2640. if (request_count == 0)
  2641. {
  2642. msg->newMessageFast(_PREHASH_RequestImage);
  2643. msg->nextBlockFast(_PREHASH_AgentData);
  2644. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  2645. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  2646. }
  2647. msg->nextBlockFast(_PREHASH_RequestImage);
  2648. msg->addUUIDFast(_PREHASH_Image, *iter2);
  2649. msg->addS8Fast(_PREHASH_DiscardLevel, -1);
  2650. msg->addF32Fast(_PREHASH_DownloadPriority, 0);
  2651. msg->addU32Fast(_PREHASH_Packet, 0);
  2652. msg->addU8Fast(_PREHASH_Type, 0);
  2653. if (++request_count >= IMAGES_PER_REQUEST)
  2654. {
  2655. msg->sendSemiReliable(host, NULL, NULL);
  2656. request_count = 0;
  2657. }
  2658. }
  2659. if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
  2660. {
  2661. msg->sendSemiReliable(host, NULL, NULL);
  2662. }
  2663. }
  2664. mCancelQueue.clear();
  2665. }
  2666. mNetworkQueueMutex.unlock();
  2667. }
  2668. bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id,
  2669. U8 codec, U16 packets, U32 totalbytes,
  2670. U16 data_size, U8* data)
  2671. {
  2672. bool res = true;
  2673. LLTextureFetchWorker* worker = getWorker(id);
  2674. if (!worker)
  2675. {
  2676. LL_DEBUGS("TextureFetch") << "Received header for non active worker: "
  2677. << id << LL_ENDL;
  2678. res = false;
  2679. }
  2680. else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
  2681. worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
  2682. {
  2683. LL_DEBUGS("TextureFetch") << "Worker: " << id << ". State: "
  2684. << e_state_name[worker->mState]
  2685. << ". Sent: " << worker->mSentRequest
  2686. << LL_ENDL;
  2687. res = false;
  2688. }
  2689. else if (worker->mLastPacket != -1)
  2690. {
  2691. // check to see if we have gotten this packet before
  2692. LL_DEBUGS("TextureFetch") << "Received duplicate header for: " << id
  2693. << LL_ENDL;
  2694. res = false;
  2695. }
  2696. else if (!data_size)
  2697. {
  2698. LL_DEBUGS("TextureFetch") << "Empty image header for " << id
  2699. << LL_ENDL;
  2700. res = false;
  2701. }
  2702. if (!res)
  2703. {
  2704. mNetworkQueueMutex.lock();
  2705. mCancelQueue[host].emplace(id);
  2706. mNetworkQueueMutex.unlock();
  2707. return false;
  2708. }
  2709. worker->lockWorkMutex();
  2710. // Copy header data into image object
  2711. worker->mImageCodec = codec;
  2712. worker->mTotalPackets = packets;
  2713. worker->mFileSize = (S32)totalbytes;
  2714. llassert_always(totalbytes > 0);
  2715. llassert_always(data_size == FIRST_PACKET_SIZE ||
  2716. data_size == worker->mFileSize);
  2717. res = worker->insertPacket(0, data, data_size);
  2718. worker->setHighPriority();
  2719. worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
  2720. worker->unlockWorkMutex();
  2721. return res;
  2722. }
  2723. bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id,
  2724. U16 packet_num, U16 data_size,
  2725. U8* data)
  2726. {
  2727. bool res = true;
  2728. LLTextureFetchWorker* worker = getWorker(id);
  2729. if (!worker)
  2730. {
  2731. LL_DEBUGS("TextureFetch") << "Received packet " << packet_num
  2732. << " for non active worker: " << id
  2733. << LL_ENDL;
  2734. res = false;
  2735. }
  2736. else if (worker->mLastPacket == -1)
  2737. {
  2738. LL_DEBUGS("TextureFetch") << "Received packet " << packet_num
  2739. << " before header for: " << id << LL_ENDL;
  2740. res = false;
  2741. }
  2742. else if (!data_size)
  2743. {
  2744. LL_DEBUGS("TextureFetch") << "Empty image header for " << id
  2745. << LL_ENDL;
  2746. res = false;
  2747. }
  2748. if (!res)
  2749. {
  2750. mNetworkQueueMutex.lock();
  2751. mCancelQueue[host].emplace(id);
  2752. mNetworkQueueMutex.unlock();
  2753. return false;
  2754. }
  2755. worker->lockWorkMutex();
  2756. res = worker->insertPacket(packet_num, data, data_size);
  2757. if (worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR ||
  2758. worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK)
  2759. {
  2760. worker->setHighPriority();
  2761. worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
  2762. }
  2763. else
  2764. {
  2765. LL_DEBUGS("TextureFetch") << "Packet " << packet_num << "/"
  2766. << worker->mLastPacket << " for worker "
  2767. << id << " in state "
  2768. << e_state_name[worker->mState] << LL_ENDL;
  2769. removeFromNetworkQueue(worker, true); // failsafe
  2770. }
  2771. worker->unlockWorkMutex();
  2772. return res;
  2773. }
  2774. bool LLTextureFetch::isFromLocalCache(const LLUUID& id)
  2775. {
  2776. bool from_cache = false;
  2777. LLTextureFetchWorker* worker = getWorker(id);
  2778. if (worker)
  2779. {
  2780. worker->lockWorkMutex();
  2781. from_cache = worker->mInLocalCache;
  2782. worker->unlockWorkMutex();
  2783. }
  2784. return from_cache;
  2785. }
  2786. S32 LLTextureFetch::getFetchState(const LLUUID& id,
  2787. F32& data_progress_p,
  2788. F32& requested_priority_p,
  2789. U32& fetch_priority_p,
  2790. F32& fetch_dtime_p,
  2791. F32& request_dtime_p,
  2792. bool& can_use_http)
  2793. {
  2794. S32 state = LLTextureFetchWorker::INVALID;
  2795. F32 data_progress = 0.0f;
  2796. F32 requested_priority = 0.0f;
  2797. F32 fetch_dtime = 999999.f;
  2798. F32 request_dtime = 999999.f;
  2799. U32 fetch_priority = 0;
  2800. LLTextureFetchWorker* worker = getWorker(id);
  2801. if (worker && worker->haveWork())
  2802. {
  2803. worker->lockWorkMutex();
  2804. state = worker->mState;
  2805. fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
  2806. request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
  2807. if (worker->mFileSize > 0)
  2808. {
  2809. if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
  2810. {
  2811. S32 data_size = FIRST_PACKET_SIZE +
  2812. (worker->mLastPacket - 1) *
  2813. MAX_IMG_PACKET_SIZE;
  2814. data_size = llmax(data_size, 0);
  2815. data_progress = (F32)data_size / (F32)worker->mFileSize;
  2816. }
  2817. else if (worker->mFormattedImage.notNull())
  2818. {
  2819. data_progress = (F32)worker->mFormattedImage->getDataSize() /
  2820. (F32)worker->mFileSize;
  2821. }
  2822. }
  2823. if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK &&
  2824. state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
  2825. {
  2826. requested_priority = worker->mRequestedPriority;
  2827. }
  2828. else
  2829. {
  2830. requested_priority = worker->mImagePriority;
  2831. }
  2832. fetch_priority = worker->getPriority();
  2833. can_use_http = worker->getCanUseHTTP();
  2834. worker->unlockWorkMutex();
  2835. }
  2836. data_progress_p = data_progress;
  2837. requested_priority_p = requested_priority;
  2838. fetch_priority_p = fetch_priority;
  2839. fetch_dtime_p = fetch_dtime;
  2840. request_dtime_p = request_dtime;
  2841. return state;
  2842. }
  2843. // Threads: Ttf
  2844. void LLTextureFetch::addHttpWaiter(const LLUUID& tid)
  2845. {
  2846. mNetworkQueueMutex.lock();
  2847. mHttpWaitResource.emplace(tid);
  2848. mNetworkQueueMutex.unlock();
  2849. }
  2850. // Threads: Ttf
  2851. void LLTextureFetch::removeHttpWaiter(const LLUUID& tid)
  2852. {
  2853. mNetworkQueueMutex.lock();
  2854. uuid_list_t::iterator iter = mHttpWaitResource.find(tid);
  2855. if (iter != mHttpWaitResource.end())
  2856. {
  2857. mHttpWaitResource.erase(iter);
  2858. }
  2859. mNetworkQueueMutex.unlock();
  2860. }
  2861. bool LLTextureFetch::isHttpWaiter(const LLUUID& tid)
  2862. {
  2863. mNetworkQueueMutex.lock();
  2864. uuid_list_t::iterator iter = mHttpWaitResource.find(tid);
  2865. bool ret = mHttpWaitResource.end() != iter;
  2866. mNetworkQueueMutex.unlock();
  2867. return ret;
  2868. }
  2869. // Release as many requests as permitted from the WAIT_HTTP_RESOURCE2 state to
  2870. // the SEND_HTTP_REQ state based on their current priority.
  2871. //
  2872. // This data structures and code associated with this looks a bit indirect and
  2873. // naive but it is done in the name of safety. An ordered container may become
  2874. // invalid from time to time due to priority changes caused by actions in other
  2875. // threads. State itself could also suffer the same fate with cancelled
  2876. // operations. Even done this way, I am not fully trusting we are truly safe.
  2877. // This module is due for a major refactoring and we will deal with it then.
  2878. //
  2879. // Threads: Ttf
  2880. // Locks: -Mw (must not hold any worker when called)
  2881. void LLTextureFetch::releaseHttpWaiters()
  2882. {
  2883. if (mHttpSemaphore >= mHttpHighWater)
  2884. {
  2885. return;
  2886. }
  2887. mNetworkQueueMutex.lock();
  2888. uuid_list_t::iterator iter;
  2889. uuid_list_t::iterator end = mHttpWaitResource.end();
  2890. for (iter = mHttpWaitResource.begin(); iter != end; ++iter)
  2891. {
  2892. LLTextureFetchWorker* worker(getWorker(*iter));
  2893. if (worker)
  2894. {
  2895. if (!worker->acquireHttpSemaphore())
  2896. {
  2897. break;
  2898. }
  2899. worker->lockWorkMutex();
  2900. worker->mState = LLTextureFetchWorker::SEND_HTTP_REQ;
  2901. worker->setHighPriority();
  2902. worker->unlockWorkMutex();
  2903. }
  2904. }
  2905. mHttpWaitResource.erase(mHttpWaitResource.begin(), iter);
  2906. mNetworkQueueMutex.unlock();
  2907. }