aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lltexturefetch.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2010-02-09 21:11:42 -0600
committerJacek Antonelli2010-02-16 18:50:15 -0600
commite6247fbe78c4d3dacb74f3b2359aba2b6538133b (patch)
tree10c42d670a2c635b4339f7f68809c221756774f8 /linden/indra/newview/lltexturefetch.cpp
parentPorted some cURL and HTTP-related changes from Snowglobe. (diff)
downloadmeta-impy-e6247fbe78c4d3dacb74f3b2359aba2b6538133b.zip
meta-impy-e6247fbe78c4d3dacb74f3b2359aba2b6538133b.tar.gz
meta-impy-e6247fbe78c4d3dacb74f3b2359aba2b6538133b.tar.bz2
meta-impy-e6247fbe78c4d3dacb74f3b2359aba2b6538133b.tar.xz
Ported many texture engine changes from Snowglobe.
Diffstat (limited to 'linden/indra/newview/lltexturefetch.cpp')
-rw-r--r--linden/indra/newview/lltexturefetch.cpp1058
1 files changed, 599 insertions, 459 deletions
diff --git a/linden/indra/newview/lltexturefetch.cpp b/linden/indra/newview/lltexturefetch.cpp
index e9dd792..935b8cc 100644
--- a/linden/indra/newview/lltexturefetch.cpp
+++ b/linden/indra/newview/lltexturefetch.cpp
@@ -32,108 +32,35 @@
32 32
33#include "llviewerprecompiledheaders.h" 33#include "llviewerprecompiledheaders.h"
34 34
35#include <iostream>
36
35#include "llstl.h" 37#include "llstl.h"
36 38
37#include "lltexturefetch.h" 39#include "lltexturefetch.h"
38 40
39#include "llcurl.h" 41#include "llcurl.h"
42#include "lldir.h"
40#include "llhttpclient.h" 43#include "llhttpclient.h"
44#include "llhttpstatuscodes.h"
41#include "llimage.h" 45#include "llimage.h"
42#include "llimageworker.h" 46#include "llimageworker.h"
43#include "llworkerthread.h" 47#include "llworkerthread.h"
44 48
45#include "llagent.h" 49#include "llagent.h"
46#include "lltexturecache.h" 50#include "lltexturecache.h"
51#include "llviewercontrol.h"
47#include "llviewerimagelist.h" 52#include "llviewerimagelist.h"
48#include "llviewerimage.h" 53#include "llviewerimage.h"
49#include "llviewerregion.h" 54#include "llviewerregion.h"
55#include "llworld.h"
50 56
51////////////////////////////////////////////////////////////////////////////// 57//////////////////////////////////////////////////////////////////////////////
52//static
53class LLTextureFetchWorker : public LLWorkerClass 58class LLTextureFetchWorker : public LLWorkerClass
54{ 59{
55friend class LLTextureFetch; 60 friend class LLTextureFetch;
56 61 friend class HTTPGetResponder;
57private:
58#if 0
59 class URLResponder : public LLHTTPClient::Responder
60 {
61 public:
62 URLResponder(LLTextureFetch* fetcher, const LLUUID& id)
63 : mFetcher(fetcher), mID(id)
64 {
65 }
66 ~URLResponder()
67 {
68 }
69 virtual void error(U32 status, const std::string& reason)
70 {
71 mFetcher->lockQueue();
72 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
73 if (worker)
74 {
75// llwarns << "LLTextureFetchWorker::URLResponder::error " << status << ": " << reason << llendl;
76 worker->callbackURLReceived(LLSD(), false);
77 }
78 mFetcher->unlockQueue();
79 }
80 virtual void result(const LLSD& content)
81 {
82 mFetcher->lockQueue();
83 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
84 if (worker)
85 {
86 worker->callbackURLReceived(content, true);
87 }
88 mFetcher->unlockQueue();
89 }
90 private:
91 LLTextureFetch* mFetcher;
92 LLUUID mID;
93 };
94
95 class HTTPGetResponder : public LLHTTPClient::Responder
96 {
97 public:
98 HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id)
99 : mFetcher(fetcher), mID(id)
100 {
101 }
102 ~HTTPGetResponder()
103 {
104 }
105 virtual void completed(U32 status, const std::stringstream& content)
106 {
107 mFetcher->lockQueue();
108 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
109 if (worker)
110 {
111 const std::string& cstr = content.str();
112 if (200 <= status && status < 300)
113 {
114 if (203 == status) // partial information (i.e. last block)
115 {
116 worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), true);
117 }
118 else
119 {
120 worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), false);
121 }
122 }
123 else
124 {
125// llinfos << "LLTextureFetchWorker::HTTPGetResponder::error " << status << ": " << cstr << llendl;
126 worker->callbackHttpGet(NULL, -1, true);
127 }
128 }
129 mFetcher->unlockQueue();
130 }
131 private:
132 LLTextureFetch* mFetcher;
133 LLUUID mID;
134 };
135#endif
136 62
63private:
137 class CacheReadResponder : public LLTextureCache::ReadResponder 64 class CacheReadResponder : public LLTextureCache::ReadResponder
138 { 65 {
139 public: 66 public:
@@ -179,20 +106,20 @@ private:
179 LLUUID mID; 106 LLUUID mID;
180 }; 107 };
181 108
182 class DecodeResponder : public LLResponder 109 class DecodeResponder : public LLImageDecodeThread::Responder
183 { 110 {
184 public: 111 public:
185 DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker) 112 DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker)
186 : mFetcher(fetcher), mID(id), mWorker(worker) 113 : mFetcher(fetcher), mID(id), mWorker(worker)
187 { 114 {
188 } 115 }
189 virtual void completed(bool success) 116 virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
190 { 117 {
191 mFetcher->lockQueue(); 118 mFetcher->lockQueue();
192 LLTextureFetchWorker* worker = mFetcher->getWorker(mID); 119 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
193 if (worker) 120 if (worker)
194 { 121 {
195 worker->callbackDecoded(success); 122 worker->callbackDecoded(success, raw, aux);
196 } 123 }
197 mFetcher->unlockQueue(); 124 mFetcher->unlockQueue();
198 } 125 }
@@ -225,39 +152,47 @@ public:
225 /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD) 152 /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
226 153
227 ~LLTextureFetchWorker(); 154 ~LLTextureFetchWorker();
228 void relese() { --mActiveCount; } 155 void release() { --mActiveCount; }
156
157 void callbackHttpGet(const LLChannelDescriptors& channels,
158 const LLIOPipe::buffer_ptr_t& buffer,
159 bool last_block, bool success);
160 void callbackCacheRead(bool success, LLImageFormatted* image,
161 S32 imagesize, BOOL islocal);
162 void callbackCacheWrite(bool success);
163 void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
164
165 void setGetStatus(U32 status, const std::string& reason)
166 {
167 mGetStatus = status;
168 mGetReason = reason;
169 }
229 170
230protected: 171protected:
231 LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host, 172 LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
232 F32 priority, S32 discard, S32 size); 173 F32 priority, S32 discard, S32 size);
174 LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
175 F32 priority, S32 discard, S32 size);
233 176
234private: 177private:
235 /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD) 178 /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
236 /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) 179 /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
237 180
238 virtual std::string getName() { return LLStringUtil::null; }
239 void resetFormattedData(); 181 void resetFormattedData();
240 182
241 void setImagePriority(F32 priority); 183 void setImagePriority(F32 priority);
242 void setDesiredDiscard(S32 discard, S32 size); 184 void setDesiredDiscard(S32 discard, S32 size);
243 bool insertPacket(S32 index, U8* data, S32 size); 185 bool insertPacket(S32 index, U8* data, S32 size);
244 void clearPackets(); 186 void clearPackets();
187 void setupPacketData();
245 U32 calcWorkPriority(); 188 U32 calcWorkPriority();
246 void removeFromCache(); 189 void removeFromCache();
247 bool processSimulatorPackets(); 190 bool processSimulatorPackets();
248 bool decodeImage();
249 bool writeToCacheComplete(); 191 bool writeToCacheComplete();
250 192
251 void lockWorkData() { mWorkMutex.lock(); } 193 void lockWorkMutex() { mWorkMutex.lock(); }
252 void unlockWorkData() { mWorkMutex.unlock(); } 194 void unlockWorkMutex() { mWorkMutex.unlock(); }
253 195
254 void callbackURLReceived(const LLSD& data, bool success);
255 void callbackHttpGet(U8* data, S32 data_size, bool last_block);
256 void callbackCacheRead(bool success, LLImageFormatted* image,
257 S32 imagesize, BOOL islocal);
258 void callbackCacheWrite(bool success);
259 void callbackDecoded(bool success);
260
261private: 196private:
262 enum e_state // mState 197 enum e_state // mState
263 { 198 {
@@ -268,8 +203,8 @@ private:
268 CACHE_POST, 203 CACHE_POST,
269 LOAD_FROM_NETWORK, 204 LOAD_FROM_NETWORK,
270 LOAD_FROM_SIMULATOR, 205 LOAD_FROM_SIMULATOR,
271 LOAD_FROM_HTTP_GET_URL, 206 SEND_HTTP_REQ,
272 LOAD_FROM_HTTP_GET_DATA, 207 WAIT_HTTP_REQ,
273 DECODE_IMAGE, 208 DECODE_IMAGE,
274 DECODE_IMAGE_UPDATE, 209 DECODE_IMAGE_UPDATE,
275 WRITE_TO_CACHE, 210 WRITE_TO_CACHE,
@@ -280,19 +215,17 @@ private:
280 { 215 {
281 UNSENT = 0, 216 UNSENT = 0,
282 QUEUED = 1, 217 QUEUED = 1,
283 SENT_SIM = 2, 218 SENT_SIM = 2
284 SENT_URL = 3,
285 SENT_HTTP = 4
286 }; 219 };
287 static const char* sStateDescs[]; 220 static const char* sStateDescs[];
288 e_state mState; 221 e_state mState;
289 LLTextureFetch* mFetcher; 222 LLTextureFetch* mFetcher;
290 LLImageWorker* mImageWorker;
291 LLPointer<LLImageFormatted> mFormattedImage; 223 LLPointer<LLImageFormatted> mFormattedImage;
292 LLPointer<LLImageRaw> mRawImage; 224 LLPointer<LLImageRaw> mRawImage;
293 LLPointer<LLImageRaw> mAuxImage; 225 LLPointer<LLImageRaw> mAuxImage;
294 LLUUID mID; 226 LLUUID mID;
295 LLHost mHost; 227 LLHost mHost;
228 std::string mUrl;
296 U8 mType; 229 U8 mType;
297 F32 mImagePriority; 230 F32 mImagePriority;
298 U32 mWorkPriority; 231 U32 mWorkPriority;
@@ -314,15 +247,18 @@ private:
314 S32 mCachedSize; 247 S32 mCachedSize;
315 BOOL mLoaded; 248 BOOL mLoaded;
316 e_request_state mSentRequest; 249 e_request_state mSentRequest;
250 handle_t mDecodeHandle;
317 BOOL mDecoded; 251 BOOL mDecoded;
318 BOOL mWritten; 252 BOOL mWritten;
319 BOOL mNeedsAux; 253 BOOL mNeedsAux;
320 BOOL mHaveAllData; 254 BOOL mHaveAllData;
321 BOOL mInLocalCache; 255 BOOL mInLocalCache;
256 S32 mHTTPFailCount;
322 S32 mRetryAttempt; 257 S32 mRetryAttempt;
323 std::string mURL;
324 S32 mActiveCount; 258 S32 mActiveCount;
325 259 U32 mGetStatus;
260 std::string mGetReason;
261
326 // Work Data 262 // Work Data
327 LLMutex mWorkMutex; 263 LLMutex mWorkMutex;
328 struct PacketData 264 struct PacketData
@@ -340,25 +276,79 @@ private:
340 U8 mImageCodec; 276 U8 mImageCodec;
341}; 277};
342 278
343class LLTextureFetchLocalFileWorker : public LLTextureFetchWorker 279//////////////////////////////////////////////////////////////////////////////
344{
345friend class LLTextureFetch;
346
347protected:
348 LLTextureFetchLocalFileWorker(LLTextureFetch* fetcher, const std::string& filename, const LLUUID& id, const LLHost& host,
349 F32 priority, S32 discard, S32 size)
350 : LLTextureFetchWorker(fetcher, id, host, priority, discard, size),
351 mFileName(filename)
352 {}
353 280
354private: 281class HTTPGetResponder : public LLCurl::Responder
355 /*virtual*/ std::string getName() { return mFileName; } 282{
283 LOG_CLASS(HTTPGetResponder);
284public:
285 HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset)
286 : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset)
287 {
288 }
289 ~HTTPGetResponder()
290 {
291 }
356 292
293 virtual void completedRaw(U32 status, const std::string& reason,
294 const LLChannelDescriptors& channels,
295 const LLIOPipe::buffer_ptr_t& buffer)
296 {
297 if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
298 {
299 mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime);
300 U64 timeNow = LLTimer::getTotalTime();
301 mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
302 mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
303 mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
304 mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
305 }
357 306
307 lldebugs << "HTTP COMPLETE: " << mID << llendl;
308 mFetcher->lockQueue();
309 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
310 if (worker)
311 {
312 bool success = false;
313 bool partial = false;
314 if (200 <= status && status < 300)
315 {
316 success = true;
317 if (HTTP_PARTIAL_CONTENT == status) // partial information (i.e. last block)
318 {
319 partial = true;
320 }
321 }
322 else
323 {
324 worker->setGetStatus(status, reason);
325// llwarns << status << ": " << reason << llendl;
326 }
327 if (!success)
328 {
329 worker->setGetStatus(status, reason);
330// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
331 }
332 mFetcher->removeFromHTTPQueue(mID);
333 worker->callbackHttpGet(channels, buffer, partial, success);
334 }
335 else
336 {
337 mFetcher->removeFromHTTPQueue(mID);
338 llwarns << "Worker not found: " << mID << llendl;
339 }
340 mFetcher->unlockQueue();
341 }
342
358private: 343private:
359 std::string mFileName; 344 LLTextureFetch* mFetcher;
345 LLUUID mID;
346 U64 mStartTime;
347 S32 mRequestedSize;
348 U32 mOffset;
360}; 349};
361 350
351//////////////////////////////////////////////////////////////////////////////
362 352
363//static 353//static
364const char* LLTextureFetchWorker::sStateDescs[] = { 354const char* LLTextureFetchWorker::sStateDescs[] = {
@@ -368,8 +358,8 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
368 "CACHE_POST", 358 "CACHE_POST",
369 "LOAD_FROM_NETWORK", 359 "LOAD_FROM_NETWORK",
370 "LOAD_FROM_SIMULATOR", 360 "LOAD_FROM_SIMULATOR",
371 "LOAD_FROM_HTTP_URL", 361 "SEND_HTTP_REQ",
372 "LOAD_FROM_HTTP_DATA", 362 "WAIT_HTTP_REQ",
373 "DECODE_IMAGE", 363 "DECODE_IMAGE",
374 "DECODE_IMAGE_UPDATE", 364 "DECODE_IMAGE_UPDATE",
375 "WRITE_TO_CACHE", 365 "WRITE_TO_CACHE",
@@ -380,6 +370,7 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
380// called from MAIN THREAD 370// called from MAIN THREAD
381 371
382LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, 372LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
373 const std::string& url, // Optional URL
383 const LLUUID& id, // Image UUID 374 const LLUUID& id, // Image UUID
384 const LLHost& host, // Simulator host 375 const LLHost& host, // Simulator host
385 F32 priority, // Priority 376 F32 priority, // Priority
@@ -388,9 +379,9 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
388 : LLWorkerClass(fetcher, "TextureFetch"), 379 : LLWorkerClass(fetcher, "TextureFetch"),
389 mState(INIT), 380 mState(INIT),
390 mFetcher(fetcher), 381 mFetcher(fetcher),
391 mImageWorker(NULL),
392 mID(id), 382 mID(id),
393 mHost(host), 383 mHost(host),
384 mUrl(url),
394 mImagePriority(priority), 385 mImagePriority(priority),
395 mWorkPriority(0), 386 mWorkPriority(0),
396 mRequestedPriority(0.f), 387 mRequestedPriority(0.f),
@@ -409,13 +400,16 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
409 mCachedSize(0), 400 mCachedSize(0),
410 mLoaded(FALSE), 401 mLoaded(FALSE),
411 mSentRequest(UNSENT), 402 mSentRequest(UNSENT),
403 mDecodeHandle(0),
412 mDecoded(FALSE), 404 mDecoded(FALSE),
413 mWritten(FALSE), 405 mWritten(FALSE),
414 mNeedsAux(FALSE), 406 mNeedsAux(FALSE),
415 mHaveAllData(FALSE), 407 mHaveAllData(FALSE),
416 mInLocalCache(FALSE), 408 mInLocalCache(FALSE),
409 mHTTPFailCount(0),
417 mRetryAttempt(0), 410 mRetryAttempt(0),
418 mActiveCount(0), 411 mActiveCount(0),
412 mGetStatus(0),
419 mWorkMutex(NULL), 413 mWorkMutex(NULL),
420 mFirstPacket(0), 414 mFirstPacket(0),
421 mLastPacket(-1), 415 mLastPacket(-1),
@@ -425,12 +419,14 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
425 calcWorkPriority(); 419 calcWorkPriority();
426 mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL; 420 mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
427// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl; 421// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
422 lockWorkMutex();
428 if (!mFetcher->mDebugPause) 423 if (!mFetcher->mDebugPause)
429 { 424 {
430 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; 425 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
431 addWork(0, work_priority ); 426 addWork(0, work_priority );
432 } 427 }
433 setDesiredDiscard(discard, size); 428 setDesiredDiscard(discard, size);
429 unlockWorkMutex();
434} 430}
435 431
436LLTextureFetchWorker::~LLTextureFetchWorker() 432LLTextureFetchWorker::~LLTextureFetchWorker()
@@ -440,7 +436,7 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
440// << " Requested=" << mRequestedDiscard 436// << " Requested=" << mRequestedDiscard
441// << " Desired=" << mDesiredDiscard << llendl; 437// << " Desired=" << mDesiredDiscard << llendl;
442 llassert_always(!haveWork()); 438 llassert_always(!haveWork());
443 lockWorkData(); 439 lockWorkMutex();
444 if (mCacheReadHandle != LLTextureCache::nullHandle()) 440 if (mCacheReadHandle != LLTextureCache::nullHandle())
445 { 441 {
446 mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); 442 mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
@@ -449,13 +445,9 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
449 { 445 {
450 mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); 446 mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
451 } 447 }
452 if (mImageWorker)
453 {
454 mImageWorker->scheduleDelete();
455 }
456 mFormattedImage = NULL; 448 mFormattedImage = NULL;
457 clearPackets(); 449 clearPackets();
458 unlockWorkData(); 450 unlockWorkMutex();
459} 451}
460 452
461void LLTextureFetchWorker::clearPackets() 453void LLTextureFetchWorker::clearPackets()
@@ -467,6 +459,38 @@ void LLTextureFetchWorker::clearPackets()
467 mFirstPacket = 0; 459 mFirstPacket = 0;
468} 460}
469 461
462void LLTextureFetchWorker::setupPacketData()
463{
464 S32 data_size = 0;
465 if (mFormattedImage.notNull())
466 {
467 data_size = mFormattedImage->getDataSize();
468 }
469 if (data_size > 0)
470 {
471 // Only used for simulator requests
472 mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
473 if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
474 {
475 llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
476 removeFromCache();
477 resetFormattedData();
478 clearPackets();
479 }
480 else if (mFileSize > 0)
481 {
482 mLastPacket = mFirstPacket-1;
483 mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
484 }
485 else
486 {
487 // This file was cached using HTTP so we have to refetch the first packet
488 resetFormattedData();
489 clearPackets();
490 }
491 }
492}
493
470U32 LLTextureFetchWorker::calcWorkPriority() 494U32 LLTextureFetchWorker::calcWorkPriority()
471{ 495{
472// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerImage::maxDecodePriority()); 496// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerImage::maxDecodePriority());
@@ -538,7 +562,6 @@ void LLTextureFetchWorker::resetFormattedData()
538// Called from MAIN thread 562// Called from MAIN thread
539void LLTextureFetchWorker::startWork(S32 param) 563void LLTextureFetchWorker::startWork(S32 param)
540{ 564{
541 llassert(mImageWorker == NULL);
542 llassert(mFormattedImage.isNull()); 565 llassert(mFormattedImage.isNull());
543} 566}
544 567
@@ -549,6 +572,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
549{ 572{
550 LLMutexLock lock(&mWorkMutex); 573 LLMutexLock lock(&mWorkMutex);
551 574
575 if ((mFetcher->isQuitting() || (mImagePriority <= 0.0f) || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
576 {
577 if (mState < WRITE_TO_CACHE)
578 {
579 return true; // abort
580 }
581 }
582
552 if (mFetcher->mDebugPause) 583 if (mFetcher->mDebugPause)
553 { 584 {
554 return false; // debug: don't do any work 585 return false; // debug: don't do any work
@@ -563,14 +594,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
563 mFetchTimer.reset(); 594 mFetchTimer.reset();
564 } 595 }
565 596
566 if (mImagePriority <= 0.0f)
567 {
568 if (mState < WRITE_TO_CACHE)
569 {
570 return true; // cancel request
571 }
572 }
573
574 if (mState == INIT) 597 if (mState == INIT)
575 { 598 {
576 mRequestedDiscard = -1; 599 mRequestedDiscard = -1;
@@ -590,7 +613,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
590 clearPackets(); // TODO: Shouldn't be necessary 613 clearPackets(); // TODO: Shouldn't be necessary
591 mCacheReadHandle = LLTextureCache::nullHandle(); 614 mCacheReadHandle = LLTextureCache::nullHandle();
592 mCacheWriteHandle = LLTextureCache::nullHandle(); 615 mCacheWriteHandle = LLTextureCache::nullHandle();
593 mURL.clear();
594 mState = LOAD_FROM_TEXTURE_CACHE; 616 mState = LOAD_FROM_TEXTURE_CACHE;
595 // fall through 617 // fall through
596 } 618 }
@@ -612,16 +634,27 @@ bool LLTextureFetchWorker::doWork(S32 param)
612 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it 634 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
613 635
614 CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); 636 CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
615 if (getName().empty()) 637 if (mUrl.compare(0, 7, "file://") == 0)
638 {
639 // read file from local disk
640 std::string filename = mUrl.substr(7, std::string::npos);
641 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
642 offset, size, responder);
643 }
644 else if (mUrl.empty())
616 { 645 {
617 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, 646 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
618 offset, size, responder); 647 offset, size, responder);
619 } 648 }
620 else 649 else
621 { 650 {
622 // read file from local disk 651 if (!(mUrl.compare(0, 7, "http://") == 0))
623 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(getName(), mID, cache_priority, 652 {
624 offset, size, responder); 653 // *TODO:?remove this warning
654 llwarns << "Unknown URL Type: " << mUrl << llendl;
655 }
656 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
657 mState = SEND_HTTP_REQ;
625 } 658 }
626 } 659 }
627 660
@@ -659,67 +692,92 @@ bool LLTextureFetchWorker::doWork(S32 param)
659 } 692 }
660 else 693 else
661 { 694 {
662 if (!getName().empty()) 695 if (mUrl.compare(0, 7, "file://") == 0)
663 { 696 {
664 // failed to load local file, we're done. 697 // failed to load local file, we're done.
665 return true; 698 return true;
666 } 699 }
667 // need more data 700 // need more data
668 mState = LOAD_FROM_NETWORK; 701 else
702 {
703 mState = LOAD_FROM_NETWORK; // CACHE_POST --> LOAD_FROM_NETWORK, or SEND_HTTP_REQ see below.
704 // This is true because mSentRequest is set to UNSENT in INIT and if we get here we went through
705 // the states INIT --> LOAD_FROM_TEXTURE_CACHE --> CACHE_POST. Therefore either
706 // mFetcher->addToNetworkQueue(this) is called below, or mState is set to SEND_HTTP_REQ.
707 llassert(mSentRequest == UNSENT);
708 }
669 // fall through 709 // fall through
670 } 710 }
671 } 711 }
672 712
673 if (mState == LOAD_FROM_NETWORK) 713 if (mState == LOAD_FROM_NETWORK)
674 { 714 {
675 if (mSentRequest == UNSENT) 715 bool get_url = gSavedSettings.getBOOL("ImagePipelineUseHTTP");
716 if (!mUrl.empty()) get_url = false;
717// if (mHost != LLHost::invalid) get_url = false;
718 if ( get_url )
676 { 719 {
677 if (mFormattedImage.isNull()) 720 LLViewerRegion* region = NULL;
678 { 721 if (mHost == LLHost::invalid)
679 mFormattedImage = new LLImageJ2C; 722 region = gAgent.getRegion();
680 } 723 else
681 // Add this to the network queue and sit here. 724 region = LLWorld::getInstance()->getRegion(mHost);
682 // LLTextureFetch::update() will send off a request which will change our state 725
683 S32 data_size = mFormattedImage->getDataSize(); 726 if (region)
684 if (data_size > 0)
685 { 727 {
686 // Only used for simulator requests 728 std::string http_url = region->getCapability("GetTexture");
687 mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1; 729 if (!http_url.empty())
688 if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
689 {
690// llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
691 removeFromCache();
692 resetFormattedData();
693 clearPackets();
694 }
695 else
696 { 730 {
697 mLastPacket = mFirstPacket-1; 731 mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
698 mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
699 } 732 }
700 } 733 }
734 else
735 {
736 llwarns << "Region not found for host: " << mHost << llendl;
737 }
738 }
739 if (!mUrl.empty())
740 {
741 mState = LLTextureFetchWorker::SEND_HTTP_REQ;
742 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
743 // don't return, fall through to next state
744 }
745 else if (mSentRequest == UNSENT)
746 {
747 // Add this to the network queue and sit here.
748 // LLTextureFetch::update() will send off a request which will change our state
701 mRequestedSize = mDesiredSize; 749 mRequestedSize = mDesiredSize;
702 mRequestedDiscard = mDesiredDiscard; 750 mRequestedDiscard = mDesiredDiscard;
703 mSentRequest = QUEUED; 751 mSentRequest = QUEUED;
704 mFetcher->lockQueue();
705 mFetcher->addToNetworkQueue(this); 752 mFetcher->addToNetworkQueue(this);
706 mFetcher->unlockQueue();
707 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); 753 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
754 return false;
755 }
756 else
757 {
758 // Shouldn't need to do anything here
759 //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
760 // Make certain this is in the network queue
761 //mFetcher->addToNetworkQueue(this);
762 //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
763 return false;
708 } 764 }
709 return false;
710 } 765 }
711 766
712 if (mState == LOAD_FROM_SIMULATOR) 767 if (mState == LOAD_FROM_SIMULATOR)
713 { 768 {
769 if (mFormattedImage.isNull())
770 {
771 mFormattedImage = new LLImageJ2C;
772 }
714 if (processSimulatorPackets()) 773 if (processSimulatorPackets())
715 { 774 {
716 mFetcher->lockQueue(); 775 mFetcher->removeFromNetworkQueue(this, false);
717 mFetcher->removeFromNetworkQueue(this);
718 mFetcher->unlockQueue();
719 if (mFormattedImage.isNull() || !mFormattedImage->getDataSize()) 776 if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
720 { 777 {
721 // processSimulatorPackets() failed 778 // processSimulatorPackets() failed
722// llwarns << "processSimulatorPackets() failed to load buffer" << llendl; 779// llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
780 // FIXME: Don't we need a mState change?
723 return true; // failed 781 return true; // failed
724 } 782 }
725 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 783 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
@@ -732,103 +790,91 @@ bool LLTextureFetchWorker::doWork(S32 param)
732 return false; 790 return false;
733 } 791 }
734 792
735#if 0 793 if (mState == SEND_HTTP_REQ)
736 if (mState == LOAD_FROM_HTTP_GET_URL) 794 {
737 { 795 {
738 if (!mSentRequest) 796 const S32 HTTP_QUEUE_MAX_SIZE = 32;
739 { 797 // *TODO: Integrate this with llviewerthrottle
740 mSentRequest = TRUE; 798 // Note: LLViewerThrottle uses dynamic throttling which makes sense for UDP,
741 mLoaded = FALSE; 799 // but probably not for Textures.
742 std::string url; 800 // Set the throttle to the entire bandwidth, assuming UDP packets will get priority
743 LLViewerRegion* region = gAgent.getRegion(); 801 // when they are needed
744 if (region) 802 F32 max_bandwidth = mFetcher->mMaxBandwidth;
803 if ((mFetcher->getHTTPQueueSize() >= HTTP_QUEUE_MAX_SIZE) ||
804 (mFetcher->getTextureBandwidth() > max_bandwidth))
745 { 805 {
746 url = region->getCapability("RequestTextureDownload"); 806 // Make normal priority and return (i.e. wait until there is room in the queue)
747 } 807 setPriority(LLWorkerThread::PRIORITY_NORMAL | mWorkPriority);
748 if (!url.empty())
749 {
750 LLSD sd;
751 sd = mID.asString();
752 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
753 LLHTTPClient::post(url, sd, new URLResponder(mFetcher, mID));
754 return false; 808 return false;
755 } 809 }
756 else 810
811 S32 cur_size = 0;
812 if (mFormattedImage.notNull())
757 { 813 {
758// llwarns << mID << ": HTTP get url failed, requesting from simulator" << llendl; 814 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
759 mSentRequest = FALSE;
760 mState = LOAD_FROM_SIMULATOR;
761 return false;
762 } 815 }
763 }
764 else
765 {
766 if (mLoaded)
767 {
768 if (!mURL.empty())
769 {
770 mState = LOAD_FROM_HTTP_GET_DATA;
771 mSentRequest = FALSE; // reset
772 mLoaded = FALSE; // reset
773 }
774 else
775 {
776// llwarns << mID << ": HTTP get url is empty, requesting from simulator" << llendl;
777 mSentRequest = FALSE;
778 mState = LOAD_FROM_SIMULATOR;
779 return false;
780 }
781 }
782 }
783 // fall through
784 }
785
786 if (mState == LOAD_FROM_HTTP_GET_DATA)
787 {
788 if (!mSentRequest)
789 {
790 mSentRequest = TRUE;
791 S32 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
792 mRequestedSize = mDesiredSize; 816 mRequestedSize = mDesiredSize;
793 mRequestedDiscard = mDesiredDiscard; 817 mRequestedDiscard = mDesiredDiscard;
794#if 1 // *TODO: LLCurl::getByteRange is broken (ignores range)
795 cur_size = 0;
796 mFormattedImage->deleteData();
797#endif
798 mRequestedSize -= cur_size; 818 mRequestedSize -= cur_size;
799 // F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1 819// F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1
800 S32 offset = cur_size; 820 S32 offset = cur_size;
801 mBufferSize = cur_size; // This will get modified by callbackHttpGet() 821 mBufferSize = cur_size; // This will get modified by callbackHttpGet()
802 std::string url; 822
803 if (mURL.empty()) 823 bool res = false;
824 if (!mUrl.empty())
804 { 825 {
805 //url = "http://asset.agni/0000002f-38ae-0e17-8e72-712e58964e9c.texture"; 826 mLoaded = FALSE;
806 std::stringstream urlstr; 827 mGetStatus = 0;
807 urlstr << "http://asset.agni/" << mID.asString() << ".texture"; 828 mGetReason.clear();
808 url = urlstr.str(); 829 lldebugs << "HTTP GET: " << mID << " Offset: " << offset
830 << " Bytes: " << mRequestedSize
831 << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth
832 << llendl;
833 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
834 mState = WAIT_HTTP_REQ;
835
836 mFetcher->addToHTTPQueue(mID);
837 // Will call callbackHttpGet when curl request completes
838 std::vector<std::string> headers;
839 headers.push_back("Accept: image/x-j2c");
840 res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
841 new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset));
809 } 842 }
810 else 843 if (!res)
811 { 844 {
812 url = mURL; 845 llwarns << "HTTP GET request failed for " << mID << llendl;
846 resetFormattedData();
847 ++mHTTPFailCount;
848 return true; // failed
813 } 849 }
814 mLoaded = FALSE; 850 // fall through
815// llinfos << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize << llendl;
816 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
817 LLCurl::getByteRange(url, offset, mRequestedSize,
818 new HTTPGetResponder(mFetcher, mID)); // *TODO: use mWorkPriority
819 return false; // not done
820 } 851 }
821 852 }
853
854 if (mState == WAIT_HTTP_REQ)
855 {
822 if (mLoaded) 856 if (mLoaded)
823 { 857 {
824 S32 cur_size = mFormattedImage->getDataSize(); 858 S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
825 if (mRequestedSize < 0) 859 if (mRequestedSize < 0)
826 { 860 {
827// llwarns << "http get failed for: " << mID << llendl; 861 const S32 HTTP_MAX_RETRY_COUNT = 4;
862 llinfos << "HTTP GET failed for: " << mUrl
863 << " Status: " << mGetStatus << " Reason: " << mGetReason
864 << " Try:" << mHTTPFailCount+1 << "/" << HTTP_MAX_RETRY_COUNT << llendl;
828 if (cur_size == 0) 865 if (cur_size == 0)
829 { 866 {
830 resetFormattedData(); 867 ++mHTTPFailCount;
831 return true; // failed 868 if (mGetStatus == HTTP_NOT_FOUND || mHTTPFailCount >= HTTP_MAX_RETRY_COUNT)
869 {
870 resetFormattedData();
871 return true; // failed
872 }
873 else
874 {
875 mState = SEND_HTTP_REQ;
876 return false; // retry
877 }
832 } 878 }
833 else 879 else
834 { 880 {
@@ -836,6 +882,18 @@ bool LLTextureFetchWorker::doWork(S32 param)
836 return false; // use what we have 882 return false; // use what we have
837 } 883 }
838 } 884 }
885
886 if (mFormattedImage.isNull())
887 {
888 // For now, create formatted image based on extension
889 std::string extension = gDirUtilp->getExtension(mUrl);
890 mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension));
891 if (mFormattedImage.isNull())
892 {
893 mFormattedImage = new LLImageJ2C; // default
894 }
895 }
896
839 llassert_always(mBufferSize == cur_size + mRequestedSize); 897 llassert_always(mBufferSize == cur_size + mRequestedSize);
840 if (mHaveAllData) 898 if (mHaveAllData)
841 { 899 {
@@ -854,16 +912,16 @@ bool LLTextureFetchWorker::doWork(S32 param)
854 mBuffer = NULL; 912 mBuffer = NULL;
855 mBufferSize = 0; 913 mBufferSize = 0;
856 mLoadedDiscard = mRequestedDiscard; 914 mLoadedDiscard = mRequestedDiscard;
857 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
858 mState = DECODE_IMAGE; 915 mState = DECODE_IMAGE;
916 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
917 return false;
918 }
919 else
920 {
921 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
859 return false; 922 return false;
860 } 923 }
861
862 // NOTE: Priority gets updated when the http get completes (in callbackHTTPGet())
863 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
864 return false;
865 } 924 }
866#endif
867 925
868 if (mState == DECODE_IMAGE) 926 if (mState == DECODE_IMAGE)
869 { 927 {
@@ -871,19 +929,19 @@ bool LLTextureFetchWorker::doWork(S32 param)
871 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it 929 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
872 mRawImage = NULL; 930 mRawImage = NULL;
873 mAuxImage = NULL; 931 mAuxImage = NULL;
874 llassert_always(mImageWorker == NULL);
875 llassert_always(mFormattedImage.notNull()); 932 llassert_always(mFormattedImage.notNull());
876 S32 discard = mHaveAllData ? 0 : mLoadedDiscard; 933 S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
877 U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; 934 U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
878 mDecoded = FALSE; 935 mDecoded = FALSE;
879 mState = DECODE_IMAGE_UPDATE; 936 mState = DECODE_IMAGE_UPDATE;
880 mImageWorker = new LLImageWorker(mFormattedImage, image_priority, discard, new DecodeResponder(mFetcher, mID, this)); 937 mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux,
881 // fall though (need to call requestDecodedData() to start work) 938 new DecodeResponder(mFetcher, mID, this));
939 // fall though
882 } 940 }
883 941
884 if (mState == DECODE_IMAGE_UPDATE) 942 if (mState == DECODE_IMAGE_UPDATE)
885 { 943 {
886 if (decodeImage()) 944 if (mDecoded)
887 { 945 {
888 if (mDecodedDiscard < 0) 946 if (mDecodedDiscard < 0)
889 { 947 {
@@ -891,6 +949,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
891 { 949 {
892 // Cache file should be deleted, try again 950 // Cache file should be deleted, try again
893// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl; 951// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl;
952 llassert_always(mDecodeHandle == 0);
894 mFormattedImage = NULL; 953 mFormattedImage = NULL;
895 ++mRetryAttempt; 954 ++mRetryAttempt;
896 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 955 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
@@ -918,9 +977,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
918 977
919 if (mState == WRITE_TO_CACHE) 978 if (mState == WRITE_TO_CACHE)
920 { 979 {
921 if (mInLocalCache || !mFileSize || mSentRequest == UNSENT) 980 if (mInLocalCache || mSentRequest == UNSENT || mFormattedImage.isNull())
922 { 981 {
923 // If we're in a local cache or we didn't actually receive any new data, skip 982 // If we're in a local cache or we didn't actually receive any new data,
983 // or we failed to load anything, skip
924 mState = DONE; 984 mState = DONE;
925 return false; 985 return false;
926 } 986 }
@@ -979,10 +1039,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
979// Called from MAIN thread 1039// Called from MAIN thread
980void LLTextureFetchWorker::endWork(S32 param, bool aborted) 1040void LLTextureFetchWorker::endWork(S32 param, bool aborted)
981{ 1041{
982 if (mImageWorker) 1042 if (mDecodeHandle != 0)
983 { 1043 {
984 mImageWorker->scheduleDelete(); 1044 mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
985 mImageWorker = NULL; 1045 mDecodeHandle = 0;
986 } 1046 }
987 mFormattedImage = NULL; 1047 mFormattedImage = NULL;
988} 1048}
@@ -1035,7 +1095,7 @@ bool LLTextureFetchWorker::deleteOK()
1035 1095
1036 if ((haveWork() && 1096 if ((haveWork() &&
1037 // not ok to delete from these states 1097 // not ok to delete from these states
1038 ((mState >= LOAD_FROM_HTTP_GET_URL && mState <= LOAD_FROM_HTTP_GET_DATA) || 1098 ((mState >= SEND_HTTP_REQ && mState <= WAIT_HTTP_REQ) ||
1039 (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE)))) 1099 (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
1040 { 1100 {
1041 delete_ok = false; 1101 delete_ok = false;
@@ -1044,7 +1104,6 @@ bool LLTextureFetchWorker::deleteOK()
1044 return delete_ok; 1104 return delete_ok;
1045} 1105}
1046 1106
1047
1048void LLTextureFetchWorker::removeFromCache() 1107void LLTextureFetchWorker::removeFromCache()
1049{ 1108{
1050 if (!mInLocalCache) 1109 if (!mInLocalCache)
@@ -1061,6 +1120,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()
1061 if (mFormattedImage.isNull() || mRequestedSize < 0) 1120 if (mFormattedImage.isNull() || mRequestedSize < 0)
1062 { 1121 {
1063 // not sure how we got here, but not a valid state, abort! 1122 // not sure how we got here, but not a valid state, abort!
1123 llassert_always(mDecodeHandle == 0);
1064 mFormattedImage = NULL; 1124 mFormattedImage = NULL;
1065 return true; 1125 return true;
1066 } 1126 }
@@ -1074,6 +1134,12 @@ bool LLTextureFetchWorker::processSimulatorPackets()
1074 buffer_size += mPackets[i]->mSize; 1134 buffer_size += mPackets[i]->mSize;
1075 } 1135 }
1076 bool have_all_data = mLastPacket >= mTotalPackets-1; 1136 bool have_all_data = mLastPacket >= mTotalPackets-1;
1137 if (mRequestedSize <= 0)
1138 {
1139 // We received a packed but haven't requested anything yet (edge case)
1140 // Return true (we're "done") since we didn't request anything
1141 return true;
1142 }
1077 if (buffer_size >= mRequestedSize || have_all_data) 1143 if (buffer_size >= mRequestedSize || have_all_data)
1078 { 1144 {
1079 /// We have enough (or all) data 1145 /// We have enough (or all) data
@@ -1109,50 +1175,36 @@ bool LLTextureFetchWorker::processSimulatorPackets()
1109 1175
1110////////////////////////////////////////////////////////////////////////////// 1176//////////////////////////////////////////////////////////////////////////////
1111 1177
1112void LLTextureFetchWorker::callbackURLReceived(const LLSD& data, bool success) 1178void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
1179 const LLIOPipe::buffer_ptr_t& buffer,
1180 bool last_block, bool success)
1113{ 1181{
1114#if 0
1115 LLMutexLock lock(&mWorkMutex); 1182 LLMutexLock lock(&mWorkMutex);
1116 if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_URL)
1117 {
1118 llwarns << "callbackURLReceived for unrequested fetch worker, req="
1119 << mSentRequest << " state= " << mState << llendl;
1120 return;
1121 }
1122 if (success)
1123 {
1124 mURL = data.asString();
1125 }
1126 mLoaded = TRUE;
1127 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
1128#endif
1129}
1130 1183
1131////////////////////////////////////////////////////////////////////////////// 1184 if (mState != WAIT_HTTP_REQ)
1132
1133void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_block)
1134{
1135#if 0
1136 LLMutexLock lock(&mWorkMutex);
1137 if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_DATA)
1138 { 1185 {
1139 llwarns << "callbackHttpGet for unrequested fetch worker, req=" 1186 llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
1140 << mSentRequest << " state= " << mState << llendl; 1187 << " req=" << mSentRequest << " state= " << mState << llendl;
1141 return; 1188 return;
1142 } 1189 }
1143// llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
1144 if (mLoaded) 1190 if (mLoaded)
1145 { 1191 {
1146 llwarns << "Duplicate callback for " << mID.asString() << llendl; 1192 llwarns << "Duplicate callback for " << mID.asString() << llendl;
1147 return; // ignore duplicate callback 1193 return; // ignore duplicate callback
1148 } 1194 }
1149 if (data_size >= 0) 1195 if (success)
1150 { 1196 {
1197 // get length of stream:
1198 S32 data_size = buffer->countAfter(channels.in(), NULL);
1199
1200 gImageList.sTextureBits += data_size * 8; // Approximate - does not include header bits
1201
1202 //llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
1151 if (data_size > 0) 1203 if (data_size > 0)
1152 { 1204 {
1205 // *TODO: set the formatted image data here directly to avoid the copy
1153 mBuffer = new U8[data_size]; 1206 mBuffer = new U8[data_size];
1154 // *TODO: set the formatted image data here 1207 buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
1155 memcpy(mBuffer, data, data_size);
1156 mBufferSize += data_size; 1208 mBufferSize += data_size;
1157 if (data_size < mRequestedSize || last_block == true) 1209 if (data_size < mRequestedSize || last_block == true)
1158 { 1210 {
@@ -1160,10 +1212,11 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
1160 } 1212 }
1161 else if (data_size > mRequestedSize) 1213 else if (data_size > mRequestedSize)
1162 { 1214 {
1163 // *TODO: This will happen until we fix LLCurl::getByteRange() 1215 // *TODO: This shouldn't be happening any more
1164// llinfos << "HUH?" << llendl; 1216 llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
1165 mHaveAllData = TRUE; 1217 mHaveAllData = TRUE;
1166 mFormattedImage->deleteData(); 1218 llassert_always(mDecodeHandle == 0);
1219 mFormattedImage = NULL; // discard any previous data we had
1167 mBufferSize = data_size; 1220 mBufferSize = data_size;
1168 } 1221 }
1169 } 1222 }
@@ -1181,7 +1234,6 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
1181 } 1234 }
1182 mLoaded = TRUE; 1235 mLoaded = TRUE;
1183 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 1236 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
1184#endif
1185} 1237}
1186 1238
1187////////////////////////////////////////////////////////////////////////////// 1239//////////////////////////////////////////////////////////////////////////////
@@ -1197,7 +1249,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima
1197 } 1249 }
1198 if (success) 1250 if (success)
1199 { 1251 {
1200 llassert_always(imagesize > 0); 1252 llassert_always(imagesize >= 0);
1201 mFileSize = imagesize; 1253 mFileSize = imagesize;
1202 mFormattedImage = image; 1254 mFormattedImage = image;
1203 mImageCodec = image->getCodec(); 1255 mImageCodec = image->getCodec();
@@ -1225,65 +1277,49 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success)
1225 1277
1226////////////////////////////////////////////////////////////////////////////// 1278//////////////////////////////////////////////////////////////////////////////
1227 1279
1228void LLTextureFetchWorker::callbackDecoded(bool success) 1280void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux)
1229{ 1281{
1282 LLMutexLock lock(&mWorkMutex);
1283 if (mDecodeHandle == 0)
1284 {
1285 return; // aborted, ignore
1286 }
1230 if (mState != DECODE_IMAGE_UPDATE) 1287 if (mState != DECODE_IMAGE_UPDATE)
1231 { 1288 {
1232// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl; 1289// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl;
1290 mDecodeHandle = 0;
1233 return; 1291 return;
1234 } 1292 }
1235// llinfos << mID << " : DECODE COMPLETE " << llendl; 1293 llassert_always(mFormattedImage.notNull());
1236 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 1294
1237} 1295 mDecodeHandle = 0;
1238 1296 if (success)
1239//////////////////////////////////////////////////////////////////////////////
1240
1241bool LLTextureFetchWorker::decodeImage()
1242{
1243 if(!mImageWorker)
1244 {
1245 //LLTextureFetchWorker is aborted, skip image decoding.
1246 return true ;
1247 }
1248
1249 bool res = true;
1250 if (mRawImage.isNull())
1251 {
1252 res = false;
1253 if (mImageWorker->requestDecodedData(mRawImage, -1))
1254 {
1255 res = true;
1256// llinfos << mID << " : BASE DECODE FINISHED" << llendl;
1257 }
1258 }
1259 if (res &&
1260 (mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
1261 (mNeedsAux && mAuxImage.isNull()))
1262 { 1297 {
1263 res = false; 1298 mRawImage = raw;
1264 if (mImageWorker->requestDecodedAuxData(mAuxImage, 4, -1)) 1299 mAuxImage = aux;
1265 { 1300 mDecodedDiscard = mFormattedImage->getDiscardLevel();
1266 res = true; 1301// llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
1267// llinfos << mID << " : AUX DECODE FINISHED" << llendl;
1268 }
1269 } 1302 }
1270 if (res) 1303 else
1271 { 1304 {
1272 if ((mRawImage.notNull() && mRawImage->getDataSize() > 0) && 1305 if (mFormattedImage.notNull())
1273 (!mNeedsAux || (mAuxImage.notNull() && mAuxImage->getDataSize() > 0)))
1274 { 1306 {
1275 mDecodedDiscard = mFormattedImage->getDiscardLevel(); 1307 LL_WARNS("http-texture") << "DECODE FAILED: id = " << mID << ", Discard = " << (S32)mFormattedImage->getDiscardLevel() << LL_ENDL;
1276// llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
1277 } 1308 }
1278 else 1309 else
1279 { 1310 {
1280// llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl; 1311 LL_WARNS("http-texture") << "DECODE FAILED: id = " << mID << ", mFormattedImage is Null!" << LL_ENDL;
1281 removeFromCache();
1282 } 1312 }
1283 mImageWorker->scheduleDelete(); 1313 removeFromCache();
1284 mImageWorker = NULL; 1314 mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
1285 } 1315 }
1286 return res; 1316 mDecoded = TRUE;
1317// llinfos << mID << " : DECODE COMPLETE " << llendl;
1318 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
1319 // Set the decode flag at the end of the callback or we trigger race conditions between the fetch thread and the
1320 // decode threads that's calling this callback. The fetch thread might set mFormattedImage to NULL before we
1321 // have time here to call getDiscardLevel() which causes crashes
1322 mDecoded = TRUE;
1287} 1323}
1288 1324
1289////////////////////////////////////////////////////////////////////////////// 1325//////////////////////////////////////////////////////////////////////////////
@@ -1314,15 +1350,21 @@ bool LLTextureFetchWorker::writeToCacheComplete()
1314////////////////////////////////////////////////////////////////////////////// 1350//////////////////////////////////////////////////////////////////////////////
1315// public 1351// public
1316 1352
1317LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded) 1353LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded)
1318 : LLWorkerThread("TextureFetch", threaded), 1354 : LLWorkerThread("TextureFetch", threaded),
1319 mDebugCount(0), 1355 mDebugCount(0),
1320 mDebugPause(FALSE), 1356 mDebugPause(FALSE),
1321 mPacketCount(0), 1357 mPacketCount(0),
1322 mBadPacketCount(0), 1358 mBadPacketCount(0),
1323 mQueueMutex(getAPRPool()), 1359 mQueueMutex(getAPRPool()),
1324 mTextureCache(cache) 1360 mNetworkQueueMutex(getAPRPool()),
1361 mTextureCache(cache),
1362 mImageDecodeThread(imagedecodethread),
1363 mTextureBandwidth(0),
1364 mCurlGetRequest(NULL)
1325{ 1365{
1366 mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
1367 mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
1326} 1368}
1327 1369
1328LLTextureFetch::~LLTextureFetch() 1370LLTextureFetch::~LLTextureFetch()
@@ -1330,13 +1372,7 @@ LLTextureFetch::~LLTextureFetch()
1330 // ~LLQueuedThread() called here 1372 // ~LLQueuedThread() called here
1331} 1373}
1332 1374
1333bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 priority, 1375bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
1334 S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
1335{
1336 return createRequest(LLStringUtil::null, id, host, priority, w, h, c, desired_discard, needs_aux);
1337}
1338
1339bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
1340 S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux) 1376 S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
1341{ 1377{
1342 if (mDebugPause) 1378 if (mDebugPause)
@@ -1361,7 +1397,14 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
1361 } 1397 }
1362 1398
1363 S32 desired_size; 1399 S32 desired_size;
1364 if (desired_discard == 0) 1400 std::string exten = gDirUtilp->getExtension(url);
1401 if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
1402 {
1403 // Only do partial requests for J2C at the moment
1404 //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl;
1405 desired_size = MAX_IMAGE_DATA_SIZE;
1406 }
1407 else if (desired_discard == 0)
1365 { 1408 {
1366 // if we want the entire image, and we know its size, then get it all 1409 // if we want the entire image, and we know its size, then get it all
1367 // (calcDataSizeJ2C() below makes assumptions about how the image 1410 // (calcDataSizeJ2C() below makes assumptions about how the image
@@ -1389,28 +1432,25 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
1389 { 1432 {
1390 return false; // need to wait for previous aborted request to complete 1433 return false; // need to wait for previous aborted request to complete
1391 } 1434 }
1392 worker->lockWorkData(); 1435 worker->lockWorkMutex();
1393 worker->setImagePriority(priority); 1436 worker->setImagePriority(priority);
1394 worker->setDesiredDiscard(desired_discard, desired_size); 1437 worker->setDesiredDiscard(desired_discard, desired_size);
1395 worker->unlockWorkData(); 1438 worker->unlockWorkMutex();
1396 if (!worker->haveWork()) 1439 if (!worker->haveWork())
1397 { 1440 {
1441 worker->lockWorkMutex();
1442 if (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK || worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
1443 {
1444 removeFromNetworkQueue(worker, true);
1445 }
1398 worker->mState = LLTextureFetchWorker::INIT; 1446 worker->mState = LLTextureFetchWorker::INIT;
1447 worker->unlockWorkMutex();
1399 worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); 1448 worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
1400 } 1449 }
1401 } 1450 }
1402 else 1451 else
1403 { 1452 {
1404 if (filename.empty()) 1453 worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
1405 {
1406 // do remote fetch
1407 worker = new LLTextureFetchWorker(this, id, host, priority, desired_discard, desired_size);
1408 }
1409 else
1410 {
1411 // do local file fetch
1412 worker = new LLTextureFetchLocalFileWorker(this, filename, id, host, priority, desired_discard, desired_size);
1413 }
1414 mRequestMap[id] = worker; 1454 mRequestMap[id] = worker;
1415 } 1455 }
1416 worker->mActiveCount++; 1456 worker->mActiveCount++;
@@ -1430,10 +1470,9 @@ void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
1430} 1470}
1431 1471
1432// protected 1472// protected
1433
1434// call lockQueue() first!
1435void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker) 1473void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
1436{ 1474{
1475 LLMutexLock lock(&mNetworkQueueMutex);
1437 if (mRequestMap.find(worker->mID) != mRequestMap.end()) 1476 if (mRequestMap.find(worker->mID) != mRequestMap.end())
1438 { 1477 {
1439 // only add to the queue if in the request map 1478 // only add to the queue if in the request map
@@ -1447,10 +1486,27 @@ void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
1447 } 1486 }
1448} 1487}
1449 1488
1450// call lockQueue() first! 1489void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
1451void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker) 1490{
1491 LLMutexLock lock(&mNetworkQueueMutex);
1492 size_t erased = mNetworkQueue.erase(worker->mID);
1493 if (cancel && erased > 0)
1494 {
1495 mCancelQueue[worker->mHost].insert(worker->mID);
1496 }
1497}
1498
1499// protected
1500void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
1501{
1502 LLMutexLock lock(&mNetworkQueueMutex);
1503 mHTTPTextureQueue.insert(id);
1504}
1505
1506void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id)
1452{ 1507{
1453 mNetworkQueue.erase(worker->mID); 1508 LLMutexLock lock(&mNetworkQueueMutex);
1509 mHTTPTextureQueue.erase(id);
1454} 1510}
1455 1511
1456// call lockQueue() first! 1512// call lockQueue() first!
@@ -1458,11 +1514,7 @@ void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
1458{ 1514{
1459 size_t erased_1 = mRequestMap.erase(worker->mID); 1515 size_t erased_1 = mRequestMap.erase(worker->mID);
1460 llassert_always(erased_1 > 0) ; 1516 llassert_always(erased_1 > 0) ;
1461 size_t erased = mNetworkQueue.erase(worker->mID); 1517 removeFromNetworkQueue(worker, cancel);
1462 if (cancel && erased > 0)
1463 {
1464 mCancelQueue[worker->mHost].insert(worker->mID);
1465 }
1466 llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ; 1518 llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
1467 1519
1468 worker->scheduleDelete(); 1520 worker->scheduleDelete();
@@ -1511,7 +1563,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
1511 } 1563 }
1512 else 1564 else
1513 { 1565 {
1514 worker->lockWorkData(); 1566 worker->lockWorkMutex();
1515 if ((worker->mDecodedDiscard >= 0) && 1567 if ((worker->mDecodedDiscard >= 0) &&
1516 (worker->mDecodedDiscard < discard_level || discard_level < 0) && 1568 (worker->mDecodedDiscard < discard_level || discard_level < 0) &&
1517 (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE)) 1569 (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE))
@@ -1521,7 +1573,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
1521 if (worker->mRawImage) raw = worker->mRawImage; 1573 if (worker->mRawImage) raw = worker->mRawImage;
1522 if (worker->mAuxImage) aux = worker->mAuxImage; 1574 if (worker->mAuxImage) aux = worker->mAuxImage;
1523 } 1575 }
1524 worker->unlockWorkData(); 1576 worker->unlockWorkMutex();
1525 } 1577 }
1526 } 1578 }
1527 else 1579 else
@@ -1538,9 +1590,9 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
1538 LLTextureFetchWorker* worker = getWorker(id); 1590 LLTextureFetchWorker* worker = getWorker(id);
1539 if (worker) 1591 if (worker)
1540 { 1592 {
1541 worker->lockWorkData(); 1593 worker->lockWorkMutex();
1542 worker->setImagePriority(priority); 1594 worker->setImagePriority(priority);
1543 worker->unlockWorkData(); 1595 worker->unlockWorkMutex();
1544 res = true; 1596 res = true;
1545 } 1597 }
1546 return res; 1598 return res;
@@ -1548,40 +1600,106 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
1548 1600
1549////////////////////////////////////////////////////////////////////////////// 1601//////////////////////////////////////////////////////////////////////////////
1550 1602
1603// MAIN THREAD
1551//virtual 1604//virtual
1552S32 LLTextureFetch::update(U32 max_time_ms) 1605S32 LLTextureFetch::update(U32 max_time_ms)
1553{ 1606{
1554 S32 res; 1607 S32 res;
1608
1609 mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
1610
1555 res = LLWorkerThread::update(max_time_ms); 1611 res = LLWorkerThread::update(max_time_ms);
1556 1612
1557 const F32 REQUEST_TIME = 1.f; 1613 if (!mDebugPause)
1558
1559 // Periodically, gather the list of textures that need data from the network
1560 // And send the requests out to the simulators
1561 if (mNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME)
1562 { 1614 {
1563 mNetworkTimer.reset();
1564 sendRequestListToSimulators(); 1615 sendRequestListToSimulators();
1565 } 1616 }
1566 1617
1567 return res; 1618 return res;
1568} 1619}
1569 1620
1621// WORKER THREAD
1622void LLTextureFetch::startThread()
1623{
1624 // Construct mCurlGetRequest from Worker Thread
1625 mCurlGetRequest = new LLCurlRequest();
1626}
1627
1628// WORKER THREAD
1629void LLTextureFetch::endThread()
1630{
1631 // Destroy mCurlGetRequest from Worker Thread
1632 delete mCurlGetRequest;
1633 mCurlGetRequest = NULL;
1634}
1635
1636// WORKER THREAD
1637void LLTextureFetch::threadedUpdate()
1638{
1639 llassert_always(mCurlGetRequest);
1640
1641 // Limit update frequency
1642 const F32 PROCESS_TIME = 0.05f;
1643 static LLFrameTimer process_timer;
1644 if (process_timer.getElapsedTimeF32() < PROCESS_TIME)
1645 {
1646 return;
1647 }
1648 process_timer.reset();
1649
1650 // Update Curl on same thread as mCurlGetRequest was constructed
1651 S32 processed = mCurlGetRequest->process();
1652 if (processed > 0)
1653 {
1654 lldebugs << "processed: " << processed << " messages." << llendl;
1655 }
1656
1657#if 0
1658 const F32 INFO_TIME = 1.0f;
1659 static LLFrameTimer info_timer;
1660 if (info_timer.getElapsedTimeF32() >= INFO_TIME)
1661 {
1662 S32 q = mCurlGetRequest->getQueued();
1663 if (q > 0)
1664 {
1665 llinfos << "Queued gets: " << q << llendl;
1666 info_timer.reset();
1667 }
1668 }
1669#endif
1670
1671}
1672
1570////////////////////////////////////////////////////////////////////////////// 1673//////////////////////////////////////////////////////////////////////////////
1571 1674
1572void LLTextureFetch::sendRequestListToSimulators() 1675void LLTextureFetch::sendRequestListToSimulators()
1573{ 1676{
1677 // All requests
1678 const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps
1679
1680 // Sim requests
1574 const S32 IMAGES_PER_REQUEST = 50; 1681 const S32 IMAGES_PER_REQUEST = 50;
1575 const F32 LAZY_FLUSH_TIMEOUT = 15.f; // 10.0f // temp 1682 const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
1576 const F32 MIN_REQUEST_TIME = 1.0f; 1683 const F32 MIN_REQUEST_TIME = 1.0f;
1577 const F32 MIN_DELTA_PRIORITY = 1000.f; 1684 const F32 MIN_DELTA_PRIORITY = 1000.f;
1578 1685
1579 LLMutexLock lock(&mQueueMutex); 1686 // Periodically, gather the list of textures that need data from the network
1687 // And send the requests out to the simulators
1688 static LLFrameTimer timer;
1689 if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME)
1690 {
1691 return;
1692 }
1693 timer.reset();
1580 1694
1695 LLMutexLock lock(&mQueueMutex);
1696
1581 // Send requests 1697 // Send requests
1582 typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t; 1698 typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t;
1583 typedef std::map< LLHost, request_list_t > work_request_map_t; 1699 typedef std::map< LLHost, request_list_t > work_request_map_t;
1584 work_request_map_t requests; 1700 work_request_map_t requests;
1701 {
1702 LLMutexLock lock2(&mNetworkQueueMutex);
1585 for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); ) 1703 for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); )
1586 { 1704 {
1587 queue_t::iterator curiter = iter++; 1705 queue_t::iterator curiter = iter++;
@@ -1591,65 +1709,66 @@ void LLTextureFetch::sendRequestListToSimulators()
1591 mNetworkQueue.erase(curiter); 1709 mNetworkQueue.erase(curiter);
1592 continue; // paranoia 1710 continue; // paranoia
1593 } 1711 }
1712 llassert(req->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK || LLTextureFetchWorker::LOAD_FROM_SIMULATOR);
1713 if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) &&
1714 (req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR))
1715 {
1716 // We really should never ever get here anymore.
1717 llwarns << "SNOW-119 failure: Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl;
1718 mNetworkQueue.erase(curiter);
1719 continue;
1720 }
1594 if (req->mID == mDebugID) 1721 if (req->mID == mDebugID)
1595 { 1722 {
1596 mDebugCount++; // for setting breakpoints 1723 mDebugCount++; // for setting breakpoints
1597 } 1724 }
1598 if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1) 1725 if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM &&
1726 req->mTotalPackets > 0 &&
1727 req->mLastPacket >= req->mTotalPackets-1)
1599 { 1728 {
1600 // We have all the packets... make sure this is high priority 1729 // We have all the packets... make sure this is high priority
1601// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority); 1730// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority);
1602 continue; 1731 continue;
1603 } 1732 }
1604 F32 elapsed = req->mRequestedTimer.getElapsedTimeF32(); 1733 F32 elapsed = req->mRequestedTimer.getElapsedTimeF32();
1605 F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
1606 if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
1607 (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
1608 (elapsed >= LAZY_FLUSH_TIMEOUT))
1609 { 1734 {
1610 requests[req->mHost].insert(req); 1735 F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
1736 if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
1737 (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
1738 (elapsed >= SIM_LAZY_FLUSH_TIMEOUT))
1739 {
1740 requests[req->mHost].insert(req);
1741 }
1611 } 1742 }
1612 } 1743 }
1613
1614 std::string http_url;
1615#if 0
1616 if (gSavedSettings.getBOOL("ImagePipelineUseHTTP"))
1617 {
1618 LLViewerRegion* region = gAgent.getRegion();
1619 if (region)
1620 {
1621 http_url = region->getCapability("RequestTextureDownload");
1622 }
1623 } 1744 }
1624#endif 1745
1625
1626 for (work_request_map_t::iterator iter1 = requests.begin(); 1746 for (work_request_map_t::iterator iter1 = requests.begin();
1627 iter1 != requests.end(); ++iter1) 1747 iter1 != requests.end(); ++iter1)
1628 { 1748 {
1629 bool use_http = http_url.empty() ? false : true;
1630 LLHost host = iter1->first; 1749 LLHost host = iter1->first;
1631 // invalid host = use agent host 1750 // invalid host = use agent host
1632 if (host == LLHost::invalid) 1751 if (host == LLHost::invalid)
1633 { 1752 {
1634 host = gAgent.getRegionHost(); 1753 host = gAgent.getRegionHost();
1635 } 1754 }
1636 else
1637 {
1638 use_http = false;
1639 }
1640 1755
1641 if (use_http) 1756 S32 sim_request_count = 0;
1642 { 1757
1643 } 1758 for (request_list_t::iterator iter2 = iter1->second.begin();
1644 else 1759 iter2 != iter1->second.end(); ++iter2)
1645 { 1760 {
1646 S32 request_count = 0; 1761 LLTextureFetchWorker* req = *iter2;
1647 for (request_list_t::iterator iter2 = iter1->second.begin(); 1762 if (gMessageSystem)
1648 iter2 != iter1->second.end(); ++iter2)
1649 { 1763 {
1650 LLTextureFetchWorker* req = *iter2; 1764 if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM)
1651 req->mSentRequest = LLTextureFetchWorker::SENT_SIM; 1765 {
1652 if (0 == request_count) 1766 // Initialize packet data based on data read from cache
1767 req->lockWorkMutex();
1768 req->setupPacketData();
1769 req->unlockWorkMutex();
1770 }
1771 if (0 == sim_request_count)
1653 { 1772 {
1654 gMessageSystem->newMessageFast(_PREHASH_RequestImage); 1773 gMessageSystem->newMessageFast(_PREHASH_RequestImage);
1655 gMessageSystem->nextBlockFast(_PREHASH_AgentData); 1774 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -1666,30 +1785,42 @@ void LLTextureFetch::sendRequestListToSimulators()
1666// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard 1785// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
1667// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl; 1786// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
1668 1787
1669 req->lockWorkData(); 1788 if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
1789 {
1790 mTextureInfo.setRequestStartTime(req->mID, LLTimer::getTotalTime());
1791 mTextureInfo.setRequestOffset(req->mID, 0);
1792 mTextureInfo.setRequestSize(req->mID, 0);
1793 mTextureInfo.setRequestType(req->mID, LLTextureInfoDetails::REQUEST_TYPE_UDP);
1794 }
1795
1796 req->lockWorkMutex();
1797 req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
1670 req->mSimRequestedDiscard = req->mDesiredDiscard; 1798 req->mSimRequestedDiscard = req->mDesiredDiscard;
1671 req->mRequestedPriority = req->mImagePriority; 1799 req->mRequestedPriority = req->mImagePriority;
1672 req->mRequestedTimer.reset(); 1800 req->mRequestedTimer.reset();
1673 req->unlockWorkData(); 1801 req->unlockWorkMutex();
1674 request_count++; 1802 sim_request_count++;
1675 if (request_count >= IMAGES_PER_REQUEST) 1803 if (sim_request_count >= IMAGES_PER_REQUEST)
1676 { 1804 {
1677// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; 1805// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
1806
1678 gMessageSystem->sendSemiReliable(host, NULL, NULL); 1807 gMessageSystem->sendSemiReliable(host, NULL, NULL);
1679 request_count = 0; 1808 sim_request_count = 0;
1680 } 1809 }
1681 } 1810 }
1682 if (request_count > 0 && request_count < IMAGES_PER_REQUEST) 1811 }
1683 { 1812 if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST)
1684// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; 1813 {
1685 gMessageSystem->sendSemiReliable(host, NULL, NULL); 1814// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
1686 request_count = 0; 1815 gMessageSystem->sendSemiReliable(host, NULL, NULL);
1687 } 1816 sim_request_count = 0;
1688 } 1817 }
1689 } 1818 }
1690 1819
1691 // Send cancelations 1820 // Send cancelations
1692 if (!mCancelQueue.empty()) 1821 {
1822 LLMutexLock lock2(&mNetworkQueueMutex);
1823 if (gMessageSystem && !mCancelQueue.empty())
1693 { 1824 {
1694 for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); 1825 for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
1695 iter1 != mCancelQueue.end(); ++iter1) 1826 iter1 != mCancelQueue.end(); ++iter1)
@@ -1732,6 +1863,7 @@ void LLTextureFetch::sendRequestListToSimulators()
1732 } 1863 }
1733 mCancelQueue.clear(); 1864 mCancelQueue.clear();
1734 } 1865 }
1866 }
1735} 1867}
1736 1868
1737////////////////////////////////////////////////////////////////////////////// 1869//////////////////////////////////////////////////////////////////////////////
@@ -1773,16 +1905,20 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
1773{ 1905{
1774 LLMutexLock lock(&mQueueMutex); 1906 LLMutexLock lock(&mQueueMutex);
1775 LLTextureFetchWorker* worker = getWorker(id); 1907 LLTextureFetchWorker* worker = getWorker(id);
1776 bool res = true;
1777 1908
1778 ++mPacketCount; 1909 ++mPacketCount;
1779 1910
1780 if (!worker) 1911 if (!worker)
1781 { 1912 {
1782// llwarns << "Received header for non active worker: " << id << llendl; 1913// llwarns << "Received header for non active worker: " << id << llendl;
1783 res = false; 1914 ++mBadPacketCount;
1915 mCancelQueue[host].insert(id);
1916 return false;
1784 } 1917 }
1785 else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK || 1918
1919 bool res = true;
1920 worker->lockWorkMutex();
1921 if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
1786 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM) 1922 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
1787 { 1923 {
1788// llwarns << "receiveImageHeader for worker: " << id 1924// llwarns << "receiveImageHeader for worker: " << id
@@ -1805,21 +1941,20 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
1805 { 1941 {
1806 ++mBadPacketCount; 1942 ++mBadPacketCount;
1807 mCancelQueue[host].insert(id); 1943 mCancelQueue[host].insert(id);
1808 return false;
1809 } 1944 }
1810 1945 else
1811 worker->lockWorkData(); 1946 {
1812 1947 // Copy header data into image object
1813 // Copy header data into image object 1948 worker->mImageCodec = codec;
1814 worker->mImageCodec = codec; 1949 worker->mTotalPackets = packets;
1815 worker->mTotalPackets = packets; 1950 worker->mFileSize = (S32)totalbytes;
1816 worker->mFileSize = (S32)totalbytes; 1951 llassert_always(totalbytes > 0);
1817 llassert_always(totalbytes > 0); 1952 llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
1818 llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); 1953 res = worker->insertPacket(0, data, data_size);
1819 res = worker->insertPacket(0, data, data_size); 1954 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
1820 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); 1955 worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
1821 worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; 1956 }
1822 worker->unlockWorkData(); 1957 worker->unlockWorkMutex();
1823 return res; 1958 return res;
1824} 1959}
1825 1960
@@ -1853,7 +1988,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
1853 return false; 1988 return false;
1854 } 1989 }
1855 1990
1856 worker->lockWorkData(); 1991 worker->lockWorkMutex();
1857 1992
1858 res = worker->insertPacket(packet_num, data, data_size); 1993 res = worker->insertPacket(packet_num, data, data_size);
1859 1994
@@ -1866,12 +2001,19 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
1866 else 2001 else
1867 { 2002 {
1868// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id 2003// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
1869// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl; 2004// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
1870 removeFromNetworkQueue(worker); // failsafe
1871 mCancelQueue[host].insert(id);
1872 } 2005 }
1873 2006
1874 worker->unlockWorkData(); 2007 if(packet_num >= (worker->mTotalPackets - 1))
2008 {
2009 if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
2010 {
2011 U64 timeNow = LLTimer::getTotalTime();
2012 mTextureInfo.setRequestSize(id, worker->mFileSize);
2013 mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);
2014 }
2015 }
2016 worker->unlockWorkMutex();
1875 2017
1876 return res; 2018 return res;
1877} 2019}
@@ -1892,7 +2034,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
1892 LLTextureFetchWorker* worker = getWorker(id); 2034 LLTextureFetchWorker* worker = getWorker(id);
1893 if (worker && worker->haveWork()) 2035 if (worker && worker->haveWork())
1894 { 2036 {
1895 worker->lockWorkData(); 2037 worker->lockWorkMutex();
1896 state = worker->mState; 2038 state = worker->mState;
1897 fetch_dtime = worker->mFetchTimer.getElapsedTimeF32(); 2039 fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
1898 request_dtime = worker->mRequestedTimer.getElapsedTimeF32(); 2040 request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
@@ -1909,7 +2051,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
1909 data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize; 2051 data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
1910 } 2052 }
1911 } 2053 }
1912 if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA) 2054 if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
1913 { 2055 {
1914 requested_priority = worker->mRequestedPriority; 2056 requested_priority = worker->mRequestedPriority;
1915 } 2057 }
@@ -1918,7 +2060,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
1918 requested_priority = worker->mImagePriority; 2060 requested_priority = worker->mImagePriority;
1919 } 2061 }
1920 fetch_priority = worker->getPriority(); 2062 fetch_priority = worker->getPriority();
1921 worker->unlockWorkData(); 2063 worker->unlockWorkMutex();
1922 } 2064 }
1923 data_progress_p = data_progress; 2065 data_progress_p = data_progress;
1924 requested_priority_p = requested_priority; 2066 requested_priority_p = requested_priority;
@@ -1944,5 +2086,3 @@ void LLTextureFetch::dump()
1944 } 2086 }
1945} 2087}
1946 2088
1947
1948//////////////////////////////////////////////////////////////////////////////