lltexturefetch.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:60k
源码类别:

游戏引擎

开发平台:

C++ Builder

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