lltexturefetch.cpp

Go to the documentation of this file.
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 //static
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) // partial information (i.e. last block)
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; // debug only (may get deleted from under us, use mFetcher/mID)
00203         };
00204 
00205         struct Compare
00206         {
00207                 // lhs < rhs
00208                 bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const
00209                 {
00210                         // greater priority is "less"
00211                         const F32 lpriority = lhs->mImagePriority;
00212                         const F32 rpriority = rhs->mImagePriority;
00213                         if (lpriority > rpriority) // higher priority
00214                                 return true;
00215                         else if (lpriority < rpriority)
00216                                 return false;
00217                         else
00218                                 return lhs < rhs;
00219                 }
00220         };
00221         
00222 public:
00223         /*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
00224         /*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
00225         /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
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         /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
00236         /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
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 // mState
00263         {
00264                 // NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
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 // mSentRequest
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         // Work Data
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         /*virtual*/ LLString getName() { return mFileName; }
00356 
00357 
00358 private:
00359         LLString mFileName;
00360 };
00361 
00362 
00363 //static
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 // called from MAIN THREAD
00381 
00382 LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
00383                                                                                    const LLUUID& id,    // Image UUID
00384                                                                                    const LLHost& host,  // Simulator host
00385                                                                                    F32 priority,                // Priority
00386                                                                                    S32 discard,                 // Desired discard
00387                                                                                    S32 size)                    // Desired 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 //      llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
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 //      llinfos << "Destroy: " << mID
00439 //                      << " Decoded=" << mDecodedDiscard
00440 //                      << " Requested=" << mRequestedDiscard
00441 //                      << " Desired=" << mDesiredDiscard << llendl;
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 //      llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerImage::maxDecodePriority());
00473         F32 priority_scale = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerImage::maxDecodePriority();
00474         mWorkPriority = (U32)(mImagePriority * priority_scale);
00475         return mWorkPriority;
00476 }
00477 
00478 // mWorkMutex is locked
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 //      llassert_always(priority >= 0 && priority <= LLViewerImage::maxDecodePriority());
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 // Called from MAIN thread
00539 void LLTextureFetchWorker::startWork(S32 param)
00540 {
00541         llassert(mImageWorker == NULL);
00542         llassert(mFormattedImage.isNull());
00543 }
00544 
00545 #include "llviewerimagelist.h" // debug
00546 
00547 // Called from LLWorkerThread::processRequest()
00548 bool LLTextureFetchWorker::doWork(S32 param)
00549 {
00550         LLMutexLock lock(&mWorkMutex);
00551 
00552         if (mFetcher->mDebugPause)
00553         {
00554                 return false; // debug: don't do any work
00555         }
00556         if (mID == mFetcher->mDebugID)
00557         {
00558                 mFetcher->mDebugCount++; // for setting breakpoints
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(); // TODO: Shouldn't be necessary
00583                 mCacheReadHandle = LLTextureCache::nullHandle();
00584                 mCacheWriteHandle = LLTextureCache::nullHandle();
00585                 mURL.clear();
00586                 mState = LOAD_FROM_TEXTURE_CACHE;
00587                 // fall through
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); // Set priority first since Responder may change it
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                                 // read file from local disk
00615                                 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(getName(), mID, cache_priority,
00616                                                                                                                                                   offset, size, responder);
00617                         }
00618                 }
00619 
00620                 if (mLoaded)
00621                 {
00622                         // Make sure request is complete. *TODO: make this auto-complete
00623                         if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false))
00624                         {
00625                                 mCacheReadHandle = LLTextureCache::nullHandle();
00626                                 mState = CACHE_POST;
00627                                 // fall through
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                 // Successfully loaded
00645                 if ((mCachedSize >= mDesiredSize) || mHaveAllData)
00646                 {
00647                         // we have enough data, decode it
00648                         llassert_always(mFormattedImage->getDataSize() > 0);
00649                         mState = DECODE_IMAGE;
00650                         // fall through
00651                 }
00652                 else
00653                 {
00654                         if (!getName().empty())
00655                         {
00656                                 // failed to load local file, we're done.
00657                                 return true;
00658                         }
00659                         // need more data
00660                         mState = LOAD_FROM_NETWORK;
00661                         // fall through
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                         // Add this to the network queue and sit here.
00674                         // LLTextureFetch::update() will send off a request which will change our state
00675                         S32 data_size = mFormattedImage->getDataSize();
00676                         if (data_size > 0)
00677                         {
00678                                 // Only used for simulator requests
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                                 // processSimulatorPackets() failed
00714                                 llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
00715                                 return true; // failed
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; // reset
00764                                         mLoaded = FALSE; // reset
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                 // fall through
00776         }
00777         
00778         if (mState == LOAD_FROM_HTTP_GET_DATA)
00779         {
00780                 if (!mSentRequest)
00781                 {
00782                         mSentRequest = TRUE;
00783                         S32 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
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                         //                        F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1
00792                         S32 offset = cur_size;
00793                         mBufferSize = cur_size; // This will get modified by callbackHttpGet()
00794                         std::string url;
00795                         if (mURL.empty())
00796                         {
00797                                 //url = "http://asset.agni/0000002f-38ae-0e17-8e72-712e58964e9c.texture";
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 //                      llinfos << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize << llendl;
00808                         setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
00809                         LLCurl::getByteRange(url, offset, mRequestedSize,
00810                                                                  new HTTPGetResponder(mFetcher, mID)); // *TODO: use mWorkPriority
00811                         return false; // not done
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; // failed
00824                                 }
00825                                 else
00826                                 {
00827                                         mState = DECODE_IMAGE;
00828                                         return false; // use what we have
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); // append
00842                         // NOTE: setData releases current data and owns new data (buffer)
00843                         mFormattedImage->setData(buffer, mBufferSize);
00844                         // delete temp data
00845                         delete[] mBuffer; // Note: not 'buffer' (assigned in setData())
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                 // NOTE: Priority gets updated when the http get completes (in callbackHTTPGet())
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); // Set priority first since Responder may change it
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                 // fall though (need to call requestDecodedData() to start work)
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                                         // Cache file should be deleted, try again
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; // failed
00896                                 }
00897                         }
00898                         else
00899                         {
00900                                 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
00901                                 mState = WRITE_TO_CACHE;
00902                         }
00903                         // fall through
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                         // If we're in a local cache or we didn't actually receive any new data, skip
00916                         mState = DONE;
00917                         return false;
00918                 }
00919                 S32 datasize = mFormattedImage->getDataSize();
00920                 llassert_always(datasize);
00921                 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
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                 // fall through
00930         }
00931         
00932         if (mState == WAIT_ON_WRITE)
00933         {
00934                 if (writeToCacheComplete())
00935                 {
00936                         mState = DONE;
00937                         // fall through
00938                 }
00939                 else
00940                 {
00941                         if (mDesiredDiscard < mDecodedDiscard)
00942                         {
00943                                 // We're waiting for this write to complete before we can receive more data
00944                                 // (we can't touch mFormattedImage until the write completes)
00945                                 // Prioritize the write
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                         // More data was requested, return to INIT
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 // Called from MAIN thread
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 // virtual
00985 void LLTextureFetchWorker::finishWork(S32 param, bool completed)
00986 {
00987         // The following are required in case the work was aborted
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 // virtual
01001 bool LLTextureFetchWorker::deleteOK()
01002 {
01003         bool delete_ok = true;
01004         // Allow any pending reads or writes to complete
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                  // not ok to delete from these states
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                                 // NOTE: setData releases current data
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 //      llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
01129         if (mLoaded)
01130         {
01131                 llwarns << "Duplicate callback for " << mID.asString() << llendl;
01132                 return; // ignore duplicate callback
01133         }
01134         if (data_size >= 0)
01135         {
01136                 if (data_size > 0)
01137                 {
01138                         mBuffer = new U8[data_size];
01139                         // *TODO: set the formatted image data here
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                                 // *TODO: This will happen until we fix LLCurl::getByteRange()
01149                                 llinfos << "HUH?" << llendl;
01150                                 mHaveAllData = TRUE;
01151                                 mFormattedImage->deleteData();
01152                                 mBufferSize = data_size;
01153                         }
01154                 }
01155                 else
01156                 {
01157                         // We requested data but received none (and no error),
01158                         // so presumably we have all of it
01159                         mHaveAllData = TRUE;
01160                 }
01161                 mRequestedSize = data_size;
01162         }
01163         else
01164         {
01165                 mRequestedSize = -1; // error
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 //      llinfos << mID << " : DECODE COMPLETE " << llendl;
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 //                      llinfos << mID << " : BASE DECODE FINISHED" << llendl;
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 //                      llinfos << mID << " : AUX DECODE FINISHED" << llendl;
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 //                      llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
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         // Complete write to cache
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 // public
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         // ~LLQueuedThread() called here
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                 // if we want the entire image, and we know its size, then get it all
01347                 // (calcDataSizeJ2C() below makes assumptions about how the image
01348                 // was compressed - this code ensures that when we request the entire image,
01349                 // we really do get it.)
01350                 desired_size = worker->mFileSize;
01351         }
01352         else if (w*h*c > 0)
01353         {
01354                 // If the requester knows the dimentions of the image,
01355                 // this will calculate how much data we need without having to parse the header
01356 
01357                 desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard);
01358         }
01359         else
01360         {
01361                 if (desired_discard == 0)
01362                 {
01363                         // If we want all of the image, request the maximum possible data
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; // need to wait for previous aborted request to complete
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                         // do remote fetch
01393                         worker = new LLTextureFetchWorker(this, id, host, priority, desired_discard, desired_size);
01394                 }
01395                 else
01396                 {
01397                         // do local file fetch
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 //      llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl;
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 // protected
01419 
01420 // call lockQueue() first!
01421 void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
01422 {
01423         if (mRequestMap.find(worker->mID) != mRequestMap.end())
01424         {
01425                 // only add to the queue if in the request map
01426                 // i.e. a delete has not been requested
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 // call lockQueue() first!
01437 void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker)
01438 {
01439         mNetworkQueue.erase(worker->mID);
01440 }
01441 
01442 // call lockQueue() first!
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 // call lockQueue() first!
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                         // Should only happen if we set mDebugPause...
01482                         if (!mDebugPause)
01483                         {
01484 //                              llwarns << "Adding work for inactive worker: " << id << llendl;
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                                 // Not finished, but data is ready
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 //virtual
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         // Periodically, gather the list of textures that need data from the network
01543         // And send the requests out to the simulators
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; // 10.0f // temp
01559         const F32 MIN_REQUEST_TIME = 1.0f;
01560         const F32 MIN_DELTA_PRIORITY = 1000.f;
01561 
01562         LLMutexLock lock(&mQueueMutex);
01563         
01564         // Send requests
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; // paranoia
01576                 }
01577                 if (req->mID == mDebugID)
01578                 {
01579                         mDebugCount++; // for setting breakpoints
01580                 }
01581                 if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1)
01582                 {
01583                         // We have all the packets... make sure this is high priority
01584 //                      req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority);
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                 // invalid host = use agent host
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 //                              llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
01650 //                                              << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
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 //                                      llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
01661                                         gMessageSystem->sendSemiReliable(host, NULL, NULL);
01662                                         request_count = 0;
01663                                 }
01664                         }
01665                         if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
01666                         {
01667 //                              llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
01668                                 gMessageSystem->sendSemiReliable(host, NULL, NULL);
01669                                 request_count = 0;
01670                         }
01671                 }
01672         }
01673         
01674         // Send cancelations
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 //                              llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl;
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 //              llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << llendl;
01728                 return false;
01729         }
01730         if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE)
01731         {
01732 //              llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << llendl;
01733                 return false;
01734         }
01735         
01736         if (index >= (S32)mPackets.size())
01737         {
01738                 mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers
01739         }
01740         else if (mPackets[index] != NULL)
01741         {
01742 //              llwarns << "Received duplicate packet: " << index << " for image: " << mID << llendl;
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 //              llwarns << "Received header for non active worker: " << id << llendl;
01766                 res = false;
01767         }
01768         else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
01769                          worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
01770         {
01771 //              llwarns << "receiveImageHeader for worker: " << id
01772 //                              << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState]
01773 //                              << " sent: " << worker->mSentRequest << llendl;
01774                 res = false;
01775         }
01776         else if (worker->mLastPacket != -1)
01777         {
01778                 // check to see if we've gotten this packet before
01779 //              llwarns << "Received duplicate header for: " << id << llendl;
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         //      Copy header data into image object
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 //              llwarns << "Received packet " << packet_num << " for non active worker: " << id << llendl;
01820                 res = false;
01821         }
01822         else if (worker->mLastPacket == -1)
01823         {
01824 //              llwarns << "Received packet " << packet_num << " before header for: " << id << llendl;
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 //              llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
01852 //                      << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
01853                 removeFromNetworkQueue(worker); // failsafe
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 

Generated on Fri May 16 08:34:04 2008 for SecondLife by  doxygen 1.5.5