00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llstl.h"
00035
00036 #include "lltexturefetch.h"
00037
00038 #include "llcurl.h"
00039 #include "llhttpclient.h"
00040 #include "llimage.h"
00041 #include "llimageworker.h"
00042 #include "llworkerthread.h"
00043
00044 #include "llagent.h"
00045 #include "lltexturecache.h"
00046 #include "llviewerimagelist.h"
00047 #include "llviewerimage.h"
00048 #include "llviewerregion.h"
00049 #include "viewer.h"
00050
00052
00053
00054 class LLTextureFetchWorker : public LLWorkerClass
00055 {
00056 friend class LLTextureFetch;
00057
00058 private:
00059 class URLResponder : public LLHTTPClient::Responder
00060 {
00061 public:
00062 URLResponder(LLTextureFetch* fetcher, const LLUUID& id)
00063 : mFetcher(fetcher), mID(id)
00064 {
00065 }
00066 ~URLResponder()
00067 {
00068 }
00069 virtual void error(U32 status, const std::string& reason)
00070 {
00071 mFetcher->lockQueue();
00072 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
00073 if (worker)
00074 {
00075 llinfos << "LLTextureFetchWorker::URLResponder::error " << status << ": " << reason << llendl;
00076 worker->callbackURLReceived(LLSD(), false);
00077 }
00078 mFetcher->unlockQueue();
00079 }
00080 virtual void result(const LLSD& content)
00081 {
00082 mFetcher->lockQueue();
00083 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
00084 if (worker)
00085 {
00086 worker->callbackURLReceived(content, true);
00087 }
00088 mFetcher->unlockQueue();
00089 }
00090 private:
00091 LLTextureFetch* mFetcher;
00092 LLUUID mID;
00093 };
00094
00095 class HTTPGetResponder : public LLCurl::Responder
00096 {
00097 public:
00098 HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id)
00099 : mFetcher(fetcher), mID(id)
00100 {
00101 }
00102 ~HTTPGetResponder()
00103 {
00104 }
00105 virtual void completed(U32 status, const std::stringstream& content)
00106 {
00107 mFetcher->lockQueue();
00108 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
00109 if (worker)
00110 {
00111 const std::string& cstr = content.str();
00112 if (200 <= status && status < 300)
00113 {
00114 if (203 == status)
00115 {
00116 worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), true);
00117 }
00118 else
00119 {
00120 worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), false);
00121 }
00122 }
00123 else
00124 {
00125 llinfos << "LLTextureFetchWorker::HTTPGetResponder::error " << status << ": " << cstr << llendl;
00126 worker->callbackHttpGet(NULL, -1, true);
00127 }
00128 }
00129 mFetcher->unlockQueue();
00130 }
00131 private:
00132 LLTextureFetch* mFetcher;
00133 LLUUID mID;
00134 };
00135
00136 class CacheReadResponder : public LLTextureCache::ReadResponder
00137 {
00138 public:
00139 CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image)
00140 : mFetcher(fetcher), mID(id)
00141 {
00142 setImage(image);
00143 }
00144 virtual void completed(bool success)
00145 {
00146 mFetcher->lockQueue();
00147 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
00148 if (worker)
00149 {
00150 worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal);
00151 }
00152 mFetcher->unlockQueue();
00153 }
00154 private:
00155 LLTextureFetch* mFetcher;
00156 LLUUID mID;
00157 };
00158
00159 class CacheWriteResponder : public LLTextureCache::WriteResponder
00160 {
00161 public:
00162 CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id)
00163 : mFetcher(fetcher), mID(id)
00164 {
00165 }
00166 virtual void completed(bool success)
00167 {
00168 mFetcher->lockQueue();
00169 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
00170 if (worker)
00171 {
00172 worker->callbackCacheWrite(success);
00173 }
00174 mFetcher->unlockQueue();
00175 }
00176 private:
00177 LLTextureFetch* mFetcher;
00178 LLUUID mID;
00179 };
00180
00181 class DecodeResponder : public LLResponder
00182 {
00183 public:
00184 DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker)
00185 : mFetcher(fetcher), mID(id), mWorker(worker)
00186 {
00187 }
00188 virtual void completed(bool success)
00189 {
00190 mFetcher->lockQueue();
00191 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
00192 if (worker)
00193 {
00194 worker->callbackDecoded(success);
00195 }
00196 mFetcher->unlockQueue();
00197 }
00198 private:
00199 LLTextureFetch* mFetcher;
00200 LLUUID mID;
00201 LLTextureFetchWorker* mWorker;
00202 };
00203
00204 struct Compare
00205 {
00206
00207 bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const
00208 {
00209
00210 const F32 lpriority = lhs->mImagePriority;
00211 const F32 rpriority = rhs->mImagePriority;
00212 if (lpriority > rpriority)
00213 return true;
00214 else if (lpriority < rpriority)
00215 return false;
00216 else
00217 return lhs < rhs;
00218 }
00219 };
00220
00221 public:
00222 bool doWork(S32 param);
00223 void finishWork(S32 param, bool completed);
00224 bool deleteOK();
00225
00226 ~LLTextureFetchWorker();
00227 void relese() { --mActiveCount; }
00228
00229 protected:
00230 LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
00231 F32 priority, S32 discard, S32 size);
00232
00233 private:
00234 void startWork(S32 param);
00235 void endWork(S32 param, bool aborted);
00236
00237 void resetFormattedData();
00238
00239 void setImagePriority(F32 priority);
00240 void setDesiredDiscard(S32 discard, S32 size);
00241 bool insertPacket(S32 index, U8* data, S32 size);
00242 void clearPackets();
00243 U32 calcWorkPriority();
00244 void removeFromCache();
00245 bool processSimulatorPackets();
00246 bool decodeImage();
00247 bool writeToCacheComplete();
00248
00249 void lockWorkData() { mWorkMutex.lock(); }
00250 void unlockWorkData() { mWorkMutex.unlock(); }
00251
00252 void callbackURLReceived(const LLSD& data, bool success);
00253 void callbackHttpGet(U8* data, S32 data_size, bool last_block);
00254 void callbackCacheRead(bool success, LLImageFormatted* image,
00255 S32 imagesize, BOOL islocal);
00256 void callbackCacheWrite(bool success);
00257 void callbackDecoded(bool success);
00258
00259 private:
00260 enum e_state
00261 {
00262
00263 INVALID = 0,
00264 INIT,
00265 LOAD_FROM_TEXTURE_CACHE,
00266 CACHE_POST,
00267 LOAD_FROM_NETWORK,
00268 LOAD_FROM_SIMULATOR,
00269 LOAD_FROM_HTTP_GET_URL,
00270 LOAD_FROM_HTTP_GET_DATA,
00271 DECODE_IMAGE,
00272 DECODE_IMAGE_UPDATE,
00273 WRITE_TO_CACHE,
00274 WAIT_ON_WRITE,
00275 DONE
00276 };
00277 enum e_request_state
00278 {
00279 UNSENT = 0,
00280 QUEUED = 1,
00281 SENT_SIM = 2,
00282 SENT_URL = 3,
00283 SENT_HTTP = 4
00284 };
00285 static const char* sStateDescs[];
00286 e_state mState;
00287 LLTextureFetch* mFetcher;
00288 LLImageWorker* mImageWorker;
00289 LLPointer<LLImageFormatted> mFormattedImage;
00290 LLPointer<LLImageRaw> mRawImage;
00291 LLPointer<LLImageRaw> mAuxImage;
00292 LLUUID mID;
00293 LLHost mHost;
00294 U8 mType;
00295 F32 mImagePriority;
00296 U32 mWorkPriority;
00297 F32 mRequestedPriority;
00298 S32 mDesiredDiscard;
00299 S32 mSimRequestedDiscard;
00300 S32 mRequestedDiscard;
00301 S32 mLoadedDiscard;
00302 S32 mDecodedDiscard;
00303 LLFrameTimer mRequestedTimer;
00304 LLFrameTimer mFetchTimer;
00305 LLTextureCache::handle_t mCacheReadHandle;
00306 LLTextureCache::handle_t mCacheWriteHandle;
00307 U8* mBuffer;
00308 S32 mBufferSize;
00309 S32 mRequestedSize;
00310 S32 mDesiredSize;
00311 S32 mFileSize;
00312 S32 mCachedSize;
00313 BOOL mLoaded;
00314 e_request_state mSentRequest;
00315 BOOL mDecoded;
00316 BOOL mWritten;
00317 BOOL mNeedsAux;
00318 BOOL mHaveAllData;
00319 BOOL mInLocalCache;
00320 S32 mRetryAttempt;
00321 std::string mURL;
00322 S32 mActiveCount;
00323
00324
00325 LLMutex mWorkMutex;
00326 struct PacketData
00327 {
00328 PacketData(U8* data, S32 size) { mData = data; mSize = size; }
00329 ~PacketData() { clearData(); }
00330 void clearData() { delete[] mData; mData = NULL; }
00331 U8* mData;
00332 U32 mSize;
00333 };
00334 std::vector<PacketData*> mPackets;
00335 S32 mFirstPacket;
00336 S32 mLastPacket;
00337 U16 mTotalPackets;
00338 U8 mImageCodec;
00339 };
00340
00341
00342 const char* LLTextureFetchWorker::sStateDescs[] = {
00343 "INVALID",
00344 "INIT",
00345 "LOAD_FROM_TEXTURE_CACHE",
00346 "CACHE_POST",
00347 "LOAD_FROM_NETWORK",
00348 "LOAD_FROM_SIMULATOR",
00349 "LOAD_FROM_HTTP_URL",
00350 "LOAD_FROM_HTTP_DATA",
00351 "DECODE_IMAGE",
00352 "DECODE_IMAGE_UPDATE",
00353 "WRITE_TO_CACHE",
00354 "WAIT_ON_WRITE",
00355 "DONE",
00356 };
00357
00358
00359
00360 LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
00361 const LLUUID& id,
00362 const LLHost& host,
00363 F32 priority,
00364 S32 discard,
00365 S32 size)
00366 : LLWorkerClass(fetcher, "TextureFetch"),
00367 mState(INIT),
00368 mFetcher(fetcher),
00369 mImageWorker(NULL),
00370 mID(id),
00371 mHost(host),
00372 mImagePriority(priority),
00373 mWorkPriority(0),
00374 mRequestedPriority(0.f),
00375 mDesiredDiscard(-1),
00376 mSimRequestedDiscard(-1),
00377 mRequestedDiscard(-1),
00378 mLoadedDiscard(-1),
00379 mDecodedDiscard(-1),
00380 mCacheReadHandle(LLTextureCache::nullHandle()),
00381 mCacheWriteHandle(LLTextureCache::nullHandle()),
00382 mBuffer(NULL),
00383 mBufferSize(0),
00384 mRequestedSize(0),
00385 mDesiredSize(FIRST_PACKET_SIZE),
00386 mFileSize(0),
00387 mCachedSize(0),
00388 mLoaded(FALSE),
00389 mSentRequest(UNSENT),
00390 mDecoded(FALSE),
00391 mWritten(FALSE),
00392 mNeedsAux(FALSE),
00393 mHaveAllData(FALSE),
00394 mInLocalCache(FALSE),
00395 mRetryAttempt(0),
00396 mActiveCount(0),
00397 mWorkMutex(fetcher->getWorkerAPRPool()),
00398 mFirstPacket(0),
00399 mLastPacket(-1),
00400 mTotalPackets(0),
00401 mImageCodec(IMG_CODEC_INVALID)
00402 {
00403 calcWorkPriority();
00404 mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
00405
00406 if (!mFetcher->mDebugPause)
00407 {
00408 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
00409 addWork(0, work_priority );
00410 }
00411 setDesiredDiscard(discard, size);
00412 }
00413
00414 LLTextureFetchWorker::~LLTextureFetchWorker()
00415 {
00416
00417
00418
00419
00420 llassert_always(!haveWork());
00421 lockWorkData();
00422 if (mCacheReadHandle != LLTextureCache::nullHandle())
00423 {
00424 mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
00425 }
00426 if (mCacheWriteHandle != LLTextureCache::nullHandle())
00427 {
00428 mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
00429 }
00430 if (mImageWorker)
00431 {
00432 mImageWorker->scheduleDelete();
00433 }
00434 mFormattedImage = NULL;
00435 clearPackets();
00436 unlockWorkData();
00437 }
00438
00439 void LLTextureFetchWorker::clearPackets()
00440 {
00441 for_each(mPackets.begin(), mPackets.end(), DeletePointer());
00442 mPackets.clear();
00443 mTotalPackets = 0;
00444 mLastPacket = -1;
00445 mFirstPacket = 0;
00446 }
00447
00448 U32 LLTextureFetchWorker::calcWorkPriority()
00449 {
00450
00451 F32 priority_scale = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerImage::maxDecodePriority();
00452 mWorkPriority = (U32)(mImagePriority * priority_scale);
00453 return mWorkPriority;
00454 }
00455
00456
00457 void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size)
00458 {
00459 bool prioritize = false;
00460 if (mDesiredDiscard != discard)
00461 {
00462 if (!haveWork())
00463 {
00464 calcWorkPriority();
00465 if (!mFetcher->mDebugPause)
00466 {
00467 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
00468 addWork(0, work_priority);
00469 }
00470 }
00471 else if (mDesiredDiscard < discard)
00472 {
00473 prioritize = true;
00474 }
00475 mDesiredDiscard = discard;
00476 mDesiredSize = size;
00477 }
00478 else if (size > mDesiredSize)
00479 {
00480 mDesiredSize = size;
00481 prioritize = true;
00482 }
00483 if ((prioritize && mState == INIT) || mState == DONE)
00484 {
00485 mState = INIT;
00486 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
00487 setPriority(work_priority);
00488 }
00489 }
00490
00491 void LLTextureFetchWorker::setImagePriority(F32 priority)
00492 {
00493
00494 F32 delta = fabs(priority - mImagePriority);
00495 if (delta > (mImagePriority * .05f) || mState == DONE)
00496 {
00497 mImagePriority = priority;
00498 calcWorkPriority();
00499 U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS);
00500 setPriority(work_priority);
00501 }
00502 }
00503
00504 void LLTextureFetchWorker::resetFormattedData()
00505 {
00506 delete[] mBuffer;
00507 mBuffer = NULL;
00508 mBufferSize = 0;
00509 if (mFormattedImage.notNull())
00510 {
00511 mFormattedImage->deleteData();
00512 }
00513 mHaveAllData = FALSE;
00514 }
00515
00516
00517 void LLTextureFetchWorker::startWork(S32 param)
00518 {
00519 llassert(mImageWorker == NULL);
00520 llassert(mFormattedImage.isNull());
00521 }
00522
00523 #include "llviewerimagelist.h"
00524
00525
00526 bool LLTextureFetchWorker::doWork(S32 param)
00527 {
00528 LLMutexLock lock(&mWorkMutex);
00529
00530 if (mFetcher->mDebugPause)
00531 {
00532 return false;
00533 }
00534 if (mID == mFetcher->mDebugID)
00535 {
00536 mFetcher->mDebugCount++;
00537 }
00538
00539 if (mState != DONE)
00540 {
00541 mFetchTimer.reset();
00542 }
00543
00544 if (mState == INIT)
00545 {
00546 mRequestedDiscard = -1;
00547 mLoadedDiscard = -1;
00548 mDecodedDiscard = -1;
00549 mRequestedSize = 0;
00550 mFileSize = 0;
00551 mCachedSize = 0;
00552 mLoaded = FALSE;
00553 mSentRequest = UNSENT;
00554 mDecoded = FALSE;
00555 mWritten = FALSE;
00556 delete[] mBuffer;
00557 mBuffer = NULL;
00558 mBufferSize = 0;
00559 mHaveAllData = FALSE;
00560 clearPackets();
00561 mCacheReadHandle = LLTextureCache::nullHandle();
00562 mCacheWriteHandle = LLTextureCache::nullHandle();
00563 mURL.clear();
00564 mState = LOAD_FROM_TEXTURE_CACHE;
00565
00566 }
00567
00568 if (mState == LOAD_FROM_TEXTURE_CACHE)
00569 {
00570 if (mCacheReadHandle == LLTextureCache::nullHandle())
00571 {
00572 U32 cache_priority = mWorkPriority;
00573 S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
00574 S32 size = mDesiredSize - offset;
00575 if (size <= 0)
00576 {
00577 mState = CACHE_POST;
00578 return false;
00579 }
00580 mFileSize = 0;
00581 mLoaded = FALSE;
00582 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00583 CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
00584 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
00585 offset, size, responder);
00586 }
00587
00588 if (mLoaded)
00589 {
00590
00591 if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false))
00592 {
00593 mCacheReadHandle = LLTextureCache::nullHandle();
00594 mState = CACHE_POST;
00595
00596 }
00597 else
00598 {
00599 return false;
00600 }
00601 }
00602 else
00603 {
00604 return false;
00605 }
00606 }
00607
00608 if (mState == CACHE_POST)
00609 {
00610 mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
00611
00612 if ((mCachedSize >= mDesiredSize) || mHaveAllData)
00613 {
00614
00615 llassert_always(mFormattedImage->getDataSize() > 0);
00616 mState = DECODE_IMAGE;
00617
00618 }
00619 else
00620 {
00621
00622 mState = LOAD_FROM_NETWORK;
00623
00624 }
00625 }
00626
00627 if (mState == LOAD_FROM_NETWORK)
00628 {
00629 if (mSentRequest == UNSENT)
00630 {
00631 if (mFormattedImage.isNull())
00632 {
00633 mFormattedImage = new LLImageJ2C;
00634 }
00635
00636
00637 S32 data_size = mFormattedImage->getDataSize();
00638 if (data_size > 0)
00639 {
00640
00641 mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
00642 if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
00643 {
00644 llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
00645 removeFromCache();
00646 resetFormattedData();
00647 clearPackets();
00648 }
00649 else
00650 {
00651 mLastPacket = mFirstPacket-1;
00652 mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
00653 }
00654 }
00655 mRequestedSize = mDesiredSize;
00656 mRequestedDiscard = mDesiredDiscard;
00657 mSentRequest = QUEUED;
00658 mFetcher->lockQueue();
00659 mFetcher->addToNetworkQueue(this);
00660 mFetcher->unlockQueue();
00661 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00662 }
00663 return false;
00664 }
00665
00666 if (mState == LOAD_FROM_SIMULATOR)
00667 {
00668 if (processSimulatorPackets())
00669 {
00670 mFetcher->lockQueue();
00671 mFetcher->removeFromNetworkQueue(this);
00672 mFetcher->unlockQueue();
00673 if (!mFormattedImage->getDataSize())
00674 {
00675
00676 llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
00677 return true;
00678 }
00679 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
00680 mState = DECODE_IMAGE;
00681 }
00682 else
00683 {
00684 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00685 }
00686 return false;
00687 }
00688
00689 #if 0
00690 if (mState == LOAD_FROM_HTTP_GET_URL)
00691 {
00692 if (!mSentRequest)
00693 {
00694 mSentRequest = TRUE;
00695 mLoaded = FALSE;
00696 std::string url;
00697 LLViewerRegion* region = gAgent.getRegion();
00698 if (region)
00699 {
00700 url = region->getCapability("RequestTextureDownload");
00701 }
00702 if (!url.empty())
00703 {
00704 LLSD sd;
00705 sd = mID.asString();
00706 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00707 LLHTTPClient::post(url, sd, new URLResponder(mFetcher, mID));
00708 return false;
00709 }
00710 else
00711 {
00712 llwarns << mID << ": HTTP get url failed, requesting from simulator" << llendl;
00713 mSentRequest = FALSE;
00714 mState = LOAD_FROM_SIMULATOR;
00715 return false;
00716 }
00717 }
00718 else
00719 {
00720 if (mLoaded)
00721 {
00722 if (!mURL.empty())
00723 {
00724 mState = LOAD_FROM_HTTP_GET_DATA;
00725 mSentRequest = FALSE;
00726 mLoaded = FALSE;
00727 }
00728 else
00729 {
00730 llwarns << mID << ": HTTP get url is empty, requesting from simulator" << llendl;
00731 mSentRequest = FALSE;
00732 mState = LOAD_FROM_SIMULATOR;
00733 return false;
00734 }
00735 }
00736 }
00737
00738 }
00739
00740 if (mState == LOAD_FROM_HTTP_GET_DATA)
00741 {
00742 if (!mSentRequest)
00743 {
00744 mSentRequest = TRUE;
00745 S32 cur_size = mFormattedImage->getDataSize();
00746 mRequestedSize = mDesiredSize;
00747 mRequestedDiscard = mDesiredDiscard;
00748 #if 1 // *TODO: LLCurl::getByteRange is broken (ignores range)
00749 cur_size = 0;
00750 mFormattedImage->deleteData();
00751 #endif
00752 mRequestedSize -= cur_size;
00753
00754 S32 offset = cur_size;
00755 mBufferSize = cur_size;
00756 std::string url;
00757 if (mURL.empty())
00758 {
00759
00760 std::stringstream urlstr;
00761 urlstr << "http://asset.agni/" << mID.asString() << ".texture";
00762 url = urlstr.str();
00763 }
00764 else
00765 {
00766 url = mURL;
00767 }
00768 mLoaded = FALSE;
00769
00770 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00771 LLCurl::getByteRange(url, offset, mRequestedSize,
00772 new HTTPGetResponder(mFetcher, mID));
00773 return false;
00774 }
00775
00776 if (mLoaded)
00777 {
00778 S32 cur_size = mFormattedImage->getDataSize();
00779 if (mRequestedSize < 0)
00780 {
00781 llwarns << "http get failed for: " << mID << llendl;
00782 if (cur_size == 0)
00783 {
00784 resetFormattedData();
00785 return true;
00786 }
00787 else
00788 {
00789 mState = DECODE_IMAGE;
00790 return false;
00791 }
00792 }
00793 llassert_always(mBufferSize == cur_size + mRequestedSize);
00794 if (mHaveAllData)
00795 {
00796 mFileSize = mBufferSize;
00797 }
00798 U8* buffer = new U8[mBufferSize];
00799 if (cur_size > 0)
00800 {
00801 memcpy(buffer, mFormattedImage->getData(), cur_size);
00802 }
00803 memcpy(buffer + cur_size, mBuffer, mRequestedSize);
00804
00805 mFormattedImage->setData(buffer, mBufferSize);
00806
00807 delete[] mBuffer;
00808 mBuffer = NULL;
00809 mBufferSize = 0;
00810 mLoadedDiscard = mRequestedDiscard;
00811 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
00812 mState = DECODE_IMAGE;
00813 return false;
00814 }
00815
00816
00817 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00818 return false;
00819 }
00820 #endif
00821
00822 if (mState == DECODE_IMAGE)
00823 {
00824 llassert_always(mFormattedImage->getDataSize() > 0);
00825 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00826 mRawImage = NULL;
00827 mAuxImage = NULL;
00828 llassert_always(mImageWorker == NULL);
00829 llassert_always(mFormattedImage.notNull());
00830 S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
00831 U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
00832 mDecoded = FALSE;
00833 mState = DECODE_IMAGE_UPDATE;
00834 mImageWorker = new LLImageWorker(mFormattedImage, image_priority, discard, new DecodeResponder(mFetcher, mID, this));
00835
00836 }
00837
00838 if (mState == DECODE_IMAGE_UPDATE)
00839 {
00840 if (decodeImage())
00841 {
00842 if (mDecodedDiscard < 0)
00843 {
00844 if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)
00845 {
00846
00847 llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl;
00848 mFormattedImage = NULL;
00849 ++mRetryAttempt;
00850 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
00851 mState = INIT;
00852 return false;
00853 }
00854 else
00855 {
00856 llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl;
00857 mState = DONE;
00858 }
00859 }
00860 else
00861 {
00862 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
00863 mState = WRITE_TO_CACHE;
00864 }
00865
00866 }
00867 else
00868 {
00869 return false;
00870 }
00871 }
00872
00873 if (mState == WRITE_TO_CACHE)
00874 {
00875 if (mInLocalCache || !mFileSize || mSentRequest == UNSENT)
00876 {
00877
00878 mState = DONE;
00879 return false;
00880 }
00881 S32 datasize = mFormattedImage->getDataSize();
00882 llassert_always(datasize);
00883 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00884 U32 cache_priority = mWorkPriority;
00885 mWritten = FALSE;
00886 mState = WAIT_ON_WRITE;
00887 CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID);
00888 mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
00889 mFormattedImage->getData(), datasize,
00890 mFileSize, responder);
00891
00892 }
00893
00894 if (mState == WAIT_ON_WRITE)
00895 {
00896 if (writeToCacheComplete())
00897 {
00898 mState = DONE;
00899
00900 }
00901 else
00902 {
00903 if (mDesiredDiscard < mDecodedDiscard)
00904 {
00905
00906
00907
00908 mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle);
00909 }
00910 return false;
00911 }
00912 }
00913
00914 if (mState == DONE)
00915 {
00916 if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard)
00917 {
00918
00919 mState = INIT;
00920 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
00921 return false;
00922 }
00923 else
00924 {
00925 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00926 return true;
00927 }
00928 }
00929
00930 return false;
00931 }
00932
00933
00934 void LLTextureFetchWorker::endWork(S32 param, bool aborted)
00935 {
00936 if (mImageWorker)
00937 {
00938 mImageWorker->scheduleDelete();
00939 mImageWorker = NULL;
00940 }
00941 mFormattedImage = NULL;
00942 }
00943
00945
00946
00947 void LLTextureFetchWorker::finishWork(S32 param, bool completed)
00948 {
00949
00950 if (mCacheReadHandle != LLTextureCache::nullHandle())
00951 {
00952 mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
00953 mCacheReadHandle = LLTextureCache::nullHandle();
00954 }
00955 if (mCacheWriteHandle != LLTextureCache::nullHandle())
00956 {
00957 mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
00958 mCacheWriteHandle = LLTextureCache::nullHandle();
00959 }
00960 }
00961
00962
00963 bool LLTextureFetchWorker::deleteOK()
00964 {
00965 bool delete_ok = true;
00966
00967 if (mCacheReadHandle != LLTextureCache::nullHandle())
00968 {
00969 if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true))
00970 {
00971 mCacheReadHandle = LLTextureCache::nullHandle();
00972 }
00973 else
00974 {
00975 delete_ok = false;
00976 }
00977 }
00978 if (mCacheWriteHandle != LLTextureCache::nullHandle())
00979 {
00980 if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
00981 {
00982 mCacheWriteHandle = LLTextureCache::nullHandle();
00983 }
00984 else
00985 {
00986 delete_ok = false;
00987 }
00988 }
00989
00990 if ((haveWork() &&
00991
00992 ((mState >= LOAD_FROM_HTTP_GET_URL && mState <= LOAD_FROM_HTTP_GET_DATA) ||
00993 (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
00994 {
00995 delete_ok = false;
00996 }
00997
00998 return delete_ok;
00999 }
01000
01001
01002 void LLTextureFetchWorker::removeFromCache()
01003 {
01004 if (!mInLocalCache)
01005 {
01006 mFetcher->mTextureCache->removeFromCache(mID);
01007 }
01008 }
01009
01010
01012
01013 bool LLTextureFetchWorker::processSimulatorPackets()
01014 {
01015 if (mLastPacket >= mFirstPacket)
01016 {
01017 S32 buffer_size = mFormattedImage->getDataSize();
01018 for (S32 i = mFirstPacket; i<=mLastPacket; i++)
01019 {
01020 buffer_size += mPackets[i]->mSize;
01021 }
01022 bool have_all_data = mLastPacket >= mTotalPackets-1;
01023 llassert_always(mRequestedSize > 0);
01024 if (buffer_size >= mRequestedSize || have_all_data)
01025 {
01027 if (have_all_data)
01028 {
01029 mHaveAllData = TRUE;
01030 }
01031 S32 cur_size = mFormattedImage->getDataSize();
01032 if (buffer_size > cur_size)
01033 {
01035 U8* buffer = new U8[buffer_size];
01036 S32 offset = 0;
01037 if (cur_size > 0 && mFirstPacket > 0)
01038 {
01039 memcpy(buffer, mFormattedImage->getData(), cur_size);
01040 offset = cur_size;
01041 }
01042 for (S32 i=mFirstPacket; i<=mLastPacket; i++)
01043 {
01044 memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize);
01045 offset += mPackets[i]->mSize;
01046 }
01047
01048 mFormattedImage->setData(buffer, buffer_size);
01049 }
01050 mLoadedDiscard = mRequestedDiscard;
01051 return true;
01052 }
01053 }
01054 return false;
01055 }
01056
01058
01059 void LLTextureFetchWorker::callbackURLReceived(const LLSD& data, bool success)
01060 {
01061 #if 0
01062 LLMutexLock lock(&mWorkMutex);
01063 if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_URL)
01064 {
01065 llwarns << "callbackURLReceived for unrequested fetch worker, req="
01066 << mSentRequest << " state= " << mState << llendl;
01067 return;
01068 }
01069 if (success)
01070 {
01071 mURL = data.asString();
01072 }
01073 mLoaded = TRUE;
01074 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
01075 #endif
01076 }
01077
01079
01080 void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_block)
01081 {
01082 #if 0
01083 LLMutexLock lock(&mWorkMutex);
01084 if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_DATA)
01085 {
01086 llwarns << "callbackHttpGet for unrequested fetch worker, req="
01087 << mSentRequest << " state= " << mState << llendl;
01088 return;
01089 }
01090
01091 if (mLoaded)
01092 {
01093 llwarns << "Duplicate callback for " << mID.asString() << llendl;
01094 return;
01095 }
01096 if (data_size >= 0)
01097 {
01098 if (data_size > 0)
01099 {
01100 mBuffer = new U8[data_size];
01101
01102 memcpy(mBuffer, data, data_size);
01103 mBufferSize += data_size;
01104 if (data_size < mRequestedSize || last_block == true)
01105 {
01106 mHaveAllData = TRUE;
01107 }
01108 else if (data_size > mRequestedSize)
01109 {
01110
01111 llinfos << "HUH?" << llendl;
01112 mHaveAllData = TRUE;
01113 mFormattedImage->deleteData();
01114 mBufferSize = data_size;
01115 }
01116 }
01117 else
01118 {
01119
01120
01121 mHaveAllData = TRUE;
01122 }
01123 mRequestedSize = data_size;
01124 }
01125 else
01126 {
01127 mRequestedSize = -1;
01128 }
01129 mLoaded = TRUE;
01130 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
01131 #endif
01132 }
01133
01135
01136 void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image,
01137 S32 imagesize, BOOL islocal)
01138 {
01139 LLMutexLock lock(&mWorkMutex);
01140 if (mState != LOAD_FROM_TEXTURE_CACHE)
01141 {
01142 llwarns << "Read callback for " << mID << " with state = " << mState << llendl;
01143 return;
01144 }
01145 if (success)
01146 {
01147 llassert_always(imagesize > 0);
01148 mFileSize = imagesize;
01149 mFormattedImage = image;
01150 mImageCodec = image->getCodec();
01151 mInLocalCache = islocal;
01152 if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize)
01153 {
01154 mHaveAllData = TRUE;
01155 }
01156 }
01157 mLoaded = TRUE;
01158 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
01159 }
01160
01161 void LLTextureFetchWorker::callbackCacheWrite(bool success)
01162 {
01163 LLMutexLock lock(&mWorkMutex);
01164 if (mState != WAIT_ON_WRITE)
01165 {
01166 llwarns << "Write callback for " << mID << " with state = " << mState << llendl;
01167 return;
01168 }
01169 mWritten = TRUE;
01170 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
01171 }
01172
01174
01175 void LLTextureFetchWorker::callbackDecoded(bool success)
01176 {
01177 if (mState != DECODE_IMAGE_UPDATE)
01178 {
01179 llwarns << "Decode callback for " << mID << " with state = " << mState << llendl;
01180 return;
01181 }
01182
01183 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
01184 }
01185
01187
01188 bool LLTextureFetchWorker::decodeImage()
01189 {
01190 llassert_always(mImageWorker);
01191 bool res = true;
01192 if (mRawImage.isNull())
01193 {
01194 res = false;
01195 if (mImageWorker->requestDecodedData(mRawImage, -1))
01196 {
01197 res = true;
01198
01199 }
01200 }
01201 if (res &&
01202 (mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
01203 (mNeedsAux && mAuxImage.isNull()))
01204 {
01205 res = false;
01206 if (mImageWorker->requestDecodedAuxData(mAuxImage, 4, -1))
01207 {
01208 res = true;
01209
01210 }
01211 }
01212 if (res)
01213 {
01214 if ((mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
01215 (!mNeedsAux || (mAuxImage.notNull() && mAuxImage->getDataSize() > 0)))
01216 {
01217 mDecodedDiscard = mFormattedImage->getDiscardLevel();
01218
01219 }
01220 else
01221 {
01222 llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
01223 removeFromCache();
01224 }
01225 mImageWorker->scheduleDelete();
01226 mImageWorker = NULL;
01227 }
01228 return res;
01229 }
01230
01232
01233 bool LLTextureFetchWorker::writeToCacheComplete()
01234 {
01235
01236 if (mCacheWriteHandle != LLTextureCache::nullHandle())
01237 {
01238 if (!mWritten)
01239 {
01240 return false;
01241 }
01242 if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
01243 {
01244 mCacheWriteHandle = LLTextureCache::nullHandle();
01245 }
01246 else
01247 {
01248 return false;
01249 }
01250 }
01251 return true;
01252 }
01253
01254
01257
01258
01259 LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded)
01260 : LLWorkerThread("TextureFetch", threaded),
01261 mDebugCount(0),
01262 mDebugPause(FALSE),
01263 mPacketCount(0),
01264 mBadPacketCount(0),
01265 mQueueMutex(getAPRPool()),
01266 mTextureCache(cache)
01267 {
01268 }
01269
01270 LLTextureFetch::~LLTextureFetch()
01271 {
01272
01273 }
01274
01275 bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 priority,
01276 S32 w, S32 h, S32 c, S32 discard, bool needs_aux)
01277 {
01278 if (mDebugPause)
01279 {
01280 return false;
01281 }
01282
01283 LLTextureFetchWorker* worker = NULL;
01284 LLMutexLock lock(&mQueueMutex);
01285 map_t::iterator iter = mRequestMap.find(id);
01286 if (iter != mRequestMap.end())
01287 {
01288 worker = iter->second;
01289 if (worker->mHost != host)
01290 {
01291 llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: "
01292 << host << " != " << worker->mHost << llendl;
01293 removeRequest(worker, true);
01294 worker = NULL;
01295 return false;
01296 }
01297 }
01298
01299
01300 S32 desired_size;
01301 if (w*h*c > 0)
01302 {
01303 desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, discard);
01304 }
01305 else
01306 {
01307 desired_size = FIRST_PACKET_SIZE;
01308 discard = MAX_DISCARD_LEVEL;
01309 }
01310 if (worker)
01311 {
01312 if (worker->wasAborted())
01313 {
01314 return false;
01315 }
01316 worker->lockWorkData();
01317 worker->setImagePriority(priority);
01318 worker->setDesiredDiscard(discard, desired_size);
01319 worker->unlockWorkData();
01320 if (!worker->haveWork())
01321 {
01322 worker->mState = LLTextureFetchWorker::INIT;
01323 worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
01324 }
01325 }
01326 else
01327 {
01328 worker = new LLTextureFetchWorker(this, id, host, priority, discard, desired_size);
01329 mRequestMap[id] = worker;
01330 }
01331 worker->mActiveCount++;
01332 worker->mNeedsAux = needs_aux;
01333
01334 return true;
01335 }
01336
01337 void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
01338 {
01339 LLMutexLock lock(&mQueueMutex);
01340 LLTextureFetchWorker* worker = getWorker(id);
01341 if (worker)
01342 {
01343 removeRequest(worker, cancel);
01344 }
01345 }
01346
01347
01348
01349
01350 void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
01351 {
01352 if (mRequestMap.find(worker->mID) != mRequestMap.end())
01353 {
01354
01355
01356 mNetworkQueue.insert(worker->mID);
01357 }
01358 for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
01359 iter1 != mCancelQueue.end(); ++iter1)
01360 {
01361 iter1->second.erase(worker->mID);
01362 }
01363 }
01364
01365
01366 void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker)
01367 {
01368 mNetworkQueue.erase(worker->mID);
01369 }
01370
01371
01372 void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
01373 {
01374 mRequestMap.erase(worker->mID);
01375 size_t erased = mNetworkQueue.erase(worker->mID);
01376 if (cancel && erased > 0)
01377 {
01378 mCancelQueue[worker->mHost].insert(worker->mID);
01379 }
01380 worker->scheduleDelete();
01381 }
01382
01383
01384 LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
01385 {
01386 LLTextureFetchWorker* res = NULL;
01387 map_t::iterator iter = mRequestMap.find(id);
01388 if (iter != mRequestMap.end())
01389 {
01390 res = iter->second;
01391 }
01392 return res;
01393 }
01394
01395
01396 bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
01397 LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux)
01398 {
01399 bool res = false;
01400 LLMutexLock lock(&mQueueMutex);
01401 LLTextureFetchWorker* worker = getWorker(id);
01402 if (worker)
01403 {
01404 if (worker->wasAborted())
01405 {
01406 res = true;
01407 }
01408 else if (!worker->haveWork())
01409 {
01410
01411 if (!mDebugPause)
01412 {
01413
01414 worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
01415 }
01416 }
01417 else if (worker->checkWork())
01418 {
01419 discard_level = worker->mDecodedDiscard;
01420 raw = worker->mRawImage; worker->mRawImage = NULL;
01421 aux = worker->mAuxImage; worker->mAuxImage = NULL;
01422 res = true;
01423 }
01424 else
01425 {
01426 worker->lockWorkData();
01427 if ((worker->mDecodedDiscard >= 0) &&
01428 (worker->mDecodedDiscard < discard_level || discard_level < 0) &&
01429 (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE))
01430 {
01431
01432 discard_level = worker->mDecodedDiscard;
01433 if (worker->mRawImage) raw = worker->mRawImage;
01434 if (worker->mAuxImage) aux = worker->mAuxImage;
01435 }
01436 worker->unlockWorkData();
01437 }
01438 }
01439 else
01440 {
01441 res = true;
01442 }
01443 return res;
01444 }
01445
01446 bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
01447 {
01448 bool res = false;
01449 LLMutexLock lock(&mQueueMutex);
01450 LLTextureFetchWorker* worker = getWorker(id);
01451 if (worker)
01452 {
01453 worker->lockWorkData();
01454 worker->setImagePriority(priority);
01455 worker->unlockWorkData();
01456 res = true;
01457 }
01458 return res;
01459 }
01460
01462
01463
01464 S32 LLTextureFetch::update(U32 max_time_ms)
01465 {
01466 S32 res;
01467 res = LLWorkerThread::update(max_time_ms);
01468
01469 const F32 REQUEST_TIME = 1.f;
01470
01471
01472
01473 if (mNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME)
01474 {
01475 mNetworkTimer.reset();
01476 sendRequestListToSimulators();
01477 }
01478
01479 return res;
01480 }
01481
01483
01484 void LLTextureFetch::sendRequestListToSimulators()
01485 {
01486 const S32 IMAGES_PER_REQUEST = 50;
01487 const F32 LAZY_FLUSH_TIMEOUT = 15.f;
01488 const F32 MIN_REQUEST_TIME = 1.0f;
01489 const F32 MIN_DELTA_PRIORITY = 1000.f;
01490
01491 LLMutexLock lock(&mQueueMutex);
01492
01493
01494 typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t;
01495 typedef std::map< LLHost, request_list_t > work_request_map_t;
01496 work_request_map_t requests;
01497 for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); )
01498 {
01499 queue_t::iterator curiter = iter++;
01500 LLTextureFetchWorker* req = getWorker(*curiter);
01501 if (!req)
01502 {
01503 mNetworkQueue.erase(curiter);
01504 continue;
01505 }
01506 if (req->mID == mDebugID)
01507 {
01508 mDebugCount++;
01509 }
01510 if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1)
01511 {
01512
01513
01514 continue;
01515 }
01516 F32 elapsed = req->mRequestedTimer.getElapsedTimeF32();
01517 F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
01518 if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
01519 (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
01520 (elapsed >= LAZY_FLUSH_TIMEOUT))
01521 {
01522 requests[req->mHost].insert(req);
01523 }
01524 }
01525
01526 std::string http_url;
01527 #if 0
01528 if (gSavedSettings.getBOOL("ImagePipelineUseHTTP"))
01529 {
01530 LLViewerRegion* region = gAgent.getRegion();
01531 if (region)
01532 {
01533 http_url = region->getCapability("RequestTextureDownload");
01534 }
01535 }
01536 #endif
01537
01538 for (work_request_map_t::iterator iter1 = requests.begin();
01539 iter1 != requests.end(); ++iter1)
01540 {
01541 bool use_http = http_url.empty() ? false : true;
01542 LLHost host = iter1->first;
01543
01544 if (host == LLHost::invalid)
01545 {
01546 host = gAgent.getRegionHost();
01547 }
01548 else
01549 {
01550 use_http = false;
01551 }
01552
01553 if (use_http)
01554 {
01555 }
01556 else
01557 {
01558 S32 request_count = 0;
01559 for (request_list_t::iterator iter2 = iter1->second.begin();
01560 iter2 != iter1->second.end(); ++iter2)
01561 {
01562 LLTextureFetchWorker* req = *iter2;
01563 req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
01564 if (0 == request_count)
01565 {
01566 gMessageSystem->newMessageFast(_PREHASH_RequestImage);
01567 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
01568 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01569 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01570 }
01571 S32 packet = req->mLastPacket + 1;
01572 gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
01573 gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID);
01574 gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mSimRequestedDiscard);
01575 gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority);
01576 gMessageSystem->addU32Fast(_PREHASH_Packet, packet);
01577 gMessageSystem->addU8Fast(_PREHASH_Type, req->mType);
01578
01579
01580
01581 req->lockWorkData();
01582 req->mSimRequestedDiscard = req->mDesiredDiscard;
01583 req->mRequestedPriority = req->mImagePriority;
01584 req->mRequestedTimer.reset();
01585 req->unlockWorkData();
01586 request_count++;
01587 if (request_count >= IMAGES_PER_REQUEST)
01588 {
01589
01590 gMessageSystem->sendSemiReliable(host, NULL, NULL);
01591 request_count = 0;
01592 }
01593 }
01594 if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
01595 {
01596
01597 gMessageSystem->sendSemiReliable(host, NULL, NULL);
01598 request_count = 0;
01599 }
01600 }
01601 }
01602
01603
01604 if (!mCancelQueue.empty())
01605 {
01606 for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
01607 iter1 != mCancelQueue.end(); ++iter1)
01608 {
01609 LLHost host = iter1->first;
01610 if (host == LLHost::invalid)
01611 {
01612 host = gAgent.getRegionHost();
01613 }
01614 S32 request_count = 0;
01615 for (queue_t::iterator iter2 = iter1->second.begin();
01616 iter2 != iter1->second.end(); ++iter2)
01617 {
01618 if (0 == request_count)
01619 {
01620 gMessageSystem->newMessageFast(_PREHASH_RequestImage);
01621 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
01622 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01623 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01624 }
01625 gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
01626 gMessageSystem->addUUIDFast(_PREHASH_Image, *iter2);
01627 gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, -1);
01628 gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0);
01629 gMessageSystem->addU32Fast(_PREHASH_Packet, 0);
01630 gMessageSystem->addU8Fast(_PREHASH_Type, 0);
01631
01632
01633 request_count++;
01634 if (request_count >= IMAGES_PER_REQUEST)
01635 {
01636 gMessageSystem->sendSemiReliable(host, NULL, NULL);
01637 request_count = 0;
01638 }
01639 }
01640 if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
01641 {
01642 gMessageSystem->sendSemiReliable(host, NULL, NULL);
01643 }
01644 }
01645 mCancelQueue.clear();
01646 }
01647 }
01648
01650
01651 bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)
01652 {
01653 mRequestedTimer.reset();
01654 if (index >= mTotalPackets)
01655 {
01656
01657 return false;
01658 }
01659 if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE)
01660 {
01661
01662 return false;
01663 }
01664
01665 if (index >= (S32)mPackets.size())
01666 {
01667 mPackets.resize(index+1, (PacketData*)NULL);
01668 }
01669 else if (mPackets[index] != NULL)
01670 {
01671
01672 return false;
01673 }
01674
01675 mPackets[index] = new PacketData(data, size);
01676 while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL)
01677 {
01678 ++mLastPacket;
01679 }
01680 return true;
01681 }
01682
01683 bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes,
01684 U16 data_size, U8* data)
01685 {
01686 LLMutexLock lock(&mQueueMutex);
01687 LLTextureFetchWorker* worker = getWorker(id);
01688 bool res = true;
01689
01690 ++mPacketCount;
01691
01692 if (!worker)
01693 {
01694
01695 res = false;
01696 }
01697 else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
01698 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
01699 {
01700
01701
01702
01703 res = false;
01704 }
01705 else if (worker->mLastPacket != -1)
01706 {
01707
01708
01709 res = false;
01710 }
01711 else if (!data_size)
01712 {
01713 llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl;
01714 res = false;
01715 }
01716 if (!res)
01717 {
01718 ++mBadPacketCount;
01719 mCancelQueue[host].insert(id);
01720 return false;
01721 }
01722
01723 worker->lockWorkData();
01724
01725
01726 worker->mImageCodec = codec;
01727 worker->mTotalPackets = packets;
01728 worker->mFileSize = (S32)totalbytes;
01729 llassert_always(totalbytes > 0);
01730 llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
01731 res = worker->insertPacket(0, data, data_size);
01732 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
01733 worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
01734 worker->unlockWorkData();
01735 return res;
01736 }
01737
01738 bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data)
01739 {
01740 LLMutexLock lock(&mQueueMutex);
01741 LLTextureFetchWorker* worker = getWorker(id);
01742 bool res = true;
01743
01744 ++mPacketCount;
01745
01746 if (!worker)
01747 {
01748
01749 res = false;
01750 }
01751 else if (worker->mLastPacket == -1)
01752 {
01753
01754 res = false;
01755 }
01756 else if (!data_size)
01757 {
01758 llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl;
01759 res = false;
01760 }
01761 if (!res)
01762 {
01763 ++mBadPacketCount;
01764 mCancelQueue[host].insert(id);
01765 return false;
01766 }
01767
01768 worker->lockWorkData();
01769
01770 res = worker->insertPacket(packet_num, data, data_size);
01771
01772 if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) ||
01773 (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK))
01774 {
01775 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
01776 worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
01777 }
01778 else
01779 {
01780
01781
01782 removeFromNetworkQueue(worker);
01783 mCancelQueue[host].insert(id);
01784 }
01785
01786 worker->unlockWorkData();
01787
01788 return res;
01789 }
01790
01792
01793 S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p,
01794 U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p)
01795 {
01796 S32 state = LLTextureFetchWorker::INVALID;
01797 F32 data_progress = 0.0f;
01798 F32 requested_priority = 0.0f;
01799 F32 fetch_dtime = 999999.f;
01800 F32 request_dtime = 999999.f;
01801 U32 fetch_priority = 0;
01802
01803 LLMutexLock lock(&mQueueMutex);
01804 LLTextureFetchWorker* worker = getWorker(id);
01805 if (worker && worker->haveWork())
01806 {
01807 worker->lockWorkData();
01808 state = worker->mState;
01809 fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
01810 request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
01811 if (worker->mFileSize > 0)
01812 {
01813 if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
01814 {
01815 S32 data_size = FIRST_PACKET_SIZE + (worker->mLastPacket-1) * MAX_IMG_PACKET_SIZE;
01816 data_size = llmax(data_size, 0);
01817 data_progress = (F32)data_size / (F32)worker->mFileSize;
01818 }
01819 else if (worker->mFormattedImage.notNull())
01820 {
01821 data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
01822 }
01823 }
01824 if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA)
01825 {
01826 requested_priority = worker->mRequestedPriority;
01827 }
01828 else
01829 {
01830 requested_priority = worker->mImagePriority;
01831 }
01832 fetch_priority = worker->getPriority();
01833 worker->unlockWorkData();
01834 }
01835 data_progress_p = data_progress;
01836 requested_priority_p = requested_priority;
01837 fetch_priority_p = fetch_priority;
01838 fetch_dtime_p = fetch_dtime;
01839 request_dtime_p = request_dtime;
01840 return state;
01841 }
01842
01843 void LLTextureFetch::dump()
01844 {
01845 llinfos << "LLTextureFetch REQUESTS:" << llendl;
01846 for (request_queue_t::iterator iter = mRequestQueue.begin();
01847 iter != mRequestQueue.end(); ++iter)
01848 {
01849 LLQueuedThread::QueuedRequest* qreq = *iter;
01850 LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq;
01851 LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass();
01852 llinfos << " ID: " << worker->mID
01853 << " PRI: " << llformat("0x%08x",wreq->getPriority())
01854 << " STATE: " << worker->sStateDescs[worker->mState]
01855 << llendl;
01856 }
01857 }
01858
01859