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