PageRenderTime 54ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/lltexturefetch.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2341 lines | 1767 code | 213 blank | 361 comment | 299 complexity | 36b1c05cd48903ad9e843aad5149a48e MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lltexturefetch.cpp
  3. * @brief Object which fetches textures from the cache and/or network
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include <iostream>
  28. #include <map>
  29. #include "llstl.h"
  30. #include "lltexturefetch.h"
  31. #include "llcurl.h"
  32. #include "lldir.h"
  33. #include "llhttpclient.h"
  34. #include "llhttpstatuscodes.h"
  35. #include "llimage.h"
  36. #include "llimagej2c.h"
  37. #include "llimageworker.h"
  38. #include "llworkerthread.h"
  39. #include "message.h"
  40. #include "llagent.h"
  41. #include "lltexturecache.h"
  42. #include "llviewercontrol.h"
  43. #include "llviewertexturelist.h"
  44. #include "llviewertexture.h"
  45. #include "llviewerregion.h"
  46. #include "llviewerstats.h"
  47. #include "llviewerassetstats.h"
  48. #include "llworld.h"
  49. //////////////////////////////////////////////////////////////////////////////
  50. class LLTextureFetchWorker : public LLWorkerClass
  51. {
  52. friend class LLTextureFetch;
  53. friend class HTTPGetResponder;
  54. private:
  55. class CacheReadResponder : public LLTextureCache::ReadResponder
  56. {
  57. public:
  58. CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image)
  59. : mFetcher(fetcher), mID(id)
  60. {
  61. setImage(image);
  62. }
  63. virtual void completed(bool success)
  64. {
  65. LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
  66. if (worker)
  67. {
  68. worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal);
  69. }
  70. }
  71. private:
  72. LLTextureFetch* mFetcher;
  73. LLUUID mID;
  74. };
  75. class CacheWriteResponder : public LLTextureCache::WriteResponder
  76. {
  77. public:
  78. CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id)
  79. : mFetcher(fetcher), mID(id)
  80. {
  81. }
  82. virtual void completed(bool success)
  83. {
  84. LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
  85. if (worker)
  86. {
  87. worker->callbackCacheWrite(success);
  88. }
  89. }
  90. private:
  91. LLTextureFetch* mFetcher;
  92. LLUUID mID;
  93. };
  94. class DecodeResponder : public LLImageDecodeThread::Responder
  95. {
  96. public:
  97. DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker)
  98. : mFetcher(fetcher), mID(id), mWorker(worker)
  99. {
  100. }
  101. virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
  102. {
  103. LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
  104. if (worker)
  105. {
  106. worker->callbackDecoded(success, raw, aux);
  107. }
  108. }
  109. private:
  110. LLTextureFetch* mFetcher;
  111. LLUUID mID;
  112. LLTextureFetchWorker* mWorker; // debug only (may get deleted from under us, use mFetcher/mID)
  113. };
  114. struct Compare
  115. {
  116. // lhs < rhs
  117. bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const
  118. {
  119. // greater priority is "less"
  120. const F32 lpriority = lhs->mImagePriority;
  121. const F32 rpriority = rhs->mImagePriority;
  122. if (lpriority > rpriority) // higher priority
  123. return true;
  124. else if (lpriority < rpriority)
  125. return false;
  126. else
  127. return lhs < rhs;
  128. }
  129. };
  130. public:
  131. /*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
  132. /*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
  133. /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
  134. ~LLTextureFetchWorker();
  135. // void relese() { --mActiveCount; }
  136. S32 callbackHttpGet(const LLChannelDescriptors& channels,
  137. const LLIOPipe::buffer_ptr_t& buffer,
  138. bool partial, bool success);
  139. void callbackCacheRead(bool success, LLImageFormatted* image,
  140. S32 imagesize, BOOL islocal);
  141. void callbackCacheWrite(bool success);
  142. void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
  143. void setGetStatus(U32 status, const std::string& reason)
  144. {
  145. LLMutexLock lock(&mWorkMutex);
  146. mGetStatus = status;
  147. mGetReason = reason;
  148. }
  149. void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
  150. bool getCanUseHTTP() const { return mCanUseHTTP; }
  151. LLTextureFetch & getFetcher() { return *mFetcher; }
  152. protected:
  153. LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
  154. F32 priority, S32 discard, S32 size);
  155. private:
  156. /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
  157. /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
  158. void resetFormattedData();
  159. void setImagePriority(F32 priority);
  160. void setDesiredDiscard(S32 discard, S32 size);
  161. bool insertPacket(S32 index, U8* data, S32 size);
  162. void clearPackets();
  163. void setupPacketData();
  164. U32 calcWorkPriority();
  165. void removeFromCache();
  166. bool processSimulatorPackets();
  167. bool writeToCacheComplete();
  168. void lockWorkMutex() { mWorkMutex.lock(); }
  169. void unlockWorkMutex() { mWorkMutex.unlock(); }
  170. private:
  171. enum e_state // mState
  172. {
  173. // NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
  174. INVALID = 0,
  175. INIT,
  176. LOAD_FROM_TEXTURE_CACHE,
  177. CACHE_POST,
  178. LOAD_FROM_NETWORK,
  179. LOAD_FROM_SIMULATOR,
  180. SEND_HTTP_REQ,
  181. WAIT_HTTP_REQ,
  182. DECODE_IMAGE,
  183. DECODE_IMAGE_UPDATE,
  184. WRITE_TO_CACHE,
  185. WAIT_ON_WRITE,
  186. DONE
  187. };
  188. enum e_request_state // mSentRequest
  189. {
  190. UNSENT = 0,
  191. QUEUED = 1,
  192. SENT_SIM = 2
  193. };
  194. enum e_write_to_cache_state //mWriteToCacheState
  195. {
  196. NOT_WRITE = 0,
  197. CAN_WRITE = 1,
  198. SHOULD_WRITE = 2
  199. };
  200. static const char* sStateDescs[];
  201. e_state mState;
  202. e_write_to_cache_state mWriteToCacheState;
  203. LLTextureFetch* mFetcher;
  204. LLPointer<LLImageFormatted> mFormattedImage;
  205. LLPointer<LLImageRaw> mRawImage;
  206. LLPointer<LLImageRaw> mAuxImage;
  207. LLUUID mID;
  208. LLHost mHost;
  209. std::string mUrl;
  210. U8 mType;
  211. F32 mImagePriority;
  212. U32 mWorkPriority;
  213. F32 mRequestedPriority;
  214. S32 mDesiredDiscard;
  215. S32 mSimRequestedDiscard;
  216. S32 mRequestedDiscard;
  217. S32 mLoadedDiscard;
  218. S32 mDecodedDiscard;
  219. LLFrameTimer mRequestedTimer;
  220. LLFrameTimer mFetchTimer;
  221. LLTextureCache::handle_t mCacheReadHandle;
  222. LLTextureCache::handle_t mCacheWriteHandle;
  223. U8* mBuffer;
  224. S32 mBufferSize;
  225. S32 mRequestedSize;
  226. S32 mDesiredSize;
  227. S32 mFileSize;
  228. S32 mCachedSize;
  229. e_request_state mSentRequest;
  230. handle_t mDecodeHandle;
  231. BOOL mLoaded;
  232. BOOL mDecoded;
  233. BOOL mWritten;
  234. BOOL mNeedsAux;
  235. BOOL mHaveAllData;
  236. BOOL mInLocalCache;
  237. bool mCanUseHTTP ;
  238. bool mCanUseNET ; //can get from asset server.
  239. S32 mHTTPFailCount;
  240. S32 mRetryAttempt;
  241. S32 mActiveCount;
  242. U32 mGetStatus;
  243. std::string mGetReason;
  244. // Work Data
  245. LLMutex mWorkMutex;
  246. struct PacketData
  247. {
  248. PacketData(U8* data, S32 size) { mData = data; mSize = size; }
  249. ~PacketData() { clearData(); }
  250. void clearData() { delete[] mData; mData = NULL; }
  251. U8* mData;
  252. U32 mSize;
  253. };
  254. std::vector<PacketData*> mPackets;
  255. S32 mFirstPacket;
  256. S32 mLastPacket;
  257. U16 mTotalPackets;
  258. U8 mImageCodec;
  259. LLViewerAssetStats::duration_t mMetricsStartTime;
  260. };
  261. //////////////////////////////////////////////////////////////////////////////
  262. class HTTPGetResponder : public LLCurl::Responder
  263. {
  264. LOG_CLASS(HTTPGetResponder);
  265. public:
  266. HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir)
  267. : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir)
  268. {
  269. }
  270. ~HTTPGetResponder()
  271. {
  272. }
  273. virtual void completedRaw(U32 status, const std::string& reason,
  274. const LLChannelDescriptors& channels,
  275. const LLIOPipe::buffer_ptr_t& buffer)
  276. {
  277. static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
  278. static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
  279. static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
  280. if (log_to_viewer_log || log_to_sim)
  281. {
  282. mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime);
  283. U64 timeNow = LLTimer::getTotalTime();
  284. mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
  285. mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
  286. mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
  287. mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
  288. }
  289. lldebugs << "HTTP COMPLETE: " << mID << llendl;
  290. LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
  291. if (worker)
  292. {
  293. bool success = false;
  294. bool partial = false;
  295. if (HTTP_OK <= status && status < HTTP_MULTIPLE_CHOICES)
  296. {
  297. success = true;
  298. if (HTTP_PARTIAL_CONTENT == status) // partial information
  299. {
  300. partial = true;
  301. }
  302. }
  303. if (!success)
  304. {
  305. worker->setGetStatus(status, reason);
  306. // llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
  307. }
  308. S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
  309. if(log_texture_traffic && data_size > 0)
  310. {
  311. LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ;
  312. if(tex)
  313. {
  314. gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ;
  315. }
  316. }
  317. mFetcher->removeFromHTTPQueue(mID, data_size);
  318. if (worker->mMetricsStartTime)
  319. {
  320. LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
  321. true,
  322. LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
  323. LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
  324. worker->mMetricsStartTime = 0;
  325. }
  326. LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
  327. true,
  328. LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
  329. }
  330. else
  331. {
  332. mFetcher->removeFromHTTPQueue(mID);
  333. llwarns << "Worker not found: " << mID << llendl;
  334. }
  335. }
  336. virtual bool followRedir()
  337. {
  338. return mFollowRedir;
  339. }
  340. private:
  341. LLTextureFetch* mFetcher;
  342. LLUUID mID;
  343. U64 mStartTime;
  344. S32 mRequestedSize;
  345. U32 mOffset;
  346. bool mFollowRedir;
  347. };
  348. //////////////////////////////////////////////////////////////////////////////
  349. // Cross-thread messaging for asset metrics.
  350. /**
  351. * @brief Base class for cross-thread requests made of the fetcher
  352. *
  353. * I believe the intent of the LLQueuedThread class was to
  354. * have these operations derived from LLQueuedThread::QueuedRequest
  355. * but the texture fetcher has elected to manage the queue
  356. * in its own manner. So these are free-standing objects which are
  357. * managed in simple FIFO order on the mCommands queue of the
  358. * LLTextureFetch object.
  359. *
  360. * What each represents is a simple command sent from an
  361. * outside thread into the TextureFetch thread to be processed
  362. * in order and in a timely fashion (though not an absolute
  363. * higher priority than other operations of the thread).
  364. * Each operation derives a new class from the base customizing
  365. * members, constructors and the doWork() method to effect
  366. * the command.
  367. *
  368. * The flow is one-directional. There are two global instances
  369. * of the LLViewerAssetStats collector, one for the main program's
  370. * thread pointed to by gViewerAssetStatsMain and one for the
  371. * TextureFetch thread pointed to by gViewerAssetStatsThread1.
  372. * Common operations has each thread recording metrics events
  373. * into the respective collector unconcerned with locking and
  374. * the state of any other thread. But when the agent moves into
  375. * a different region or the metrics timer expires and a report
  376. * needs to be sent back to the grid, messaging across threads
  377. * is required to distribute data and perform global actions.
  378. * In pseudo-UML, it looks like:
  379. *
  380. * Main Thread1
  381. * . .
  382. * . .
  383. * +-----+ .
  384. * | AM | .
  385. * +--+--+ .
  386. * +-------+ | .
  387. * | Main | +--+--+ .
  388. * | | | SRE |---. .
  389. * | Stats | +-----+ \ .
  390. * | | | \ (uuid) +-----+
  391. * | Coll. | +--+--+ `-------->| SR |
  392. * +-------+ | MSC | +--+--+
  393. * | ^ +-----+ |
  394. * | | (uuid) / . +-----+ (uuid)
  395. * | `--------' . | MSC |---------.
  396. * | . +-----+ |
  397. * | +-----+ . v
  398. * | | TE | . +-------+
  399. * | +--+--+ . | Thd1 |
  400. * | | . | |
  401. * | +-----+ . | Stats |
  402. * `--------->| RSC | . | |
  403. * +--+--+ . | Coll. |
  404. * | . +-------+
  405. * +--+--+ . |
  406. * | SME |---. . |
  407. * +-----+ \ . |
  408. * . \ (clone) +-----+ |
  409. * . `-------->| SM | |
  410. * . +--+--+ |
  411. * . | |
  412. * . +-----+ |
  413. * . | RSC |<--------'
  414. * . +-----+
  415. * . |
  416. * . +-----+
  417. * . | CP |--> HTTP POST
  418. * . +-----+
  419. * . .
  420. * . .
  421. *
  422. *
  423. * Key:
  424. *
  425. * SRE - Set Region Enqueued. Enqueue a 'Set Region' command in
  426. * the other thread providing the new UUID of the region.
  427. * TFReqSetRegion carries the data.
  428. * SR - Set Region. New region UUID is sent to the thread-local
  429. * collector.
  430. * SME - Send Metrics Enqueued. Enqueue a 'Send Metrics' command
  431. * including an ownership transfer of a cloned LLViewerAssetStats.
  432. * TFReqSendMetrics carries the data.
  433. * SM - Send Metrics. Global metrics reporting operation. Takes
  434. * the cloned stats from the command, merges it with the
  435. * thread's local stats, converts to LLSD and sends it on
  436. * to the grid.
  437. * AM - Agent Moved. Agent has completed some sort of move to a
  438. * new region.
  439. * TE - Timer Expired. Metrics timer has expired (on the order
  440. * of 10 minutes).
  441. * CP - CURL Post
  442. * MSC - Modify Stats Collector. State change in the thread-local
  443. * collector. Typically a region change which affects the
  444. * global pointers used to find the 'current stats'.
  445. * RSC - Read Stats Collector. Extract collector data cloning it
  446. * (i.e. deep copy) when necessary.
  447. *
  448. */
  449. class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
  450. {
  451. public:
  452. // Default ctors and assignment operator are correct.
  453. virtual ~TFRequest()
  454. {}
  455. // Patterned after QueuedRequest's method but expected behavior
  456. // is different. Always expected to complete on the first call
  457. // and work dispatcher will assume the same and delete the
  458. // request after invocation.
  459. virtual bool doWork(LLTextureFetch * fetcher) = 0;
  460. };
  461. namespace
  462. {
  463. /**
  464. * @brief Implements a 'Set Region' cross-thread command.
  465. *
  466. * When an agent moves to a new region, subsequent metrics need
  467. * to be binned into a new or existing stats collection in 1:1
  468. * relationship with the region. We communicate this region
  469. * change across the threads involved in the communication with
  470. * this message.
  471. *
  472. * Corresponds to LLTextureFetch::commandSetRegion()
  473. */
  474. class TFReqSetRegion : public LLTextureFetch::TFRequest
  475. {
  476. public:
  477. TFReqSetRegion(U64 region_handle)
  478. : LLTextureFetch::TFRequest(),
  479. mRegionHandle(region_handle)
  480. {}
  481. TFReqSetRegion & operator=(const TFReqSetRegion &); // Not defined
  482. virtual ~TFReqSetRegion()
  483. {}
  484. virtual bool doWork(LLTextureFetch * fetcher);
  485. public:
  486. const U64 mRegionHandle;
  487. };
  488. /**
  489. * @brief Implements a 'Send Metrics' cross-thread command.
  490. *
  491. * This is the big operation. The main thread gathers metrics
  492. * for a period of minutes into LLViewerAssetStats and other
  493. * objects then makes a snapshot of the data by cloning the
  494. * collector. This command transfers the clone, along with a few
  495. * additional arguments (UUIDs), handing ownership to the
  496. * TextureFetch thread. It then merges its own data into the
  497. * cloned copy, converts to LLSD and kicks off an HTTP POST of
  498. * the resulting data to the currently active metrics collector.
  499. *
  500. * Corresponds to LLTextureFetch::commandSendMetrics()
  501. */
  502. class TFReqSendMetrics : public LLTextureFetch::TFRequest
  503. {
  504. public:
  505. /**
  506. * Construct the 'Send Metrics' command to have the TextureFetch
  507. * thread add and log metrics data.
  508. *
  509. * @param caps_url URL of a "ViewerMetrics" Caps target
  510. * to receive the data. Does not have to
  511. * be associated with a particular region.
  512. *
  513. * @param session_id UUID of the agent's session.
  514. *
  515. * @param agent_id UUID of the agent. (Being pure here...)
  516. *
  517. * @param main_stats Pointer to a clone of the main thread's
  518. * LLViewerAssetStats data. Thread1 takes
  519. * ownership of the copy and disposes of it
  520. * when done.
  521. */
  522. TFReqSendMetrics(const std::string & caps_url,
  523. const LLUUID & session_id,
  524. const LLUUID & agent_id,
  525. LLViewerAssetStats * main_stats)
  526. : LLTextureFetch::TFRequest(),
  527. mCapsURL(caps_url),
  528. mSessionID(session_id),
  529. mAgentID(agent_id),
  530. mMainStats(main_stats)
  531. {}
  532. TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined
  533. virtual ~TFReqSendMetrics();
  534. virtual bool doWork(LLTextureFetch * fetcher);
  535. public:
  536. const std::string mCapsURL;
  537. const LLUUID mSessionID;
  538. const LLUUID mAgentID;
  539. LLViewerAssetStats * mMainStats;
  540. };
  541. /*
  542. * Examines the merged viewer metrics report and if found to be too long,
  543. * will attempt to truncate it in some reasonable fashion.
  544. *
  545. * @param max_regions Limit of regions allowed in report.
  546. *
  547. * @param metrics Full, merged viewer metrics report.
  548. *
  549. * @returns If data was truncated, returns true.
  550. */
  551. bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
  552. } // end of anonymous namespace
  553. //////////////////////////////////////////////////////////////////////////////
  554. //static
  555. const char* LLTextureFetchWorker::sStateDescs[] = {
  556. "INVALID",
  557. "INIT",
  558. "LOAD_FROM_TEXTURE_CACHE",
  559. "CACHE_POST",
  560. "LOAD_FROM_NETWORK",
  561. "LOAD_FROM_SIMULATOR",
  562. "SEND_HTTP_REQ",
  563. "WAIT_HTTP_REQ",
  564. "DECODE_IMAGE",
  565. "DECODE_IMAGE_UPDATE",
  566. "WRITE_TO_CACHE",
  567. "WAIT_ON_WRITE",
  568. "DONE",
  569. };
  570. // static
  571. volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break
  572. // called from MAIN THREAD
  573. LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
  574. const std::string& url, // Optional URL
  575. const LLUUID& id, // Image UUID
  576. const LLHost& host, // Simulator host
  577. F32 priority, // Priority
  578. S32 discard, // Desired discard
  579. S32 size) // Desired size
  580. : LLWorkerClass(fetcher, "TextureFetch"),
  581. mState(INIT),
  582. mWriteToCacheState(NOT_WRITE),
  583. mFetcher(fetcher),
  584. mID(id),
  585. mHost(host),
  586. mUrl(url),
  587. mImagePriority(priority),
  588. mWorkPriority(0),
  589. mRequestedPriority(0.f),
  590. mDesiredDiscard(-1),
  591. mSimRequestedDiscard(-1),
  592. mRequestedDiscard(-1),
  593. mLoadedDiscard(-1),
  594. mDecodedDiscard(-1),
  595. mCacheReadHandle(LLTextureCache::nullHandle()),
  596. mCacheWriteHandle(LLTextureCache::nullHandle()),
  597. mBuffer(NULL),
  598. mBufferSize(0),
  599. mRequestedSize(0),
  600. mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
  601. mFileSize(0),
  602. mCachedSize(0),
  603. mLoaded(FALSE),
  604. mSentRequest(UNSENT),
  605. mDecodeHandle(0),
  606. mDecoded(FALSE),
  607. mWritten(FALSE),
  608. mNeedsAux(FALSE),
  609. mHaveAllData(FALSE),
  610. mInLocalCache(FALSE),
  611. mCanUseHTTP(true),
  612. mHTTPFailCount(0),
  613. mRetryAttempt(0),
  614. mActiveCount(0),
  615. mGetStatus(0),
  616. mWorkMutex(NULL),
  617. mFirstPacket(0),
  618. mLastPacket(-1),
  619. mTotalPackets(0),
  620. mImageCodec(IMG_CODEC_INVALID),
  621. mMetricsStartTime(0)
  622. {
  623. mCanUseNET = mUrl.empty() ;
  624. calcWorkPriority();
  625. mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
  626. // llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
  627. if (!mFetcher->mDebugPause)
  628. {
  629. U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
  630. addWork(0, work_priority );
  631. }
  632. setDesiredDiscard(discard, size);
  633. }
  634. LLTextureFetchWorker::~LLTextureFetchWorker()
  635. {
  636. // llinfos << "Destroy: " << mID
  637. // << " Decoded=" << mDecodedDiscard
  638. // << " Requested=" << mRequestedDiscard
  639. // << " Desired=" << mDesiredDiscard << llendl;
  640. llassert_always(!haveWork());
  641. lockWorkMutex();
  642. if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
  643. {
  644. mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
  645. }
  646. if (mCacheWriteHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
  647. {
  648. mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
  649. }
  650. mFormattedImage = NULL;
  651. clearPackets();
  652. unlockWorkMutex();
  653. mFetcher->removeFromHTTPQueue(mID);
  654. }
  655. void LLTextureFetchWorker::clearPackets()
  656. {
  657. for_each(mPackets.begin(), mPackets.end(), DeletePointer());
  658. mPackets.clear();
  659. mTotalPackets = 0;
  660. mLastPacket = -1;
  661. mFirstPacket = 0;
  662. }
  663. void LLTextureFetchWorker::setupPacketData()
  664. {
  665. S32 data_size = 0;
  666. if (mFormattedImage.notNull())
  667. {
  668. data_size = mFormattedImage->getDataSize();
  669. }
  670. if (data_size > 0)
  671. {
  672. // Only used for simulator requests
  673. mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
  674. if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
  675. {
  676. llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
  677. removeFromCache();
  678. resetFormattedData();
  679. clearPackets();
  680. }
  681. else if (mFileSize > 0)
  682. {
  683. mLastPacket = mFirstPacket-1;
  684. mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
  685. }
  686. else
  687. {
  688. // This file was cached using HTTP so we have to refetch the first packet
  689. resetFormattedData();
  690. clearPackets();
  691. }
  692. }
  693. }
  694. U32 LLTextureFetchWorker::calcWorkPriority()
  695. {
  696. //llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerFetchedTexture::maxDecodePriority());
  697. static const F32 PRIORITY_SCALE = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerFetchedTexture::maxDecodePriority();
  698. mWorkPriority = llmin((U32)LLWorkerThread::PRIORITY_LOWBITS, (U32)(mImagePriority * PRIORITY_SCALE));
  699. return mWorkPriority;
  700. }
  701. // mWorkMutex is locked
  702. void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size)
  703. {
  704. bool prioritize = false;
  705. if (mDesiredDiscard != discard)
  706. {
  707. if (!haveWork())
  708. {
  709. calcWorkPriority();
  710. if (!mFetcher->mDebugPause)
  711. {
  712. U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
  713. addWork(0, work_priority);
  714. }
  715. }
  716. else if (mDesiredDiscard < discard)
  717. {
  718. prioritize = true;
  719. }
  720. mDesiredDiscard = discard;
  721. mDesiredSize = size;
  722. }
  723. else if (size > mDesiredSize)
  724. {
  725. mDesiredSize = size;
  726. prioritize = true;
  727. }
  728. mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
  729. if ((prioritize && mState == INIT) || mState == DONE)
  730. {
  731. mState = INIT;
  732. U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
  733. setPriority(work_priority);
  734. }
  735. }
  736. void LLTextureFetchWorker::setImagePriority(F32 priority)
  737. {
  738. // llassert_always(priority >= 0 && priority <= LLViewerTexture::maxDecodePriority());
  739. F32 delta = fabs(priority - mImagePriority);
  740. if (delta > (mImagePriority * .05f) || mState == DONE)
  741. {
  742. mImagePriority = priority;
  743. calcWorkPriority();
  744. U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS);
  745. setPriority(work_priority);
  746. }
  747. }
  748. void LLTextureFetchWorker::resetFormattedData()
  749. {
  750. FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
  751. mBuffer = NULL;
  752. mBufferSize = 0;
  753. if (mFormattedImage.notNull())
  754. {
  755. mFormattedImage->deleteData();
  756. }
  757. mHaveAllData = FALSE;
  758. }
  759. // Called from MAIN thread
  760. void LLTextureFetchWorker::startWork(S32 param)
  761. {
  762. llassert(mFormattedImage.isNull());
  763. }
  764. #include "llviewertexturelist.h" // debug
  765. // Called from LLWorkerThread::processRequest()
  766. bool LLTextureFetchWorker::doWork(S32 param)
  767. {
  768. LLMutexLock lock(&mWorkMutex);
  769. if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
  770. {
  771. if (mState < DECODE_IMAGE)
  772. {
  773. return true; // abort
  774. }
  775. }
  776. if(mImagePriority < F_ALMOST_ZERO)
  777. {
  778. if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
  779. {
  780. return true; // abort
  781. }
  782. }
  783. if(mState > CACHE_POST && !mCanUseNET && !mCanUseHTTP)
  784. {
  785. //nowhere to get data, abort.
  786. return true ;
  787. }
  788. if (mFetcher->mDebugPause)
  789. {
  790. return false; // debug: don't do any work
  791. }
  792. if (mID == mFetcher->mDebugID)
  793. {
  794. mFetcher->mDebugCount++; // for setting breakpoints
  795. }
  796. if (mState != DONE)
  797. {
  798. mFetchTimer.reset();
  799. }
  800. if (mState == INIT)
  801. {
  802. mRawImage = NULL ;
  803. mRequestedDiscard = -1;
  804. mLoadedDiscard = -1;
  805. mDecodedDiscard = -1;
  806. mRequestedSize = 0;
  807. mFileSize = 0;
  808. mCachedSize = 0;
  809. mLoaded = FALSE;
  810. mSentRequest = UNSENT;
  811. mDecoded = FALSE;
  812. mWritten = FALSE;
  813. FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
  814. mBuffer = NULL;
  815. mBufferSize = 0;
  816. mHaveAllData = FALSE;
  817. clearPackets(); // TODO: Shouldn't be necessary
  818. mCacheReadHandle = LLTextureCache::nullHandle();
  819. mCacheWriteHandle = LLTextureCache::nullHandle();
  820. mState = LOAD_FROM_TEXTURE_CACHE;
  821. mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE
  822. LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
  823. << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
  824. // fall through
  825. }
  826. if (mState == LOAD_FROM_TEXTURE_CACHE)
  827. {
  828. if (mCacheReadHandle == LLTextureCache::nullHandle())
  829. {
  830. U32 cache_priority = mWorkPriority;
  831. S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
  832. S32 size = mDesiredSize - offset;
  833. if (size <= 0)
  834. {
  835. mState = CACHE_POST;
  836. return false;
  837. }
  838. mFileSize = 0;
  839. mLoaded = FALSE;
  840. if (mUrl.compare(0, 7, "file://") == 0)
  841. {
  842. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
  843. // read file from local disk
  844. std::string filename = mUrl.substr(7, std::string::npos);
  845. CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
  846. mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
  847. offset, size, responder);
  848. }
  849. else if (mUrl.empty())
  850. {
  851. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
  852. CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
  853. mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
  854. offset, size, responder);
  855. }
  856. else if(mCanUseHTTP)
  857. {
  858. if (!(mUrl.compare(0, 7, "http://") == 0))
  859. {
  860. // *TODO:?remove this warning
  861. llwarns << "Unknown URL Type: " << mUrl << llendl;
  862. }
  863. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  864. mState = SEND_HTTP_REQ;
  865. }
  866. else
  867. {
  868. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  869. mState = LOAD_FROM_NETWORK;
  870. }
  871. }
  872. if (mLoaded)
  873. {
  874. // Make sure request is complete. *TODO: make this auto-complete
  875. if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false))
  876. {
  877. mCacheReadHandle = LLTextureCache::nullHandle();
  878. mState = CACHE_POST;
  879. // fall through
  880. }
  881. else
  882. {
  883. return false;
  884. }
  885. }
  886. else
  887. {
  888. return false;
  889. }
  890. }
  891. if (mState == CACHE_POST)
  892. {
  893. mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
  894. // Successfully loaded
  895. if ((mCachedSize >= mDesiredSize) || mHaveAllData)
  896. {
  897. // we have enough data, decode it
  898. llassert_always(mFormattedImage->getDataSize() > 0);
  899. mLoadedDiscard = mDesiredDiscard;
  900. mState = DECODE_IMAGE;
  901. mWriteToCacheState = NOT_WRITE ;
  902. LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize()
  903. << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight())
  904. << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
  905. // fall through
  906. }
  907. else
  908. {
  909. if (mUrl.compare(0, 7, "file://") == 0)
  910. {
  911. // failed to load local file, we're done.
  912. return true;
  913. }
  914. // need more data
  915. else
  916. {
  917. LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
  918. mState = LOAD_FROM_NETWORK;
  919. }
  920. // fall through
  921. }
  922. }
  923. if (mState == LOAD_FROM_NETWORK)
  924. {
  925. static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
  926. // if (mHost != LLHost::invalid) get_url = false;
  927. if ( use_http && mCanUseHTTP && mUrl.empty())//get http url.
  928. {
  929. LLViewerRegion* region = NULL;
  930. if (mHost == LLHost::invalid)
  931. region = gAgent.getRegion();
  932. else
  933. region = LLWorld::getInstance()->getRegion(mHost);
  934. if (region)
  935. {
  936. std::string http_url = region->getHttpUrl() ;
  937. if (!http_url.empty())
  938. {
  939. mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
  940. mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
  941. }
  942. else
  943. {
  944. mCanUseHTTP = false ;
  945. }
  946. }
  947. else
  948. {
  949. // This will happen if not logged in or if a region deoes not have HTTP Texture enabled
  950. //llwarns << "Region not found for host: " << mHost << llendl;
  951. mCanUseHTTP = false;
  952. }
  953. }
  954. if (mCanUseHTTP && !mUrl.empty())
  955. {
  956. mState = LLTextureFetchWorker::SEND_HTTP_REQ;
  957. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  958. if(mWriteToCacheState != NOT_WRITE)
  959. {
  960. mWriteToCacheState = CAN_WRITE ;
  961. }
  962. // don't return, fall through to next state
  963. }
  964. else if (mSentRequest == UNSENT && mCanUseNET)
  965. {
  966. // Add this to the network queue and sit here.
  967. // LLTextureFetch::update() will send off a request which will change our state
  968. mWriteToCacheState = CAN_WRITE ;
  969. mRequestedSize = mDesiredSize;
  970. mRequestedDiscard = mDesiredDiscard;
  971. mSentRequest = QUEUED;
  972. mFetcher->addToNetworkQueue(this);
  973. if (! mMetricsStartTime)
  974. {
  975. mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
  976. }
  977. LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
  978. false,
  979. LLImageBase::TYPE_AVATAR_BAKE == mType);
  980. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  981. return false;
  982. }
  983. else
  984. {
  985. // Shouldn't need to do anything here
  986. //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
  987. // Make certain this is in the network queue
  988. //mFetcher->addToNetworkQueue(this);
  989. //if (! mMetricsStartTime)
  990. //{
  991. // mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
  992. //}
  993. //LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
  994. // LLImageBase::TYPE_AVATAR_BAKE == mType);
  995. //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  996. return false;
  997. }
  998. }
  999. if (mState == LOAD_FROM_SIMULATOR)
  1000. {
  1001. if (mFormattedImage.isNull())
  1002. {
  1003. mFormattedImage = new LLImageJ2C;
  1004. }
  1005. if (processSimulatorPackets())
  1006. {
  1007. LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL;
  1008. mFetcher->removeFromNetworkQueue(this, false);
  1009. if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
  1010. {
  1011. // processSimulatorPackets() failed
  1012. // llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
  1013. return true; // failed
  1014. }
  1015. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1016. mState = DECODE_IMAGE;
  1017. mWriteToCacheState = SHOULD_WRITE;
  1018. if (mMetricsStartTime)
  1019. {
  1020. LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
  1021. false,
  1022. LLImageBase::TYPE_AVATAR_BAKE == mType,
  1023. LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
  1024. mMetricsStartTime = 0;
  1025. }
  1026. LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
  1027. false,
  1028. LLImageBase::TYPE_AVATAR_BAKE == mType);
  1029. }
  1030. else
  1031. {
  1032. mFetcher->addToNetworkQueue(this); // failsafe
  1033. if (! mMetricsStartTime)
  1034. {
  1035. mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
  1036. }
  1037. LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
  1038. false,
  1039. LLImageBase::TYPE_AVATAR_BAKE == mType);
  1040. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1041. }
  1042. return false;
  1043. }
  1044. if (mState == SEND_HTTP_REQ)
  1045. {
  1046. if(mCanUseHTTP)
  1047. {
  1048. //NOTE:
  1049. //control the number of the http requests issued for:
  1050. //1, not openning too many file descriptors at the same time;
  1051. //2, control the traffic of http so udp gets bandwidth.
  1052. //
  1053. static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ;
  1054. if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE)
  1055. {
  1056. return false ; //wait.
  1057. }
  1058. mFetcher->removeFromNetworkQueue(this, false);
  1059. S32 cur_size = 0;
  1060. if (mFormattedImage.notNull())
  1061. {
  1062. cur_size = mFormattedImage->getDataSize(); // amount of data we already have
  1063. if (mFormattedImage->getDiscardLevel() == 0)
  1064. {
  1065. if(cur_size > 0)
  1066. {
  1067. // We already have all the data, just decode it
  1068. mLoadedDiscard = mFormattedImage->getDiscardLevel();
  1069. mState = DECODE_IMAGE;
  1070. return false;
  1071. }
  1072. else
  1073. {
  1074. return true ; //abort.
  1075. }
  1076. }
  1077. }
  1078. mRequestedSize = mDesiredSize;
  1079. mRequestedDiscard = mDesiredDiscard;
  1080. mRequestedSize -= cur_size;
  1081. S32 offset = cur_size;
  1082. mBufferSize = cur_size; // This will get modified by callbackHttpGet()
  1083. bool res = false;
  1084. if (!mUrl.empty())
  1085. {
  1086. mLoaded = FALSE;
  1087. mGetStatus = 0;
  1088. mGetReason.clear();
  1089. LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset
  1090. << " Bytes: " << mRequestedSize
  1091. << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth
  1092. << LL_ENDL;
  1093. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1094. mState = WAIT_HTTP_REQ;
  1095. mFetcher->addToHTTPQueue(mID);
  1096. if (! mMetricsStartTime)
  1097. {
  1098. mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
  1099. }
  1100. LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
  1101. true,
  1102. LLImageBase::TYPE_AVATAR_BAKE == mType);
  1103. // Will call callbackHttpGet when curl request completes
  1104. std::vector<std::string> headers;
  1105. headers.push_back("Accept: image/x-j2c");
  1106. res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
  1107. new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true));
  1108. }
  1109. if (!res)
  1110. {
  1111. llwarns << "HTTP GET request failed for " << mID << llendl;
  1112. resetFormattedData();
  1113. ++mHTTPFailCount;
  1114. return true; // failed
  1115. }
  1116. // fall through
  1117. }
  1118. else //can not use http fetch.
  1119. {
  1120. return true ; //abort
  1121. }
  1122. }
  1123. if (mState == WAIT_HTTP_REQ)
  1124. {
  1125. if (mLoaded)
  1126. {
  1127. S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
  1128. if (mRequestedSize < 0)
  1129. {
  1130. S32 max_attempts;
  1131. if (mGetStatus == HTTP_NOT_FOUND)
  1132. {
  1133. mHTTPFailCount = max_attempts = 1; // Don't retry
  1134. llwarns << "Texture missing from server (404): " << mUrl << llendl;
  1135. //roll back to try UDP
  1136. if(mCanUseNET)
  1137. {
  1138. mState = INIT ;
  1139. mCanUseHTTP = false ;
  1140. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1141. return false ;
  1142. }
  1143. }
  1144. else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE)
  1145. {
  1146. // *TODO: Should probably introduce a timer here to delay future HTTP requsts
  1147. // for a short time (~1s) to ease server load? Ideally the server would queue
  1148. // requests instead of returning 503... we already limit the number pending.
  1149. ++mHTTPFailCount;
  1150. max_attempts = mHTTPFailCount+1; // Keep retrying
  1151. LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL;
  1152. }
  1153. else
  1154. {
  1155. const S32 HTTP_MAX_RETRY_COUNT = 3;
  1156. max_attempts = HTTP_MAX_RETRY_COUNT + 1;
  1157. ++mHTTPFailCount;
  1158. llinfos << "HTTP GET failed for: " << mUrl
  1159. << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
  1160. << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
  1161. }
  1162. if (mHTTPFailCount >= max_attempts)
  1163. {
  1164. if (cur_size > 0)
  1165. {
  1166. // Use available data
  1167. mLoadedDiscard = mFormattedImage->getDiscardLevel();
  1168. mState = DECODE_IMAGE;
  1169. return false;
  1170. }
  1171. else
  1172. {
  1173. resetFormattedData();
  1174. mState = DONE;
  1175. return true; // failed
  1176. }
  1177. }
  1178. else
  1179. {
  1180. mState = SEND_HTTP_REQ;
  1181. return false; // retry
  1182. }
  1183. }
  1184. llassert_always(mBufferSize == cur_size + mRequestedSize);
  1185. if(!mBufferSize)//no data received.
  1186. {
  1187. FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
  1188. mBuffer = NULL;
  1189. //abort.
  1190. mState = DONE;
  1191. return true;
  1192. }
  1193. if (mFormattedImage.isNull())
  1194. {
  1195. // For now, create formatted image based on extension
  1196. std::string extension = gDirUtilp->getExtension(mUrl);
  1197. mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension));
  1198. if (mFormattedImage.isNull())
  1199. {
  1200. mFormattedImage = new LLImageJ2C; // default
  1201. }
  1202. }
  1203. if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded.
  1204. {
  1205. mFileSize = mBufferSize;
  1206. }
  1207. else //the file size is unknown.
  1208. {
  1209. mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
  1210. }
  1211. U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize);
  1212. if (cur_size > 0)
  1213. {
  1214. memcpy(buffer, mFormattedImage->getData(), cur_size);
  1215. }
  1216. memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append
  1217. // NOTE: setData releases current data and owns new data (buffer)
  1218. mFormattedImage->setData(buffer, mBufferSize);
  1219. // delete temp data
  1220. FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData())
  1221. mBuffer = NULL;
  1222. mBufferSize = 0;
  1223. mLoadedDiscard = mRequestedDiscard;
  1224. mState = DECODE_IMAGE;
  1225. if(mWriteToCacheState != NOT_WRITE)
  1226. {
  1227. mWriteToCacheState = SHOULD_WRITE ;
  1228. }
  1229. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1230. return false;
  1231. }
  1232. else
  1233. {
  1234. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1235. return false;
  1236. }
  1237. }
  1238. if (mState == DECODE_IMAGE)
  1239. {
  1240. static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled");
  1241. if(textures_decode_disabled)
  1242. {
  1243. // for debug use, don't decode
  1244. mState = DONE;
  1245. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1246. return true;
  1247. }
  1248. if (mDesiredDiscard < 0)
  1249. {
  1250. // We aborted, don't decode
  1251. mState = DONE;
  1252. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1253. return true;
  1254. }
  1255. if (mFormattedImage->getDataSize() <= 0)
  1256. {
  1257. //llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl;
  1258. //abort, don't decode
  1259. mState = DONE;
  1260. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1261. return true;
  1262. }
  1263. if (mLoadedDiscard < 0)
  1264. {
  1265. //llerrs << "Decode entered with invalid mLoadedDiscard. ID = " << mID << llendl;
  1266. //abort, don't decode
  1267. mState = DONE;
  1268. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1269. return true;
  1270. }
  1271. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
  1272. mRawImage = NULL;
  1273. mAuxImage = NULL;
  1274. llassert_always(mFormattedImage.notNull());
  1275. S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
  1276. U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
  1277. mDecoded = FALSE;
  1278. mState = DECODE_IMAGE_UPDATE;
  1279. LL_DEBUGS("Texture") << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard
  1280. << " All Data: " << mHaveAllData << LL_ENDL;
  1281. mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux,
  1282. new DecodeResponder(mFetcher, mID, this));
  1283. // fall though
  1284. }
  1285. if (mState == DECODE_IMAGE_UPDATE)
  1286. {
  1287. if (mDecoded)
  1288. {
  1289. if (mDecodedDiscard < 0)
  1290. {
  1291. LL_DEBUGS("Texture") << mID << ": Failed to Decode." << LL_ENDL;
  1292. if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)
  1293. {
  1294. // Cache file should be deleted, try again
  1295. // llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl;
  1296. llassert_always(mDecodeHandle == 0);
  1297. mFormattedImage = NULL;
  1298. ++mRetryAttempt;
  1299. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1300. mState = INIT;
  1301. return false;
  1302. }
  1303. else
  1304. {
  1305. // llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl;
  1306. mState = DONE; // failed
  1307. }
  1308. }
  1309. else
  1310. {
  1311. llassert_always(mRawImage.notNull());
  1312. LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard
  1313. << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
  1314. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1315. mState = WRITE_TO_CACHE;
  1316. }
  1317. // fall through
  1318. }
  1319. else
  1320. {
  1321. return false;
  1322. }
  1323. }
  1324. if (mState == WRITE_TO_CACHE)
  1325. {
  1326. if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull())
  1327. {
  1328. // If we're in a local cache or we didn't actually receive any new data,
  1329. // or we failed to load anything, skip
  1330. mState = DONE;
  1331. return false;
  1332. }
  1333. S32 datasize = mFormattedImage->getDataSize();
  1334. if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed.
  1335. {
  1336. if(mHaveAllData)
  1337. {
  1338. mFileSize = datasize ;
  1339. }
  1340. else
  1341. {
  1342. mFileSize = datasize + 1 ; //flag not fully loaded.
  1343. }
  1344. }
  1345. llassert_always(datasize);
  1346. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
  1347. U32 cache_priority = mWorkPriority;
  1348. mWritten = FALSE;
  1349. mState = WAIT_ON_WRITE;
  1350. CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID);
  1351. mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
  1352. mFormattedImage->getData(), datasize,
  1353. mFileSize, responder);
  1354. // fall through
  1355. }
  1356. if (mState == WAIT_ON_WRITE)
  1357. {
  1358. if (writeToCacheComplete())
  1359. {
  1360. mState = DONE;
  1361. // fall through
  1362. }
  1363. else
  1364. {
  1365. if (mDesiredDiscard < mDecodedDiscard)
  1366. {
  1367. // We're waiting for this write to complete before we can receive more data
  1368. // (we can't touch mFormattedImage until the write completes)
  1369. // Prioritize the write
  1370. mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle);
  1371. }
  1372. return false;
  1373. }
  1374. }
  1375. if (mState == DONE)
  1376. {
  1377. if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard)
  1378. {
  1379. // More data was requested, return to INIT
  1380. mState = INIT;
  1381. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1382. return false;
  1383. }
  1384. else
  1385. {
  1386. setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
  1387. return true;
  1388. }
  1389. }
  1390. return false;
  1391. }
  1392. // Called from MAIN thread
  1393. void LLTextureFetchWorker::endWork(S32 param, bool aborted)
  1394. {
  1395. if (mDecodeHandle != 0)
  1396. {
  1397. mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
  1398. mDecodeHandle = 0;
  1399. }
  1400. mFormattedImage = NULL;
  1401. }
  1402. //////////////////////////////////////////////////////////////////////////////
  1403. // virtual
  1404. void LLTextureFetchWorker::finishWork(S32 param, bool completed)
  1405. {
  1406. // The following are required in case the work was aborted
  1407. if (mCacheReadHandle != LLTextureCache::nullHandle())
  1408. {
  1409. mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
  1410. mCacheReadHandle = LLTextureCache::nullHandle();
  1411. }
  1412. if (mCacheWriteHandle != LLTextureCache::nullHandle())
  1413. {
  1414. mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
  1415. mCacheWriteHandle = LLTextureCache::nullHandle();
  1416. }
  1417. }
  1418. // virtual
  1419. bool LLTextureFetchWorker::deleteOK()
  1420. {
  1421. bool delete_ok = true;
  1422. // Allow any pending reads or writes to complete
  1423. if (mCacheReadHandle != LLTextureCache::nullHandle())
  1424. {
  1425. if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true))
  1426. {
  1427. mCacheReadHandle = LLTextureCache::nullHandle();
  1428. }
  1429. else
  1430. {
  1431. delete_ok = false;
  1432. }
  1433. }
  1434. if (mCacheWriteHandle != LLTextureCache::nullHandle())
  1435. {
  1436. if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
  1437. {
  1438. mCacheWriteHandle = LLTextureCache::nullHandle();
  1439. }
  1440. else
  1441. {
  1442. delete_ok = false;
  1443. }
  1444. }
  1445. if ((haveWork() &&
  1446. // not ok to delete from these states
  1447. ((mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
  1448. {
  1449. delete_ok = false;
  1450. }
  1451. return delete_ok;
  1452. }
  1453. void LLTextureFetchWorker::removeFromCache()
  1454. {
  1455. if (!mInLocalCache)
  1456. {
  1457. mFetcher->mTextureCache->removeFromCache(mID);
  1458. }
  1459. }
  1460. //////////////////////////////////////////////////////////////////////////////
  1461. bool LLTextureFetchWorker::processSimulatorPackets()
  1462. {
  1463. if (mFormattedImage.isNull() || mRequestedSize < 0)
  1464. {
  1465. // not sure how we got here, but not a valid state, abort!
  1466. llassert_always(mDecodeHandle == 0);
  1467. mFormattedImage = NULL;
  1468. return true;
  1469. }
  1470. if (mLastPacket >= mFirstPacket)
  1471. {
  1472. S32 buffer_size = mFormattedImage->getDataSize();
  1473. for (S32 i = mFirstPacket; i<=mLastPacket; i++)
  1474. {
  1475. llassert_always(mPackets[i]);
  1476. buffer_size += mPackets[i]->mSize;
  1477. }
  1478. bool have_all_data = mLastPacket >= mTotalPackets-1;
  1479. if (mRequestedSize <= 0)
  1480. {
  1481. // We received a packed but haven't requested anything yet (edge case)
  1482. // Return true (we're "done") since we didn't request anything
  1483. return true;
  1484. }
  1485. if (buffer_size >= mRequestedSize || have_all_data)
  1486. {
  1487. /// We have enough (or all) data
  1488. if (have_all_data)
  1489. {
  1490. mHaveAllData = TRUE;
  1491. }
  1492. S32 cur_size = mFormattedImage->getDataSize();
  1493. if (buffer_size > cur_size)
  1494. {
  1495. /// We have new data
  1496. U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), buffer_size);
  1497. S32 offset = 0;
  1498. if (cur_size > 0 && mFirstPacket > 0)
  1499. {
  1500. memcpy(buffer, mFormattedImage->getData(), cur_size);
  1501. offset = cur_size;
  1502. }
  1503. for (S32 i=mFirstPacket; i<=mLastPacket; i++)
  1504. {
  1505. memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize);
  1506. offset += mPackets[i]->mSize;
  1507. }
  1508. // NOTE: setData releases current data
  1509. mFormattedImage->setData(buffer, buffer_size);
  1510. }
  1511. mLoadedDiscard = mRequestedDiscard;
  1512. return true;
  1513. }
  1514. }
  1515. return false;
  1516. }
  1517. //////////////////////////////////////////////////////////////////////////////
  1518. S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
  1519. const LLIOPipe::buffer_ptr_t& buffer,
  1520. bool partial, bool success)
  1521. {
  1522. S32 data_size = 0 ;
  1523. LLMutexLock lock(&mWorkMutex);
  1524. if (mState != WAIT_HTTP_REQ)
  1525. {
  1526. llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
  1527. << " req=" << mSentRequest << " state= " << mState << llendl;
  1528. return data_size;
  1529. }
  1530. if (mLoaded)
  1531. {
  1532. llwarns << "Duplicate callback for " << mID.asString() << llendl;
  1533. return data_size ; // ignore duplicate callback
  1534. }
  1535. if (success)
  1536. {
  1537. // get length of stream:
  1538. data_size = buffer->countAfter(channels.in(), NULL);
  1539. LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL;
  1540. if (data_size > 0)
  1541. {
  1542. // *TODO: set the formatted image data here directly to avoid the copy
  1543. mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size);
  1544. buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
  1545. mBufferSize += data_size;
  1546. if (data_size < mRequestedSize && mRequestedDiscard == 0)
  1547. {
  1548. mHaveAllData = TRUE;
  1549. }
  1550. else if (data_size > mRequestedSize)
  1551. {
  1552. // *TODO: This shouldn't be happening any more
  1553. llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
  1554. mHaveAllData = TRUE;
  1555. llassert_always(mDecodeHandle == 0);
  1556. mFormattedImage = NULL; // discard any previous data we had
  1557. mBufferSize = data_size;
  1558. }
  1559. }
  1560. else
  1561. {
  1562. // We requested data but received none (and no error),
  1563. // so presumably we have all of it
  1564. mHaveAllData = TRUE;
  1565. }
  1566. mRequestedSize = data_size;
  1567. }
  1568. else
  1569. {
  1570. mRequestedSize = -1; // error
  1571. }
  1572. mLoaded = TRUE;
  1573. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1574. return data_size ;
  1575. }
  1576. //////////////////////////////////////////////////////////////////////////////
  1577. void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image,
  1578. S32 imagesize, BOOL islocal)
  1579. {
  1580. LLMutexLock lock(&mWorkMutex);
  1581. if (mState != LOAD_FROM_TEXTURE_CACHE)
  1582. {
  1583. // llwarns << "Read callback for " << mID << " with state = " << mState << llendl;
  1584. return;
  1585. }
  1586. if (success)
  1587. {
  1588. llassert_always(imagesize >= 0);
  1589. mFileSize = imagesize;
  1590. mFormattedImage = image;
  1591. mImageCodec = image->getCodec();
  1592. mInLocalCache = islocal;
  1593. if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize)
  1594. {
  1595. mHaveAllData = TRUE;
  1596. }
  1597. }
  1598. mLoaded = TRUE;
  1599. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1600. }
  1601. void LLTextureFetchWorker::callbackCacheWrite(bool success)
  1602. {
  1603. LLMutexLock lock(&mWorkMutex);
  1604. if (mState != WAIT_ON_WRITE)
  1605. {
  1606. // llwarns << "Write callback for " << mID << " with state = " << mState << llendl;
  1607. return;
  1608. }
  1609. mWritten = TRUE;
  1610. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1611. }
  1612. //////////////////////////////////////////////////////////////////////////////
  1613. void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux)
  1614. {
  1615. LLMutexLock lock(&mWorkMutex);
  1616. if (mDecodeHandle == 0)
  1617. {
  1618. return; // aborted, ignore
  1619. }
  1620. if (mState != DECODE_IMAGE_UPDATE)
  1621. {
  1622. // llwarns << "Decode callback for " << mID << " with state = " << mState << llendl;
  1623. mDecodeHandle = 0;
  1624. return;
  1625. }
  1626. llassert_always(mFormattedImage.notNull());
  1627. mDecodeHandle = 0;
  1628. if (success)
  1629. {
  1630. llassert_always(raw);
  1631. mRawImage = raw;
  1632. mAuxImage = aux;
  1633. mDecodedDiscard = mFormattedImage->getDiscardLevel();
  1634. LL_DEBUGS("Texture") << mID << ": Decode Finished. Discard: " << mDecodedDiscard
  1635. << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
  1636. }
  1637. else
  1638. {
  1639. llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
  1640. removeFromCache();
  1641. mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
  1642. }
  1643. mDecoded = TRUE;
  1644. // llinfos << mID << " : DECODE COMPLETE " << llendl;
  1645. setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
  1646. }
  1647. //////////////////////////////////////////////////////////////////////////////
  1648. bool LLTextureFetchWorker::writeToCacheComplete()
  1649. {
  1650. // Complete write to cache
  1651. if (mCacheWriteHandle != LLTextureCache::nullHandle())
  1652. {
  1653. if (!mWritten)
  1654. {
  1655. return false;
  1656. }
  1657. if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
  1658. {
  1659. mCacheWriteHandle = LLTextureCache::nullHandle();
  1660. }
  1661. else
  1662. {
  1663. return false;
  1664. }
  1665. }
  1666. return true;
  1667. }
  1668. //////////////////////////////////////////////////////////////////////////////
  1669. //////////////////////////////////////////////////////////////////////////////
  1670. // public
  1671. LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode)
  1672. : LLWorkerThread("TextureFetch", threaded, true),
  1673. mDebugCount(0),
  1674. mDebugPause(FALSE),
  1675. mPacketCount(0),
  1676. mBadPacketCount(0),
  1677. mQueueMutex(getAPRPool()),
  1678. mNetworkQueueMutex(getAPRPool()),
  1679. mTextureCache(cache),
  1680. mImageDecodeThread(imagedecodethread),
  1681. mTextureBandwidth(0),
  1682. mHTTPTextureBits(0),
  1683. mTotalHTTPRequests(0),
  1684. mCurlGetRequest(NULL),
  1685. mQAMode(qa_mode)
  1686. {
  1687. mCurlPOSTRequestCount = 0;
  1688. mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
  1689. mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
  1690. }
  1691. LLTextureFetch::~LLTextureFetch()
  1692. {
  1693. clearDeleteList() ;
  1694. while (! mCommands.empty())
  1695. {
  1696. TFRequest * req(mCommands.front());
  1697. mCommands.erase(mCommands.begin());
  1698. delete req;
  1699. }
  1700. // ~LLQueuedThread() called here
  1701. }
  1702. bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
  1703. S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http)
  1704. {
  1705. if (mDebugPause)
  1706. {
  1707. return false;
  1708. }
  1709. LLTextureFetchWorker* worker = getWorker(id) ;
  1710. if (worker)
  1711. {
  1712. if (worker->mHost != host)
  1713. {
  1714. llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: "
  1715. << host << " != " << worker->mHost << llendl;
  1716. removeRequest(worker, true);
  1717. worker = NULL;
  1718. return false;
  1719. }
  1720. }
  1721. S32 desired_size;
  1722. std::string exten = gDirUtilp->getExtension(url);
  1723. if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
  1724. {
  1725. // Only do partial requests for J2C at the moment
  1726. desired_size = MAX_IMAGE_DATA_SIZE;
  1727. desired_discard = 0;
  1728. }
  1729. else if (desired_discard == 0)
  1730. {
  1731. // if we want the entire image, and we know its size, then get it all
  1732. // (calcDataSizeJ2C() below makes assumptions about how the image
  1733. // was compressed - this code ensures that when we request the entire image,
  1734. // we really do get it.)
  1735. desired_size = MAX_IMAGE_DATA_SIZE;
  1736. }
  1737. else if (w*h*c > 0)
  1738. {
  1739. // If the requester knows the dimensions of the image,
  1740. // this will calculate how much data we need without having to parse the header
  1741. desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard);
  1742. }
  1743. else
  1744. {
  1745. desired_size = TEXTURE_CACHE_ENTRY_SIZE;
  1746. desired_discard = MAX_DISCARD_LEVEL;
  1747. }
  1748. if (worker)
  1749. {
  1750. if (worker->wasAborted())
  1751. {
  1752. return false; // need to wait for previous aborted request to complete
  1753. }
  1754. worker->lockWorkMutex();
  1755. worker->mActiveCount++;
  1756. worker->mNeedsAux = needs_aux;
  1757. worker->setImagePriority(priority);
  1758. worker->setDesiredDiscard(desired_discard, desired_size);
  1759. worker->setCanUseHTTP(can_use_http) ;
  1760. if (!worker->haveWork())
  1761. {
  1762. worker->mState = LLTextureFetchWorker::INIT;
  1763. worker->unlockWorkMutex();
  1764. worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
  1765. }
  1766. else
  1767. {
  1768. worker->unlockWorkMutex();
  1769. }
  1770. }
  1771. else
  1772. {
  1773. worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
  1774. lockQueue() ;
  1775. mRequestMap[id] = worker;
  1776. unlockQueue() ;
  1777. worker->lockWorkMutex();
  1778. worker->mActiveCount++;
  1779. worker->mNeedsAux = needs_aux;
  1780. worker->setCanUseHTTP(can_use_http) ;
  1781. worker->unlockWorkMutex();
  1782. }
  1783. // llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl;
  1784. return true;
  1785. }
  1786. // protected
  1787. void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
  1788. {
  1789. lockQueue() ;
  1790. bool in_request_map = (mRequestMap.find(worker->mID) != mRequestMap.end()) ;
  1791. unlockQueue() ;
  1792. LLMutexLock lock(&mNetworkQueueMutex);
  1793. if (in_request_map)
  1794. {
  1795. // only add to the queue if in the request map
  1796. // i.e. a delete has not been requested
  1797. mNetworkQueue.insert(worker->mID);
  1798. }
  1799. for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
  1800. iter1 != mCancelQueue.end(); ++iter1)
  1801. {
  1802. iter1->second.erase(worker->mID);
  1803. }
  1804. }
  1805. void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
  1806. {
  1807. LLMutexLock lock(&mNetworkQueueMutex);
  1808. size_t erased = mNetworkQueue.erase(worker->mID);
  1809. if (cancel && erased > 0)
  1810. {
  1811. mCancelQueue[worker->mHost].insert(worker->mID);
  1812. }
  1813. }
  1814. // protected
  1815. void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
  1816. {
  1817. LLMutexLock lock(&mNetworkQueueMutex);
  1818. mHTTPTextureQueue.insert(id);
  1819. mTotalHTTPRequests++;
  1820. }
  1821. void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
  1822. {
  1823. LLMutexLock lock(&mNetworkQueueMutex);
  1824. mHTTPTextureQueue.erase(id);
  1825. mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits
  1826. }
  1827. void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
  1828. {
  1829. lockQueue() ;
  1830. LLTextureFetchWorker* worker = getWorkerAfterLock(id);
  1831. if (worker)
  1832. {
  1833. size_t erased_1 = mRequestMap.erase(worker->mID);
  1834. unlockQueue() ;
  1835. llassert_always(erased_1 > 0) ;
  1836. removeFromNetworkQueue(worker, cancel);
  1837. llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
  1838. worker->scheduleDelete();
  1839. }
  1840. else
  1841. {
  1842. unlockQueue() ;
  1843. }
  1844. }
  1845. void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
  1846. {
  1847. lockQueue() ;
  1848. size_t erased_1 = mRequestMap.erase(worker->mID);
  1849. unlockQueue() ;
  1850. llassert_always(erased_1 > 0) ;
  1851. removeFromNetworkQueue(worker, cancel);
  1852. llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
  1853. worker->scheduleDelete();
  1854. }
  1855. S32 LLTextureFetch::getNumRequests()
  1856. {
  1857. lockQueue() ;
  1858. S32 size = (S32)mRequestMap.size();
  1859. unlockQueue() ;
  1860. return size ;
  1861. }
  1862. S32 LLTextureFetch::getNumHTTPRequests()
  1863. {
  1864. mNetworkQueueMutex.lock() ;
  1865. S32 size = (S32)mHTTPTextureQueue.size();
  1866. mNetworkQueueMutex.unlock() ;
  1867. return size ;
  1868. }
  1869. U32 LLTextureFetch::getTotalNumHTTPRequests()
  1870. {
  1871. mNetworkQueueMutex.lock() ;
  1872. U32 size = mTotalHTTPRequests ;
  1873. mNetworkQueueMutex.unlock() ;
  1874. return size ;
  1875. }
  1876. // call lockQueue() first!
  1877. LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id)
  1878. {
  1879. LLTextureFetchWorker* res = NULL;
  1880. map_t::iterator iter = mRequestMap.find(id);
  1881. if (iter != mRequestMap.end())
  1882. {
  1883. res = iter->second;
  1884. }
  1885. return res;
  1886. }
  1887. LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
  1888. {
  1889. LLMutexLock lock(&mQueueMutex) ;
  1890. return getWorkerAfterLock(id) ;
  1891. }
  1892. bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
  1893. LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux)
  1894. {
  1895. bool res = false;
  1896. LLTextureFetchWorker* worker = getWorker(id);
  1897. if (worker)
  1898. {
  1899. if (worker->wasAborted())
  1900. {
  1901. res = true;
  1902. }
  1903. else if (!worker->haveWork())
  1904. {
  1905. // Should only happen if we set mDebugPause...
  1906. if (!mDebugPause)
  1907. {
  1908. // llwarns << "Adding work for inactive worker: " << id << llendl;
  1909. worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
  1910. }
  1911. }
  1912. else if (worker->checkWork())
  1913. {
  1914. worker->lockWorkMutex();
  1915. discard_level = worker->mDecodedDiscard;
  1916. raw = worker->mRawImage;
  1917. aux = worker->mAuxImage;
  1918. res = true;
  1919. LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL;
  1920. worker->unlockWorkMutex();
  1921. }
  1922. else
  1923. {
  1924. worker->lockWorkMutex();
  1925. if ((worker->mDecodedDiscard >= 0) &&
  1926. (worker->mDecodedDiscard < discard_level || discard_level < 0) &&
  1927. (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE))
  1928. {
  1929. // Not finished, but data is ready
  1930. discard_level = worker->mDecodedDiscard;
  1931. raw = worker->mRawImage;
  1932. aux = worker->mAuxImage;
  1933. }
  1934. worker->unlockWorkMutex();
  1935. }
  1936. }
  1937. else
  1938. {
  1939. res = true;
  1940. }
  1941. return res;
  1942. }
  1943. bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
  1944. {
  1945. bool res = false;
  1946. LLTextureFetchWorker* worker = getWorker(id);
  1947. if (worker)
  1948. {
  1949. worker->lockWorkMutex();
  1950. worker->setImagePriority(priority);
  1951. worker->unlockWorkMutex();
  1952. res = true;
  1953. }
  1954. return res;
  1955. }
  1956. // Replicates and expands upon the base class's
  1957. // getPending() implementation. getPending() and
  1958. // runCondition() replicate one another's logic to
  1959. // an extent and are sometimes used for the same
  1960. // function (deciding whether or not to sleep/pause
  1961. // a thread). So the implementations need to stay
  1962. // in step, at least until this can be refactored and
  1963. // the redundancy eliminated.
  1964. //
  1965. // May be called from any thread
  1966. //virtual
  1967. S32 LLTextureFetch::getPending()
  1968. {
  1969. S32 res;
  1970. lockData();
  1971. {
  1972. LLMutexLock lock(&mQueueMutex);
  1973. res = mRequestQueue.size();
  1974. res += mCurlPOSTRequestCount;
  1975. res += mCommands.size();
  1976. }
  1977. unlockData();
  1978. return res;
  1979. }
  1980. // virtual
  1981. bool LLTextureFetch::runCondition()
  1982. {
  1983. // Caller is holding the lock on LLThread's condition variable.
  1984. // LLQueuedThread, unlike its base class LLThread, makes this a
  1985. // private method which is unfortunate. I want to use it directly
  1986. // but I'm going to have to re-implement the logic here (or change
  1987. // declarations, which I don't want to do right now).
  1988. //
  1989. // Changes here may need to be reflected in getPending().
  1990. bool have_no_commands(false);
  1991. {
  1992. LLMutexLock lock(&mQueueMutex);
  1993. have_no_commands = mCommands.empty();
  1994. }
  1995. bool have_no_curl_requests(0 == mCurlPOSTRequestCount);
  1996. return ! (have_no_commands
  1997. && have_no_curl_requests
  1998. && (mRequestQueue.empty() && mIdleThread)); // From base class
  1999. }
  2000. //////////////////////////////////////////////////////////////////////////////
  2001. // MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
  2002. void LLTextureFetch::commonUpdate()
  2003. {
  2004. // Run a cross-thread command, if any.
  2005. cmdDoWork();
  2006. // Update Curl on same thread as mCurlGetRequest was constructed
  2007. S32 processed = mCurlGetRequest->process();
  2008. if (processed > 0)
  2009. {
  2010. lldebugs << "processed: " << processed << " messages." << llendl;
  2011. }
  2012. }
  2013. // MAIN THREAD
  2014. //virtual
  2015. S32 LLTextureFetch::update(F32 max_time_ms)
  2016. {
  2017. static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS");
  2018. {
  2019. mNetworkQueueMutex.lock() ;
  2020. mMaxBandwidth = band_width ;
  2021. gTextureList.sTextureBits += mHTTPTextureBits ;
  2022. mHTTPTextureBits = 0 ;
  2023. mNetworkQueueMutex.unlock() ;
  2024. }
  2025. S32 res = LLWorkerThread::update(max_time_ms);
  2026. if (!mDebugPause)
  2027. {
  2028. sendRequestListToSimulators();
  2029. }
  2030. if (!mThreaded)
  2031. {
  2032. commonUpdate();
  2033. }
  2034. return res;
  2035. }
  2036. //called in the MAIN thread after the TextureCacheThread shuts down.
  2037. void LLTextureFetch::shutDownTextureCacheThread()
  2038. {
  2039. if(mTextureCache)
  2040. {
  2041. llassert_always(mTextureCache->isQuitting() || mTextureCache->isStopped()) ;
  2042. mTextureCache = NULL ;
  2043. }
  2044. }
  2045. //called in the MAIN thread after the ImageDecodeThread shuts down.
  2046. void LLTextureFetch::shutDownImageDecodeThread()
  2047. {
  2048. if(mImageDecodeThread)
  2049. {
  2050. llassert_always(mImageDecodeThread->isQuitting() || mImageDecodeThread->isStopped()) ;
  2051. mImageDecodeThread = NULL ;
  2052. }
  2053. }
  2054. // WORKER THREAD
  2055. void LLTextureFetch::startThread()
  2056. {
  2057. // Construct mCurlGetRequest from Worker Thread
  2058. mCurlGetRequest = new LLCurlRequest();
  2059. }
  2060. // WORKER THREAD
  2061. void LLTextureFetch::endThread()
  2062. {
  2063. // Destroy mCurlGetRequest from Worker Thread
  2064. delete mCurlGetRequest;
  2065. mCurlGetRequest = NULL;
  2066. }
  2067. // WORKER THREAD
  2068. void LLTextureFetch::threadedUpdate()
  2069. {
  2070. llassert_always(mCurlGetRequest);
  2071. // Limit update frequency
  2072. const F32 PROCESS_TIME = 0.05f;
  2073. static LLFrameTimer process_timer;
  2074. if (process_timer.getElapsedTimeF32() < PROCESS_TIME)
  2075. {
  2076. return;
  2077. }
  2078. process_timer.reset();
  2079. commonUpdate();
  2080. #if 0
  2081. const F32 INFO_TIME = 1.0f;
  2082. static LLFrameTimer info_timer;
  2083. if (info_timer.getElapsedTimeF32() >= INFO_TIME)
  2084. {
  2085. S32 q = mCurlGetRequest->getQueued();
  2086. if (q > 0)
  2087. {
  2088. llinfos << "Queued gets: " << q << llendl;
  2089. info_timer.reset();
  2090. }
  2091. }
  2092. #endif
  2093. }
  2094. //////////////////////////////////////////////////////////////////////////////
  2095. void LLTextureFetch::sendRequestListToSimulators()
  2096. {
  2097. // All requests
  2098. const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps
  2099. // Sim requests
  2100. const S32 IMAGES_PER_REQUEST = 50;
  2101. const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
  2102. const F32 MIN_REQUEST_TIME = 1.0f;
  2103. const F32 MIN_DELTA_PRIORITY = 1000.f;
  2104. // Periodically, gather the list of textures that need data from the network
  2105. // And send the requests out to the simulators
  2106. static LLFrameTimer timer;
  2107. if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME)
  2108. {
  2109. return;
  2110. }
  2111. timer.reset();
  2112. // Send requests
  2113. typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t;
  2114. typedef std::map< LLHost, request_list_t > work_request_map_t;
  2115. work_request_map_t requests;
  2116. {
  2117. LLMutexLock lock2(&mNetworkQueueMutex);
  2118. for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); )
  2119. {
  2120. queue_t::iterator curiter = iter++;
  2121. LLTextureFetchWorker* req = getWorker(*curiter);
  2122. if (!req)
  2123. {
  2124. mNetworkQueue.erase(curiter);
  2125. continue; // paranoia
  2126. }
  2127. if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) &&
  2128. (req