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

Generated on Thu Jul 1 06:09:19 2010 for Second Life Viewer by  doxygen 1.4.7