aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerimage.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:50 -0500
committerJacek Antonelli2008-08-15 23:44:50 -0500
commit89fe5dab825a62a0e3fd8d248cbc91c65eb2a426 (patch)
treebcff14b7888d04a2fec799c59369f6095224bd08 /linden/indra/newview/llviewerimage.cpp
parentSecond Life viewer sources 1.13.3.2 (diff)
downloadmeta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.zip
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.gz
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.bz2
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.xz
Second Life viewer sources 1.14.0.0
Diffstat (limited to 'linden/indra/newview/llviewerimage.cpp')
-rw-r--r--linden/indra/newview/llviewerimage.cpp1581
1 files changed, 374 insertions, 1207 deletions
diff --git a/linden/indra/newview/llviewerimage.cpp b/linden/indra/newview/llviewerimage.cpp
index 7500ada..5a745ae 100644
--- a/linden/indra/newview/llviewerimage.cpp
+++ b/linden/indra/newview/llviewerimage.cpp
@@ -34,11 +34,13 @@
34#include "llmath.h" 34#include "llmath.h"
35#include "llerror.h" 35#include "llerror.h"
36#include "llgl.h" 36#include "llgl.h"
37#include "llglheaders.h"
37#include "llhost.h" 38#include "llhost.h"
38#include "llimage.h" 39#include "llimage.h"
39#include "llimagebmp.h" 40#include "llimagebmp.h"
40#include "llimagej2c.h" 41#include "llimagej2c.h"
41#include "llimagetga.h" 42#include "llimagetga.h"
43#include "llmemtype.h"
42#include "llstl.h" 44#include "llstl.h"
43#include "lltexturetable.h" 45#include "lltexturetable.h"
44#include "llvfile.h" 46#include "llvfile.h"
@@ -47,41 +49,12 @@
47#include "lltimer.h" 49#include "lltimer.h"
48 50
49// viewer includes 51// viewer includes
52#include "lldrawpool.h"
53#include "lltexturefetch.h"
50#include "llviewerimagelist.h" 54#include "llviewerimagelist.h"
51#include "llviewercontrol.h" 55#include "llviewercontrol.h"
52#include "viewer.h"
53#include "llglheaders.h"
54#include "pipeline.h" 56#include "pipeline.h"
55#include "lldrawpool.h" 57#include "viewer.h"
56
57const S32 IMAGE_HEADER_SIZE = 27;
58const S32 PACKET_HEADER_SIZE = 4;
59
60///////////////////////////////////////////////////////////////////////////////
61
62class LLViewerImagePacket
63{
64public:
65 LLViewerImagePacket(U8 *data, U16 data_size, U16 packet_num, BOOL wrote_to_disk)
66 {
67 mData = data;
68 mDataSize = data_size;
69 mPacketNum = packet_num;
70 mWroteToDisk = wrote_to_disk;
71 }
72
73 ~LLViewerImagePacket()
74 {
75 delete[] mData;
76 }
77
78public:
79 U8 *mData;
80 U16 mDataSize;
81 U16 mPacketNum;
82 BOOL mWroteToDisk;
83};
84
85 58
86/////////////////////////////////////////////////////////////////////////////// 59///////////////////////////////////////////////////////////////////////////////
87 60
@@ -95,6 +68,8 @@ LLPointer<LLImageGL> LLViewerImage::sNullImagep = NULL;
95S32 LLViewerImage::sImageCount = 0; 68S32 LLViewerImage::sImageCount = 0;
96LLTimer LLViewerImage::sEvaluationTimer; 69LLTimer LLViewerImage::sEvaluationTimer;
97F32 LLViewerImage::sDesiredDiscardBias = 0.f; 70F32 LLViewerImage::sDesiredDiscardBias = 0.f;
71static F32 sDesiredDiscardBiasMin = -2.0f; // -max number of levels to improve image quality by
72static F32 sDesiredDiscardBiasMax = 1.5f; // max number of levels to reduce image quality by
98F32 LLViewerImage::sDesiredDiscardScale = 1.1f; 73F32 LLViewerImage::sDesiredDiscardScale = 1.1f;
99S32 LLViewerImage::sBoundTextureMemory = 0; 74S32 LLViewerImage::sBoundTextureMemory = 0;
100S32 LLViewerImage::sTotalTextureMemory = 0; 75S32 LLViewerImage::sTotalTextureMemory = 0;
@@ -109,6 +84,43 @@ void LLViewerImage::initClass()
109 LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,3); 84 LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,3);
110 raw->clear(0x77, 0x77, 0x77, 0xFF); 85 raw->clear(0x77, 0x77, 0x77, 0xFF);
111 sNullImagep->createGLTexture(0, raw); 86 sNullImagep->createGLTexture(0, raw);
87
88#if 1
89 LLViewerImage* imagep = new LLViewerImage(IMG_DEFAULT, TRUE);
90 sDefaultImagep = imagep;
91 const S32 dim = 128;
92 LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
93 U8* data = image_raw->getData();
94 for (S32 i = 0; i<dim; i++)
95 {
96 for (S32 j = 0; j<dim; j++)
97 {
98#if 0
99 const S32 border = 2;
100 if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
101 {
102 *data++ = 0xff;
103 *data++ = 0xff;
104 *data++ = 0xff;
105 }
106 else
107#endif
108 {
109 *data++ = 0x7f;
110 *data++ = 0x7f;
111 *data++ = 0x7f;
112 }
113 }
114 }
115 imagep->createGLTexture(0, image_raw);
116 image_raw = NULL;
117 gImageList.addImage(imagep);
118 imagep->dontDiscard();
119#else
120 sDefaultImagep = gImageList.getImage(IMG_DEFAULT, TRUE, TRUE);
121#endif
122 sSmokeImagep = gImageList.getImage(IMG_SMOKE, TRUE, TRUE);
123
112} 124}
113 125
114// static 126// static
@@ -171,6 +183,7 @@ void LLViewerImage::updateClass(const F32 velocity, const F32 angular_velocity)
171 sEvaluationTimer.reset(); 183 sEvaluationTimer.reset();
172 } 184 }
173 } 185 }
186 sDesiredDiscardBias = llclamp(sDesiredDiscardBias, sDesiredDiscardBiasMin, sDesiredDiscardBiasMax);
174} 187}
175 188
176//---------------------------------------------------------------------------- 189//----------------------------------------------------------------------------
@@ -209,35 +222,20 @@ LLViewerImage::LLViewerImage(const LLImageRaw* raw, BOOL usemipmaps)
209 222
210void LLViewerImage::init(bool firstinit) 223void LLViewerImage::init(bool firstinit)
211{ 224{
212 mDataCodec = 0;
213 mFullWidth = 0; 225 mFullWidth = 0;
214 mFullHeight = 0; 226 mFullHeight = 0;
215 mFormattedImagep = NULL;
216 mNeedsAux = FALSE; 227 mNeedsAux = FALSE;
217 mRequested = FALSE;
218 mNeedsDecode = FALSE;
219 mTexelsPerImage = 64.f*64.f; 228 mTexelsPerImage = 64.f*64.f;
220 mMaxVirtualSize = 0.f; 229 mMaxVirtualSize = 0.f;
230 mDiscardVirtualSize = 0.f;
221 mMaxCosAngle = -1.f; 231 mMaxCosAngle = -1.f;
222 mRequestedDiscardLevel = -1; 232 mRequestedDiscardLevel = -1;
223 mRequestedDownloadPriority = 0.f; 233 mRequestedDownloadPriority = 0.f;
224 mPackets = 0;
225 mGotFirstPacket = FALSE;
226 mPacketsReceived = 0;
227 mFullyLoaded = FALSE; 234 mFullyLoaded = FALSE;
228 mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; 235 mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
229 mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; 236 mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
230 mStreamFile = NULL; 237 mCalculatedDiscardLevel = -1.f;
231 mCachedData = NULL;
232 mCachedSize = 0;
233 mFormattedFlushed = FALSE;
234 mTotalBytes = 0;
235 238
236 resetPacketData();
237
238 mLastPacketProcessed = -1;
239 mLastBytesProcessed = 0;
240 mLastPacket = -1;
241 mDecodingAux = FALSE; 239 mDecodingAux = FALSE;
242 240
243 mKnownDrawWidth = 0; 241 mKnownDrawWidth = 0;
@@ -247,7 +245,6 @@ void LLViewerImage::init(bool firstinit)
247 { 245 {
248 mDecodePriority = 0.f; 246 mDecodePriority = 0.f;
249 mInImageList = 0; 247 mInImageList = 0;
250 mInStaticVFS = FALSE;
251 } 248 }
252 mIsMediaTexture = FALSE; 249 mIsMediaTexture = FALSE;
253 250
@@ -261,9 +258,18 @@ void LLViewerImage::init(bool firstinit)
261 258
262 mIsRawImageValid = FALSE; 259 mIsRawImageValid = FALSE;
263 mRawDiscardLevel = INVALID_DISCARD_LEVEL; 260 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
264 mRawImage = NULL; 261 mMinDiscardLevel = 0;
265 262
266 mTargetHost = LLHost::invalid; 263 mTargetHost = LLHost::invalid;
264
265 mHasFetcher = FALSE;
266 mIsFetching = FALSE;
267 mFetchState = 0;
268 mFetchPriority = 0;
269 mDownloadProgress = 0.f;
270 mFetchDeltaTime = 999999.f;
271 mDecodeFrame = 0;
272 mVisibleFrame = 0;
267} 273}
268 274
269// virtual 275// virtual
@@ -283,6 +289,10 @@ void LLViewerImage::dump()
283 289
284LLViewerImage::~LLViewerImage() 290LLViewerImage::~LLViewerImage()
285{ 291{
292 if (mHasFetcher)
293 {
294 gTextureFetch->deleteRequest(getID(), true);
295 }
286 // Explicitly call LLViewerImage::cleanup since we're in a destructor and cleanup is virtual 296 // Explicitly call LLViewerImage::cleanup since we're in a destructor and cleanup is virtual
287 LLViewerImage::cleanup(); 297 LLViewerImage::cleanup();
288 sImageCount--; 298 sImageCount--;
@@ -304,27 +314,9 @@ void LLViewerImage::cleanup()
304 } 314 }
305 mLoadedCallbackList.clear(); 315 mLoadedCallbackList.clear();
306 316
307 // Clean up any remaining packet data.
308 std::for_each(mReceivedPacketMap.begin(), mReceivedPacketMap.end(), DeletePairedPointer());
309 mReceivedPacketMap.clear();
310
311 // Clean up the streaming file
312 if (mStreamFile && !mStreamFile->isReadComplete())
313 {
314// llwarns << "Destroying LLViewerImage stream file while still reading data!" << llendl;
315 }
316 delete mStreamFile;
317 mStreamFile = NULL;
318
319 // Clean up image data 317 // Clean up image data
320 setFormattedImage(NULL); 318 destroyRawImage();
321 mRawImage = NULL;
322 mIsRawImageValid = FALSE;
323 mAuxRawImage = NULL;
324 319
325 delete[] mCachedData;
326 mCachedData = NULL;
327
328 // LLImageGL::cleanup will get called more than once when this is used in the destructor. 320 // LLImageGL::cleanup will get called more than once when this is used in the destructor.
329 LLImageGL::cleanup(); 321 LLImageGL::cleanup();
330} 322}
@@ -335,128 +327,25 @@ void LLViewerImage::reinit(BOOL usemipmaps /* = TRUE */)
335 LLImageGL::init(usemipmaps); 327 LLImageGL::init(usemipmaps);
336 init(false); 328 init(false);
337 setSize(0,0,0); 329 setSize(0,0,0);
338 if (mInStaticVFS)
339 {
340 mFormattedFlushed = TRUE;
341 }
342} 330}
343 331
344/////////////////////////////////////////////////////////////////////////////// 332///////////////////////////////////////////////////////////////////////////////
345 333
346void LLViewerImage::setFormattedImage(LLImageFormatted* imagep) 334// ONLY called from LLViewerImageList
347{
348 mFormattedImagep = NULL; // deletes image
349 mFormattedImagep = imagep;
350 if (mFormattedImagep.notNull())
351 {
352 mFormattedImagep->mMemType = LLMemType::MTYPE_APPFMTIMAGE;
353 mFormattedFlushed = FALSE;
354 }
355 else
356 {
357 setNeedsDecode(FALSE);
358 }
359}
360
361BOOL LLViewerImage::loadLocalImage(const LLUUID &image_id)
362{
363 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
364
365 // first look for this image in the static VFS
366 LLAssetType::EType asset_type = LLAssetType::AT_NONE;
367 // Try TGA first
368 if (gStaticVFS->getExists(image_id, LLAssetType::AT_TEXTURE_TGA))
369 {
370 asset_type = LLAssetType::AT_TEXTURE_TGA;
371 //RN: force disable discards for TGA files because they can't decode at different quality levels
372 dontDiscard();
373 mDataCodec = IMG_CODEC_TGA;
374 }
375 else if (gStaticVFS->getExists(image_id, LLAssetType::AT_TEXTURE))
376 {
377 // then try for a J2C version
378 asset_type = LLAssetType::AT_TEXTURE;
379 mDataCodec = IMG_CODEC_J2C;
380 LLImageJ2C* imagej2c = new LLImageJ2C();
381 setFormattedImage(imagej2c);
382 }
383
384 if (asset_type != LLAssetType::AT_NONE)
385 {
386 S32 size = gStaticVFS->getSize(image_id, asset_type);
387 U8* buffer = new U8[size];
388 BOOL success = LLVFSThread::sLocal->readImmediate(gStaticVFS, image_id, asset_type, buffer, 0, size);
389
390 if (!success)
391 {
392 llwarns << "loadLocalImage() - vfs read failed" << llendl;
393 return FALSE;
394 }
395
396 mInStaticVFS = TRUE;
397 mFullyLoaded = TRUE;
398 setNeedsDecode(TRUE); // Loading a local image
399 mID = image_id;
400 setDecodeData(buffer, size);
401 mTotalBytes = size;
402 mLastBytesProcessed = size;
403 return TRUE;
404 }
405
406 return FALSE;
407}
408
409BOOL LLViewerImage::startVFSLoad()
410{
411 // We're no longer considered "flushed" no matter what happens after here.
412 mFormattedFlushed = FALSE;
413 if (!mStreamFile && mFormattedImagep.isNull())
414 {
415 // Start load from VFS if it's there
416 if (gVFS->getExists(mID, LLAssetType::AT_TEXTURE))
417 {
418// llinfos << "Reading image from disk " << getID() << llendl;
419
420 //llinfos << mID << ": starting VFS load" << llendl;
421 mStreamFile = new LLVFile(gVFS, mID, LLAssetType::AT_TEXTURE, LLVFile::READ_WRITE);
422 mCachedSize = 0;
423 gImageList.mLoadingStreamList.push_back(this);
424 }
425 else
426 {
427 return loadLocalImage(mID);
428 }
429 }
430 return TRUE;
431}
432
433void LLViewerImage::startImageDecode()
434{
435 // We need to load and/or decode the image
436 if (mFormattedImagep.isNull())
437 {
438 startVFSLoad(); // Start the VFS loading
439 }
440 else
441 {
442 setNeedsDecode(TRUE); // Force a new decode of this texture
443 }
444}
445
446
447BOOL LLViewerImage::createTexture(S32 usename/*= 0*/) 335BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
448{ 336{
449 if (mFormattedImagep.notNull() && mFormattedImagep->isDecoding()) 337 if (!mNeedsCreateTexture)
450 { 338 {
451 llerrs << "Trying to create texture on an image that is currently being decoded: " << mID << llendl; 339 destroyRawImage();
340 return FALSE;
452 } 341 }
453 mNeedsCreateTexture = FALSE; 342 mNeedsCreateTexture = FALSE;
454 if (mRawImage.isNull()) 343 if (mRawImage.isNull())
455 { 344 {
456 llerrs << "LLViewerImage trying to create texture with no Raw Image" << llendl; 345 llerrs << "LLViewerImage trying to create texture with no Raw Image" << llendl;
457 } 346 }
458// llinfos << llformat("IMAGE Creating (%d,%d) [%d x %d] Bytes: %d ", 347// llinfos << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ",
459// mRawDiscardLevel, mFormattedImagep ? mFormattedImagep->getDiscardLevel() : -1, 348// mRawDiscardLevel,
460// mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) 349// mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize())
461// << mID.getString() << llendl; 350// << mID.getString() << llendl;
462 BOOL res = TRUE; 351 BOOL res = TRUE;
@@ -471,7 +360,7 @@ BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
471 // A non power-of-two image was uploaded (through a non standard client) 360 // A non power-of-two image was uploaded (through a non standard client)
472 // We treat these images as missing assets which causes them to 361 // We treat these images as missing assets which causes them to
473 // be renderd as 'missing image' and to stop requesting data 362 // be renderd as 'missing image' and to stop requesting data
474 setIsMissingAsset(TRUE); 363 setIsMissingAsset();
475 destroyRawImage(); 364 destroyRawImage();
476 return FALSE; 365 return FALSE;
477 } 366 }
@@ -481,6 +370,7 @@ BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
481 // Iterate through the list of image loading callbacks to see 370 // Iterate through the list of image loading callbacks to see
482 // what sort of data they need. 371 // what sort of data they need.
483 // 372 //
373 // *TODO: Fix image callback code
484 BOOL imageraw_callbacks = FALSE; 374 BOOL imageraw_callbacks = FALSE;
485 for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); 375 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
486 iter != mLoadedCallbackList.end(); ) 376 iter != mLoadedCallbackList.end(); )
@@ -500,292 +390,6 @@ BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
500 return res; 390 return res;
501} 391}
502 392
503BOOL LLViewerImage::destroyTexture()
504{
505 LLImageGL::destroyGLTexture();
506 return TRUE;
507}
508
509void LLViewerImage::resetPacketData()
510{
511 //llinfos << "resetting packet data for " << getID() << llendl;
512 mPackets = 0;
513 mLastPacket = -1;
514 mPacketsReceived = 0;
515 mGotFirstPacket = FALSE;
516 mRequested = FALSE;
517
518 std::for_each(mReceivedPacketMap.begin(), mReceivedPacketMap.end(), DeletePairedPointer());
519 mReceivedPacketMap.clear();
520 mLastPacketProcessed = -1;
521}
522
523////////////////////////////////////////////////////////////////////////////////
524// This sets up a new formatted image at the requested size, and sets the decode flag
525void LLViewerImage::setDecodeData(U8 * data, U32 size)
526{
527 if (size == mTotalBytes)
528 {
529 mFullyLoaded = TRUE;
530 }
531 if (mDataCodec == IMG_CODEC_J2C)
532 {
533 //Codec 2 = compressed with JPEG2000 (Wavelet)
534 // Create formatted image first, then use it to generate the
535 // raw image.
536 if (mFormattedImagep.isNull())
537 {
538 LLPointer<LLImageJ2C> j2cp = new LLImageJ2C();
539 setFormattedImage(j2cp);
540 }
541 BOOL res = mFormattedImagep->setData(data, size);
542 if (mFullyLoaded)
543 {
544 mFormattedImagep->setDiscardLevel(0); // Force full res if all data is loaded
545 }
546 if ((mFormattedImagep->getWidth() > MAX_IMAGE_SIZE_DEFAULT ||
547 mFormattedImagep->getHeight() > MAX_IMAGE_SIZE_DEFAULT) &&
548 (mFormattedImagep->getDiscardLevel() == 0))
549 {
550 mFormattedImagep->setDiscardLevel(1); // Force x2048 images to x1024
551 }
552
553 if( res )
554 {
555 if (mFormattedImagep->getComponents() > 4)
556 {
557 mNeedsAux = TRUE;
558 }
559 else
560 {
561 mNeedsAux = FALSE;
562 }
563 mFullWidth = mFormattedImagep->getWidth();
564 mFullHeight = mFormattedImagep->getHeight();
565 if ((mFullWidth == 0) || (mFullHeight == 0))
566 {
567 llwarns << "Zero size width/height!" << llendl;
568 }
569 setNeedsDecode(TRUE); // Setting new formatted data
570 }
571 else
572 {
573 llwarns << "Unable to setData() for image " << mID << " Aborting." << llendl;
574 abortDecode();
575 }
576 }
577 else if (mDataCodec == IMG_CODEC_TGA)
578 {
579 //Codec 4 = compressed with TGA
580 // Create formatted image first, then use it to generate the
581 // raw image.
582 if (mFormattedImagep.isNull())
583 {
584 LLPointer<LLImageTGA> tgap = new LLImageTGA();
585 setFormattedImage(tgap);
586 }
587 BOOL res = mFormattedImagep->setData(data, size);
588
589 if( res )
590 {
591 mFullWidth = mFormattedImagep->getWidth();
592 mFullHeight = mFormattedImagep->getHeight();
593 if ((mFullWidth == 0) || (mFullHeight == 0))
594 {
595 llwarns << "Zero size width/height!" << llendl;
596 }
597 setNeedsDecode(TRUE); // Setting new formatted data
598 }
599 else
600 {
601 llwarns << "Unable to setData() for image " << mID << " Aborting." << llendl;
602 abortDecode();
603 }
604 }
605 else
606 {
607 llerrs << "Image " << mID << ": Unknown codec " << (int)mDataCodec << llendl;
608 setNeedsDecode(FALSE); // Unknown codec
609 }
610}
611
612void LLViewerImage::decodeImage(const F32 decode_time)
613{
614 if (!needsDecode())
615 {
616 return;
617 }
618
619 if (mFormattedImagep.isNull())
620 {
621 llerrs << "Decoding image without formatted data!" << llendl;
622 return;
623 }
624
625 //
626 // Only do a decode if we don't already have an image for this resolution.
627 //
628 if (getTexName() != 0 && getDiscardLevel() <= mFormattedImagep->getDiscardLevel()
629 && !mNeedsAux)
630 {
631 // We already have an image this size or larger
632 setNeedsDecode(FALSE);
633 return;
634 }
635
636 // Partial Decode of J2C images:
637 // If this is the first time we are decoding an image,
638 // make sure we limit the amount of data we decode in order not to stall other decodes
639 if (!mFormattedImagep->isDecoding() && mFormattedImagep->getCodec() == IMG_CODEC_J2C)
640 {
641 LLImageJ2C* j2cp = (LLImageJ2C*)((LLImageFormatted*)mFormattedImagep);
642 const S32 INITIAL_DECODE_SIZE = 2048;
643 if (!mDontDiscard &&
644 getUseMipMaps() &&
645 !mNeedsAux &&
646 getDiscardLevel() < 0 &&
647 mFormattedImagep->getDataSize() > INITIAL_DECODE_SIZE * 2)
648 {
649 j2cp->setMaxBytes(INITIAL_DECODE_SIZE);
650 }
651 else
652 {
653 j2cp->setMaxBytes(0); // In case we set it on a previous decode
654 }
655 }
656
657 //
658 // Decode Image
659 //
660 mLastDecodeTime.reset();
661
662 if (mFormattedImagep->getCodec() == 0)
663 {
664 llerrs << "LLViewerImage::decodeImage: mFormattedImagep->getCodec() == 0" << llendl;
665 }
666
667 //
668 // Decode first 4 channels
669 //
670 // Skip over this if we're already in the process of decoding the aux channel,
671 // that means that we've alredy decoded the base channels of this texture.
672 if (!mDecodingAux)
673 {
674 if (!mFormattedImagep->isDecoding())
675 {
676 mNeedsCreateTexture = FALSE; // Raw is no longer valid
677 destroyRawImage();
678 createRawImage(mFormattedImagep->getDiscardLevel());
679 //llinfos << "starting decode at " << (S32)mFormattedImagep->getDiscardLevel() << " for " << getID() << llendl;
680 }
681 else
682 {
683 llassert(mRawImage.notNull());
684 }
685 if (!mFormattedImagep->decode(mRawImage, decode_time, 0, 4))
686 {
687 if (!mFormattedImagep->isDecoding())
688 {
689 // bogus data, delete and try again
690 llwarns << "Failed to decode " << mID << ":" << gTextureTable.getName(mID) << llendl;
691 abortDecode();
692 destroyRawImage();
693 return;
694 }
695 }
696// llinfos << llformat("IMAGE Decode (%d) ", mFormattedImagep->getDiscardLevel()) << mID << llendl;
697
698 // Get the discard level of the decoded raw image,
699 // which may not match the formatted image discard level if a partial decode was done
700 mRawDiscardLevel = mFormattedImagep->getRawDiscardLevel();
701
702 if (mFormattedImagep->isDecoding())
703 {
704 return; // Not done decoding.
705 }
706 }
707
708 //
709 // If we've finished with the main channels and need to decode the aux, do it now.
710 // Aux buffers contain extra data (e.g. cloth maps)
711 //
712 if (mNeedsAux)
713 {
714 mDecodingAux = TRUE;
715
716 // Create the target raw image for the aux channels
717 if (mAuxRawImage.isNull())
718 {
719 S32 discard = mFormattedImagep->getDiscardLevel();
720 mAuxRawImage = new LLImageRaw(getWidth(discard), getHeight(discard), 1);
721 mAuxRawImage->mMemType = LLMemType::MTYPE_APPAUXRAWIMAGE;
722 }
723
724 if (!mFormattedImagep->decode(mAuxRawImage, decode_time, 4, 4))
725 {
726 if (!mFormattedImagep->isDecoding())
727 {
728 llwarns << "Failed to decode high components " << mID << ":" << gTextureTable.getName(mID) << llendl;
729 abortDecode();
730 destroyRawImage();
731 return; // decode failed; re-request
732 }
733 }
734
735 if (mFormattedImagep->isDecoding())
736 {
737 return; // Not done decoding.
738 }
739
740 mDecodingAux = FALSE;
741 }
742
743 if (mRawImage.notNull() && getComponents() != mRawImage->getComponents())
744 {
745 //
746 // We've changed the number of components (presumably this is after
747 // decoding the first packet of an image), so we need to move any
748 // objects using this pool to a different pool.
749 //
750 mComponents = mRawImage->getComponents();
751 gPipeline.dirtyPoolObjectTextures(this);
752 }
753
754 //
755 // We've decoded this image, and no longer need to.
756 //
757 setNeedsDecode(FALSE); // Done decoding image
758 mIsRawImageValid = TRUE;
759
760 //
761 // We have a raw image, and now we need to push the data
762 // from the raw image into the GL image
763 //
764 llassert(mRawImage.notNull());
765 mNeedsCreateTexture = TRUE;
766
767 // Everything's OK...
768#if LL_DEBUG
769 lldebugst(LLERR_IMAGE) << "Img: ";
770 std::string tex_name = gTextureTable.getName(mID);
771 if (!tex_name.empty())
772 {
773 llcont << tex_name;
774 }
775 else
776 {
777 llcont << mID;
778 }
779 llcont << " Discard level " << (S32)getDiscardLevel();
780 llcont << llendl;
781#endif
782}
783
784bool LLViewerImage::isDecoding()
785{
786 return (mFormattedImagep.notNull() && mFormattedImagep->isDecoding());
787}
788
789//============================================================================ 393//============================================================================
790 394
791void LLViewerImage::addTextureStats(F32 pixel_area, 395void LLViewerImage::addTextureStats(F32 pixel_area,
@@ -868,15 +472,23 @@ void LLViewerImage::processTextureStats()
868 } 472 }
869 else 473 else
870 { 474 {
871 // Guess the required scale factor of the image using pixels per texel.. 475 if ((mCalculatedDiscardLevel >= 0.f) &&
872 // Right now, use a safe 1:1 for the tradeoff - we can adjust this later. 476 (llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f))
873 // Actually, it might be nice to generate a float, so we can prioritize which 477 {
874 // ones we can discard quality levels from. 478 // < 20% change in virtual size = no change in desired discard
875 discard_level = (F32)(log(mTexelsPerImage/mMaxVirtualSize) / log_4); 479 discard_level = mCalculatedDiscardLevel;
480 }
481 else
482 {
483 // Calculate the required scale factor of the image using pixels per texel
484 discard_level = (F32)(log(mTexelsPerImage/mMaxVirtualSize) / log_4);
485 mDiscardVirtualSize = mMaxVirtualSize;
486 mCalculatedDiscardLevel = discard_level;
487 }
876 } 488 }
877 if (mBoostLevel < LLViewerImage::BOOST_HIGH) 489 if (mBoostLevel < LLViewerImage::BOOST_HIGH)
878 { 490 {
879 static const F32 discard_bias = 0.5f; // Must be < 1 or highest discard will never load! 491 static const F32 discard_bias = -.5f; // Must be < 1 or highest discard will never load!
880 discard_level += discard_bias; 492 discard_level += discard_bias;
881 discard_level += sDesiredDiscardBias; 493 discard_level += sDesiredDiscardBias;
882 discard_level *= sDesiredDiscardScale; // scale 494 discard_level *= sDesiredDiscardScale; // scale
@@ -901,94 +513,68 @@ void LLViewerImage::processTextureStats()
901 // proper action if we don't. 513 // proper action if we don't.
902 // 514 //
903 515
904 //
905 // Only need to do an actual decode if we don't have the right GL level,
906 // or we don't have raw data and need raw data.
907 //
908 BOOL increase_discard = FALSE; 516 BOOL increase_discard = FALSE;
909 if (getDiscardLevel() < 0 || mDesiredDiscardLevel < getDiscardLevel()) 517 S32 current_discard = getDiscardLevel();
518 if ((sDesiredDiscardBias > 0.0f) &&
519 (current_discard >= 0 && mDesiredDiscardLevel >= current_discard))
910 { 520 {
911 // We need to do a decode of that discard level to get more data. 521 if ( sBoundTextureMemory > sMaxBoundTextureMem*texmem_middle_bound_scale)
912 if (mFormattedImagep.notNull() && !needsDecode())
913 { 522 {
914 if (mFormattedImagep->getDiscardLevel() <= mDesiredDiscardLevel) 523 // Limit the amount of GL memory bound each frame
524 if (mDesiredDiscardLevel > current_discard)
915 { 525 {
916 setNeedsDecode(TRUE); // processTextureStats - Changing discard level of texture 526 increase_discard = TRUE;
917 } 527 }
918 // else let the llviewerimagelist logic do its thing
919 } 528 }
920 else if (mFormattedFlushed) 529 if ( sTotalTextureMemory > sMaxTotalTextureMem*texmem_middle_bound_scale)
921 { 530 {
922 //llinfos << "Attempting vfs reload (a) of " << mID << llendl; 531 // Only allow GL to have 2x the video card memory
923 startVFSLoad(); 532 if (!getBoundRecently())
924 } 533 {
925 } 534 increase_discard = TRUE;
926 else if (sDesiredDiscardBias > 0.0f && sBoundTextureMemory > sMaxBoundTextureMem*texmem_middle_bound_scale) 535 }
927 {
928 // Limit the amount of GL memory bound each frame
929 if (mDesiredDiscardLevel > getDiscardLevel())
930 {
931 increase_discard = TRUE;
932 } 536 }
933 } 537 if (increase_discard)
934 else if (sDesiredDiscardBias > 0.0f && sTotalTextureMemory > sTotalTextureMemory*texmem_middle_bound_scale)
935 {
936 // Only allow GL to have 2x the video card memory
937 if (!getBoundRecently())
938 { 538 {
939 increase_discard = TRUE; 539 // llinfos << "DISCARDED: " << mID << " Discard: " << current_discard << llendl;
540 sBoundTextureMemory -= mTextureMemory;
541 sTotalTextureMemory -= mTextureMemory;
542 // Increase the discard level (reduce the texture res)
543 S32 new_discard = current_discard+1;
544 setDiscardLevel(new_discard);
545 sBoundTextureMemory += mTextureMemory;
546 sTotalTextureMemory += mTextureMemory;
940 } 547 }
941 } 548 }
942 if (increase_discard)
943 {
944 sBoundTextureMemory -= mTextureMemory;
945 sTotalTextureMemory -= mTextureMemory;
946 // Increase the discard level (reduce the texture res)
947 S32 new_discard = getDiscardLevel()+1;
948 setDiscardLevel(new_discard);
949 sBoundTextureMemory += mTextureMemory;
950 sTotalTextureMemory += mTextureMemory;
951 }
952 } 549 }
953
954 //
955 // Flush the formatted data for this image if it hasn't been used in a while.
956 //
957#if 1
958 const F32 FLUSH_TIME = 30.f;
959 if (mFormattedImagep.notNull())
960 {
961 if ((mLastDecodeTime.getElapsedTimeF32() > FLUSH_TIME)
962 && !mStreamFile
963 && (this->mLastPacketTimer.getElapsedTimeF32() > FLUSH_TIME)
964 && !mNeedsDecode
965 && !mFormattedImagep->isDecoding()
966 && (mDesiredDiscardLevel == getDiscardLevel()))
967 {
968 //llinfos << mID << ": flushing formatted image, last processed packet " << mLastPacketProcessed << llendl;
969 // Treat this very similarly to like we haven't gotten any data
970 // Flush all received packets that haven't been processed, they will be readded on reload.
971 resetPacketData();
972
973 setFormattedImage(NULL);
974 mFullyLoaded = FALSE;
975
976 // This flag says that we may have VFS data if we want to reload this texture
977 // (or get network traffic for this texture)
978 mFormattedFlushed = TRUE;
979 }
980 }
981#endif
982} 550}
983 551
984//============================================================================ 552//============================================================================
985 553
986F32 LLViewerImage::calcDecodePriority() 554F32 LLViewerImage::calcDecodePriority()
987{ 555{
988 F32 priority; 556#ifndef LL_RELEASE_FOR_DOWNLOAD
989 S32 gldiscard = getDiscardLevel(); 557 if (mID == gTextureFetch->mDebugID)
990 S32 ddiscard = gldiscard - mDesiredDiscardLevel; 558 {
559 gTextureFetch->mDebugCount++; // for setting breakpoints
560 }
561#endif
562
563 if (mNeedsCreateTexture)
564 {
565 return mDecodePriority; // no change while waiting to create
566 }
991 567
568 F32 priority;
569 S32 cur_discard = getDiscardLevel();
570 F32 pixel_priority = fsqrtf(mMaxVirtualSize) * (1.f + mMaxCosAngle);
571 const S32 MIN_NOT_VISIBLE_FRAMES = 30; // NOTE: this function is not called every frame
572 mDecodeFrame++;
573 if (pixel_priority > 0.f)
574 {
575 mVisibleFrame = mDecodeFrame;
576 }
577
992 if (mIsMissingAsset) 578 if (mIsMissingAsset)
993 { 579 {
994 priority = 0.0f; 580 priority = 0.0f;
@@ -996,50 +582,73 @@ F32 LLViewerImage::calcDecodePriority()
996 else if (mDesiredDiscardLevel > mMaxDiscardLevel) 582 else if (mDesiredDiscardLevel > mMaxDiscardLevel)
997 { 583 {
998 // Don't decode anything we don't need 584 // Don't decode anything we don't need
999 priority = 0.0f; 585 priority = -1.0f;
586 }
587 else if (pixel_priority <= 0.f && (cur_discard < 0 || mDesiredDiscardLevel < cur_discard))
588 {
589 // Not on screen but we might want some data
590 if (mBoostLevel > BOOST_HIGH)
591 {
592 // Always want high boosted images
593 priority = 1.f;
594 }
595 else if (mVisibleFrame == 0 || (mDecodeFrame - mVisibleFrame > MIN_NOT_VISIBLE_FRAMES))
596 {
597 // Don't decode anything that isn't visible unless it's important
598 priority = -2.0f;
599 }
600 else
601 {
602 // Leave the priority as-is
603 return mDecodePriority;
604 }
1000 } 605 }
1001 else if (gldiscard < 0 && mDesiredDiscardLevel >= 0) 606 else if (cur_discard < 0)
1002 { 607 {
1003 // We don't have any data yet, we need something immideately 608 // We don't have any data yet, so we don't know the size of the image, treat as 1024x1024
1004 priority = 200000.f; 609// priority = 900000.f;
610 static const F64 log_2 = log(2.0);
611 F32 desired = (F32)(log(1024.0/pixel_priority) / log_2);
612 S32 ddiscard = MAX_DISCARD_LEVEL - (S32)desired + 1;
613 ddiscard = llclamp(ddiscard, 1, 9);
614 priority = ddiscard*100000.f;
1005 } 615 }
1006 else if (getDiscardLevel() < 0 && mDesiredDiscardLevel < MAX_DISCARD_LEVEL+1) 616 else if (cur_discard <= mMinDiscardLevel)
1007 { 617 {
1008 // We have data, but haven't decoded any of it yet, but it on top 618 // larger mips are corrupted
1009 priority = 300000.f; 619 priority = -3.0f;
1010 } 620 }
1011 else if (gldiscard <= mDesiredDiscardLevel) 621 else if (cur_discard <= mDesiredDiscardLevel)
1012 { 622 {
1013 priority = 0.0f; 623 priority = -4.0f;
1014 } 624 }
1015 else 625 else
1016 { 626 {
1017 // priority range = 0 - 10000 (10 ^ 4) 627 // priority range = 100000-400000
628 S32 ddiscard = cur_discard - mDesiredDiscardLevel;
1018 if (getDontDiscard()) 629 if (getDontDiscard())
1019 { 630 {
1020 ddiscard+=2; 631 ddiscard+=2;
1021 } 632 }
1022 else if (!getBoundRecently()) 633 else if (!getBoundRecently() && mBoostLevel == 0)
1023 { 634 {
1024 ddiscard-=2; 635 ddiscard-=2;
1025 } 636 }
1026 else
1027 {
1028 ddiscard-=1;
1029 }
1030 ddiscard = llclamp(ddiscard, 0, 4); 637 ddiscard = llclamp(ddiscard, 0, 4);
1031 638 priority = ddiscard*100000.f;
1032 priority = powf(10.f,(F32)ddiscard);
1033 } 639 }
1034 if (priority > 0.0f) 640 if (priority > 0.0f)
1035 { 641 {
1036 F32 pixel_priority = llmin(mMaxVirtualSize * (1.5f + mMaxCosAngle) * (100.f / (1024.f*1024.f)), 100.f);
1037 pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f); 642 pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f);
1038 priority += pixel_priority; 643 priority += pixel_priority;
1039 if ( mBoostLevel > 0) 644 if ( mBoostLevel > BOOST_HIGH)
1040 { 645 {
1041 priority += 1000000.f + 1000.f * mBoostLevel; 646 priority += 1000000.f + 1000.f * mBoostLevel;
1042 } 647 }
648 else if ( mBoostLevel > 0)
649 {
650 priority += 0.f + 1000.f * mBoostLevel;
651 }
1043 } 652 }
1044 return priority; 653 return priority;
1045} 654}
@@ -1048,7 +657,7 @@ F32 LLViewerImage::calcDecodePriority()
1048//static 657//static
1049F32 LLViewerImage::maxDecodePriority() 658F32 LLViewerImage::maxDecodePriority()
1050{ 659{
1051 return 1400000.f; 660 return 2000000.f;
1052} 661}
1053 662
1054void LLViewerImage::setDecodePriority(F32 priority) 663void LLViewerImage::setDecodePriority(F32 priority)
@@ -1062,10 +671,6 @@ void LLViewerImage::setDecodePriority(F32 priority)
1062 { 671 {
1063 mDecodePriority = priority; 672 mDecodePriority = priority;
1064 } 673 }
1065 if (mStreamFile)
1066 {
1067 mStreamFile->setReadPriority(priority);
1068 }
1069} 674}
1070 675
1071void LLViewerImage::setBoostLevel(S32 level) 676void LLViewerImage::setBoostLevel(S32 level)
@@ -1079,187 +684,219 @@ void LLViewerImage::setBoostLevel(S32 level)
1079 684
1080//============================================================================ 685//============================================================================
1081 686
1082void LLViewerImage::abortDecode() 687bool LLViewerImage::updateFetch()
1083{ 688{
1084 // Don't try to recover, just don't set a formatted image. 689 mFetchState = 0;
1085 // Recovery makes the code MUCH more complex 690 mFetchPriority = 0;
1086 //llinfos << "Reset on abort decode" << llendl; 691 mFetchDeltaTime = 999999.f;
1087 resetPacketData(); 692 mRequestDeltaTime = 999999.f;
1088 693
1089 setFormattedImage(NULL); 694#ifndef LL_RELEASE_FOR_DOWNLOAD
1090 mFullyLoaded = FALSE; 695 if (mID == gTextureFetch->mDebugID)
1091 // Make sure mNeedsAux is false, otherwise it'll try to decode the 5th channel
1092 mNeedsAux = FALSE;
1093 mFullWidth = 0;
1094 mFullHeight = 0;
1095 setNeedsDecode(FALSE); // Aborting setDecodeData
1096 mDecodingAux = FALSE;
1097 if (mStreamFile)
1098 { 696 {
1099 llwarns << "Removing bad texture: " << mID << llendl; 697 gTextureFetch->mDebugCount++; // for setting breakpoints
1100 hoseStreamFile();
1101 } 698 }
1102 else 699#endif
700
701 if (mIsMediaTexture)
1103 { 702 {
1104 llwarns << "Removing bad texture: " << mID << llendl; 703 llassert_always(!mHasFetcher);
1105 LLVFile vf(gVFS, mID, LLAssetType::AT_TEXTURE, LLVFile::READ_WRITE); 704 return false; // skip
1106 vf.remove();
1107 } 705 }
1108 mRequestedDiscardLevel = -1; // make sure we re-request the data 706 if (mNeedsCreateTexture)
1109}
1110
1111void LLViewerImage::hoseStreamFile()
1112{
1113 mStreamFile->remove();
1114
1115 delete mStreamFile;
1116 mStreamFile = NULL;
1117
1118 delete[] mCachedData;
1119 mCachedData = NULL;
1120 mCachedSize = 0;
1121}
1122
1123
1124// Sets mStreamFile to NULL when finishes loading.
1125BOOL LLViewerImage::loadStreamFile()
1126{
1127 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1128 // load as much data as possible from the stream cache file
1129 // TODO: unify stream cache with load local
1130
1131 // are we waiting on a file read?
1132 if (mStreamFile)
1133 { 707 {
1134 if (mCachedSize == 0) 708 // We may be fetching still (e.g. waiting on write)
709 // but don't check until we've processed the raw data we have
710 return false;
711 }
712 if (mFullyLoaded)
713 {
714 llassert_always(!mHasFetcher);
715 return false;
716 }
717 if (mIsMissingAsset)
718 {
719 llassert_always(!mHasFetcher);
720 return false; // skip
721 }
722 if (!mLoadedCallbackList.empty() && mRawImage.notNull())
723 {
724 return false; // process any raw image data in callbacks before replacing
725 }
726
727 S32 current_discard = getDiscardLevel();
728 S32 desired_discard = getDesiredDiscardLevel();
729 F32 decode_priority = getDecodePriority();
730
731 if (mIsFetching)
732 {
733 // Sets mRawDiscardLevel, mRawImage, mAuxRawImage
734 S32 fetch_discard = current_discard;
735 bool finished = gTextureFetch->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
736 if (finished)
1135 { 737 {
1136 if (mStreamFile->isLocked(VFSLOCK_APPEND)) 738 mIsFetching = FALSE;
1137 { 739 }
1138 // avoid stalling if we are still writing to the file 740 else
1139 return FALSE; 741 {
1140 } 742 mFetchState = gTextureFetch->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
1141 mCachedSize = mStreamFile->getSize(); 743 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
1142 if (mCachedSize >= 27) 744 }
745
746 // We may have data ready regardless of whether or not we are finished (e.g. waiting on write)
747 if (mRawImage.notNull())
748 {
749 mRawDiscardLevel = fetch_discard;
750 if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) &&
751 (current_discard < 0 || mRawDiscardLevel < current_discard))
1143 { 752 {
1144 mCachedData = new U8[mCachedSize]; 753 if (getComponents() != mRawImage->getComponents())
1145 mStreamFile->read(mCachedData, mCachedSize, TRUE, 100 + mDecodePriority); 754 {
755 // We've changed the number of components, so we need to move any
756 // objects using this pool to a different pool.
757 mComponents = mRawImage->getComponents();
758 gImageList.dirtyImage(this);
759 }
760 mIsRawImageValid = TRUE;
761 gImageList.mCreateTextureList.insert(this);
762 mNeedsCreateTexture = TRUE;
763 mFullWidth = mRawImage->getWidth() << mRawDiscardLevel;
764 mFullHeight = mRawImage->getHeight() << mRawDiscardLevel;
1146 } 765 }
1147 else 766 else
1148 { 767 {
1149 llwarns << "Cached image " << mID << " has length " << mCachedSize << " not loading" << llendl; 768 // Data is ready but we don't need it
1150 769 // (received it already while fetcher was writing to disk)
1151 mStreamFile->remove(); 770 destroyRawImage();
1152 771 return false; // done
1153 delete mStreamFile;
1154 mStreamFile = NULL;
1155 mCachedSize = 0;
1156 return FALSE;
1157 } 772 }
1158 } 773 }
1159 774
1160 // is it finished? 775 if (!mIsFetching)
1161 if (mStreamFile->isReadComplete())
1162 { 776 {
1163 //llinfos << mID << ": loading from stream file " << llendl; 777 if (mRawDiscardLevel < 0)
1164 U16 packet;
1165 U32 file_version;
1166 LLUUID file_id;
1167
1168 U8 *tmp = mCachedData;
1169 memcpy(&file_version, tmp, 4);
1170 tmp += 4;
1171 memcpy(file_id.mData, tmp, 16);
1172 tmp += 16;
1173
1174 if (file_version != sCurrentFileVersion ||
1175 file_id != mID)
1176 {
1177 // this file is from an old version, failed to open, or is invalid
1178 hoseStreamFile();
1179
1180 return TRUE; // done
1181 }
1182
1183 mGotFirstPacket = TRUE;
1184
1185 memcpy(&mDataCodec, tmp, 1);
1186 tmp += 1;
1187 memcpy(&mPackets, tmp, 2);
1188 tmp += 2;
1189
1190 memcpy(&mTotalBytes, tmp, 4);
1191 tmp += 4;
1192
1193 while (tmp - mCachedData < mCachedSize)
1194 { 778 {
1195 memcpy(&packet, tmp, 2); 779 // We finished but received no data
1196 tmp += 2; 780 if (current_discard < 0)
1197
1198 if (packet >= mPackets)
1199 { 781 {
1200 llwarns << "Cached image " << mID << " has bogus packet " << packet << " of " << mPackets << llendl; 782 llwarns << mID << ": Marking image as missing" << llendl;
1201 783 setIsMissingAsset();
1202 hoseStreamFile(); 784 desired_discard = -1;
1203 return TRUE; // done
1204 }
1205
1206 U16 data_size;
1207 memcpy((U8*)&(data_size), tmp, 2);
1208 tmp += 2;
1209
1210 if (tmp + data_size > mCachedData + mCachedSize)
1211 {
1212 llwarns << "Cached image " << mID << " has bad length " << mCachedSize << ", should be " << (S32)(tmp + data_size - mCachedData) << llendl;
1213
1214 hoseStreamFile();
1215 return TRUE; // done
1216 }
1217
1218 if (mReceivedPacketMap.find(packet) == mReceivedPacketMap.end())
1219 {
1220 U8 *buf = new U8[data_size];
1221 memcpy(buf, tmp, data_size);
1222 mReceivedPacketMap[packet] = new LLViewerImagePacket(buf, data_size, packet, TRUE);
1223 } 785 }
1224 else 786 else
1225 { 787 {
1226 // Technically this assertion is correct, but there may be bogus VFS files out there which invalidate this 788 llwarns << mID << ": Setting min discard to " << current_discard << llendl;
1227 // condition. 789 mMinDiscardLevel = current_discard;
1228 //llassert(!mReceivedPacketMap[packet]->mWroteToDisk); 790 desired_discard = current_discard;
1229 mReceivedPacketMap[packet]->mWroteToDisk = TRUE;
1230 } 791 }
1231 792 destroyRawImage();
1232 tmp += data_size;
1233
1234 mPacketsReceived++;
1235 } 793 }
794 else if (mRawImage.isNull())
795 {
796 // We have data, but our fetch failed to return raw data
797 // *TODO: FIgure out why this is happening and fix it
798 destroyRawImage();
799 }
800 }
801 else if (mDecodePriority >= 0.f)
802 {
803 gTextureFetch->updateRequestPriority(mID, mDecodePriority);
804 }
805 }
1236 806
1237 delete mStreamFile; 807 bool make_request = true;
1238 mStreamFile = NULL; 808
1239 809 if (decode_priority <= 0)
1240 delete[] mCachedData; 810 {
1241 mCachedData = NULL; 811 make_request = false;
1242 mCachedSize = 0; 812 }
1243 813 else if (mNeedsCreateTexture || mIsMissingAsset)
1244 // Make sure we process all of the packet data associated with this texture. 814 {
1245 mLastPacketProcessed = -1; 815 make_request = false;
1246 mLastPacket = -1; 816 }
1247 mLastPacketTimer.reset(); 817 else if (current_discard >= 0 && current_discard <= mMinDiscardLevel)
1248 818 {
1249 // Process the packets and write to disk any that have not been written 819 make_request = false;
1250 checkPacketData(); 820 }
1251 821 else
1252 return TRUE; // done 822 {
823 if (mIsFetching)
824 {
825 if (mRequestedDiscardLevel <= desired_discard)
826 {
827 make_request = false;
828 }
1253 } 829 }
1254 else 830 else
1255 { 831 {
1256 return FALSE; // still loading 832 if (current_discard >= 0 && current_discard <= desired_discard)
833 {
834 make_request = false;
835 }
1257 } 836 }
1258 } 837 }
1259 else 838
839 if (make_request)
840 {
841 S32 w=0, h=0, c=0;
842 if (current_discard >= 0)
843 {
844 w = getWidth(0);
845 h = getHeight(0);
846 c = getComponents();
847 }
848 if (!mDontDiscard)
849 {
850 if (mBoostLevel == 0)
851 {
852 desired_discard = llmax(desired_discard, current_discard-1);
853 }
854 else
855 {
856 desired_discard = llmax(desired_discard, current_discard-2);
857 }
858 }
859 if (gTextureFetch->createRequest(getID(),getTargetHost(), decode_priority,
860 w, h, c, desired_discard,
861 needsAux()))
862 {
863 mHasFetcher = TRUE;
864 mIsFetching = TRUE;
865 mRequestedDiscardLevel = desired_discard;
866 mFetchState = gTextureFetch->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
867 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
868 }
869 // if createRequest() failed, we're finishing up a request for this UUID,
870 // wait for it to complete
871 }
872 else if (mHasFetcher && !mIsFetching)
873 {
874 // Only delete requests that haven't receeived any network data for a while
875 const F32 FETCH_IDLE_TIME = 5.f;
876 if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME)
877 {
878// llinfos << "Deleting request: " << getID() << " Discard: " << current_discard << " <= min:" << mMinDiscardLevel << " or priority == 0: " << decode_priority << llendl;
879 gTextureFetch->deleteRequest(getID(), true);
880 mHasFetcher = FALSE;
881 }
882 }
883
884 llassert_always(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid));
885
886 return mIsFetching ? true : false;
887}
888
889void LLViewerImage::setIsMissingAsset()
890{
891 if (mHasFetcher)
1260 { 892 {
1261 return TRUE; // not loading 893 gTextureFetch->deleteRequest(getID(), true);
894 mHasFetcher = FALSE;
895 mIsFetching = FALSE;
896 mFetchState = 0;
897 mFetchPriority = 0;
1262 } 898 }
899 mIsMissingAsset = TRUE;
1263} 900}
1264 901
1265//============================================================================ 902//============================================================================
@@ -1278,13 +915,14 @@ void LLViewerImage::setLoadedCallback( loaded_callback_func loaded_callback, S32
1278 mLoadedCallbackList.push_back(entryp); 915 mLoadedCallbackList.push_back(entryp);
1279} 916}
1280 917
1281void LLViewerImage::doLoadedCallbacks() 918bool LLViewerImage::doLoadedCallbacks()
1282{ 919{
1283 // Need to make sure we don't do these during the process of a decode or something? 920 if (mNeedsCreateTexture)
1284 if ((mFormattedImagep.notNull() && mFormattedImagep->isDecoding()) || mNeedsCreateTexture)
1285 { 921 {
1286 return; 922 return false;
1287 } 923 }
924
925 bool res = false;
1288 926
1289 if (isMissingAsset()) 927 if (isMissingAsset())
1290 { 928 {
@@ -1311,12 +949,6 @@ void LLViewerImage::doLoadedCallbacks()
1311 gl_discard = MAX_DISCARD_LEVEL + 1; 949 gl_discard = MAX_DISCARD_LEVEL + 1;
1312 } 950 }
1313 951
1314 // assert: We should either have a valid raw image, be decoding one, or not have one at all
1315 llassert(mIsRawImageValid || needsDecode() || mRawImage.isNull());
1316 // assert: We should either not have a raw image, or it's discard level should be <= gl_discard
1317 llassert(!mIsRawImageValid || mRawDiscardLevel <= gl_discard);
1318
1319
1320 // 952 //
1321 // Determine the quality levels of textures that we can provide to callbacks 953 // Determine the quality levels of textures that we can provide to callbacks
1322 // and whether we need to do decompression/readback to get it 954 // and whether we need to do decompression/readback to get it
@@ -1335,18 +967,9 @@ void LLViewerImage::doLoadedCallbacks()
1335 } 967 }
1336 else 968 else
1337 { 969 {
1338 if (mFormattedImagep.notNull()) 970 // We have no data at all, we need to get it
1339 { 971 // Do this by forcing the best aux discard to be 0.
1340 // If we don't have a raw image or a GL image, we need to decode from a formatted image 972 best_aux_discard = 0;
1341 best_aux_discard = llmin(best_aux_discard,
1342 mFormattedImagep->calcDiscardLevelBytes(mFormattedImagep->getDataSize()));
1343 }
1344 else
1345 {
1346 // We have no data at all, we need to get the formatted image.
1347 // Do this by forcing the best aux discard to be 0.
1348 best_aux_discard = 0;
1349 }
1350 } 973 }
1351 974
1352 975
@@ -1357,7 +980,6 @@ void LLViewerImage::doLoadedCallbacks()
1357 bool run_gl_callbacks = false; 980 bool run_gl_callbacks = false;
1358 bool run_raw_callbacks = false; 981 bool run_raw_callbacks = false;
1359 bool need_readback = false; 982 bool need_readback = false;
1360 bool need_decompress = false;
1361 983
1362 for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); 984 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
1363 iter != mLoadedCallbackList.end(); ) 985 iter != mLoadedCallbackList.end(); )
@@ -1375,12 +997,6 @@ void LLViewerImage::doLoadedCallbacks()
1375 // We have useful data, run the callbacks 997 // We have useful data, run the callbacks
1376 run_raw_callbacks = true; 998 run_raw_callbacks = true;
1377 } 999 }
1378 else if (entryp->mLastUsedDiscard > best_aux_discard)
1379 {
1380 // We need to decompress data, but don't need
1381 // to run the callbacks
1382 need_decompress = true;
1383 }
1384 } 1000 }
1385 else 1001 else
1386 { 1002 {
@@ -1420,10 +1036,8 @@ void LLViewerImage::doLoadedCallbacks()
1420 createRawImage(gl_discard, TRUE); 1036 createRawImage(gl_discard, TRUE);
1421 readBackRaw(gl_discard, mRawImage); 1037 readBackRaw(gl_discard, mRawImage);
1422 mIsRawImageValid = TRUE; 1038 mIsRawImageValid = TRUE;
1423 } 1039 llassert_always(mRawImage.notNull());
1424 if (need_decompress) 1040 llassert_always(!mNeedsAux || mAuxRawImage.notNull());
1425 {
1426 startImageDecode();
1427 } 1041 }
1428 1042
1429 // 1043 //
@@ -1434,10 +1048,6 @@ void LLViewerImage::doLoadedCallbacks()
1434 // Do callbacks which require raw image data. 1048 // Do callbacks which require raw image data.
1435 //llinfos << "doLoadedCallbacks raw for " << getID() << llendl; 1049 //llinfos << "doLoadedCallbacks raw for " << getID() << llendl;
1436 1050
1437 LLImageRaw* raw_image = mRawImage;
1438 LLImageRaw* raw_image_aux = mAuxRawImage;
1439 llassert(!mNeedsAux || mAuxRawImage.notNull());
1440
1441 // Call each party interested in the raw data. 1051 // Call each party interested in the raw data.
1442 for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); 1052 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
1443 iter != mLoadedCallbackList.end(); ) 1053 iter != mLoadedCallbackList.end(); )
@@ -1450,28 +1060,26 @@ void LLViewerImage::doLoadedCallbacks()
1450 // to satisfy the interested party, then this is the last time that 1060 // to satisfy the interested party, then this is the last time that
1451 // we're going to call them. 1061 // we're going to call them.
1452 1062
1063 llassert_always(mRawImage.notNull());
1064 llassert_always(!mNeedsAux || mAuxRawImage.notNull());
1453 1065
1454 BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE; 1066 BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE;
1455 //llinfos << "Running callback for " << getID() << llendl; 1067 //llinfos << "Running callback for " << getID() << llendl;
1456 //llinfos << raw_image->getWidth() << "x" << raw_image->getHeight() << llendl; 1068 //llinfos << mRawImage->getWidth() << "x" << mRawImage->getHeight() << llendl;
1457 if (final) 1069 if (final)
1458 { 1070 {
1459 //llinfos << "Final!" << llendl; 1071 //llinfos << "Final!" << llendl;
1460 } 1072 }
1461 entryp->mLastUsedDiscard = mRawDiscardLevel; 1073 entryp->mLastUsedDiscard = mRawDiscardLevel;
1462 entryp->mCallback(TRUE, this, raw_image, raw_image_aux, mRawDiscardLevel, final, entryp->mUserData); 1074 entryp->mCallback(TRUE, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData);
1463 if (final) 1075 if (final)
1464 { 1076 {
1465 iter = mLoadedCallbackList.erase(curiter); 1077 iter = mLoadedCallbackList.erase(curiter);
1466 delete entryp; 1078 delete entryp;
1467 } 1079 }
1080 res = true;
1468 } 1081 }
1469 } 1082 }
1470
1471 //
1472 // If you want to keep a copy of the raw image, you better copy it off yourself
1473 //
1474 destroyRawImage();
1475 } 1083 }
1476 1084
1477 // 1085 //
@@ -1497,6 +1105,7 @@ void LLViewerImage::doLoadedCallbacks()
1497 iter = mLoadedCallbackList.erase(curiter); 1105 iter = mLoadedCallbackList.erase(curiter);
1498 delete entryp; 1106 delete entryp;
1499 } 1107 }
1108 res = true;
1500 } 1109 }
1501 } 1110 }
1502 } 1111 }
@@ -1508,450 +1117,14 @@ void LLViewerImage::doLoadedCallbacks()
1508 { 1117 {
1509 gImageList.mCallbackList.erase(this); 1118 gImageList.mCallbackList.erase(this);
1510 } 1119 }
1511}
1512 1120
1513//============================================================================ 1121 // Done with any raw image data at this point (will be re-created if we still have callbacks)
1514 1122 destroyRawImage();
1515// static
1516void LLViewerImage::receiveImage(LLMessageSystem *msg, void **user_data)
1517{
1518 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1519
1520 // Receive image header, copy into image object and decompresses
1521 // if this is a one-packet image.
1522
1523 LLUUID id;
1524
1525 char ip_string[256];
1526 u32_to_ip_string(msg->getSenderIP(),ip_string);
1527
1528 if (msg->getReceiveCompressedSize())
1529 {
1530 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
1531 }
1532 else
1533 {
1534 gImageList.sTextureBits += msg->getReceiveSize() * 8;
1535 }
1536 gImageList.sTexturePackets++;
1537
1538 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
1539
1540 char id_string[UUID_STR_LENGTH];
1541 id.toString(id_string);
1542
1543 LLViewerImage *image = gImageList.getImage(id); // Look up the correct image
1544
1545 image->mLastPacketTimer.reset();
1546 1123
1547 if (image->mFullyLoaded) 1124 return res;
1548 {
1549// llinfos << id << ":" << " Packet 0 for already loaded image!" << llendl;
1550 return;
1551 }
1552
1553 // check to see if we've gotten this packet before
1554 if (image->mGotFirstPacket)
1555 {
1556 //llinfos << id << ":" << " Duplicate Packet 0" << llendl;
1557 return;
1558 }
1559 if (!image->mRequested)
1560 {
1561// llinfos << id << ":" << " Packet 0 for unrequested image!" << llendl;
1562 return;
1563 }
1564
1565 image->mGotFirstPacket = TRUE;
1566
1567 // Copy header data into image object
1568 msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, image->mDataCodec);
1569 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, image->mPackets);
1570 msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, image->mTotalBytes);
1571
1572 if (0 == image->mPackets)
1573 {
1574 llwarns << "Img: " << (gTextureTable.getName(id).empty() ? id_string : gTextureTable.getName(id)) << ":" << " Number of packets is 0" << llendl;
1575 return;
1576 }
1577
1578 lldebugst(LLERR_IMAGE) << "Img: " << (gTextureTable.getName(id).empty() ? id_string : gTextureTable.getName(id)) << ":" << " Packet 0:" << image->mPackets - 1 << llendl;
1579
1580 U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
1581
1582 // Got a packet, reset the counter.
1583 image->mRequestTime.reset();
1584 image->mPacketsReceived++;
1585
1586 if (data_size)
1587 {
1588 if (gVFS->getExists(image->mID, LLAssetType::AT_TEXTURE))
1589 {
1590 // We have data in the VFS, but it's not loaded.
1591 // We should start the VFS load on the assumption that we're going to use this data shortly.
1592 image->startVFSLoad();
1593 // We can throw out this data, because we have at least ONE packet on the disk
1594 //llinfos << "Throwing out first packet for " << image->mID << " which we already have a VFS file for!" << llendl;
1595 return;
1596 }
1597
1598 // this buffer gets saved off in the packet list
1599 U8 *data = new U8[data_size];
1600 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
1601
1602 // output this image data to cache file
1603 // only do this if we don't have old data
1604 LLVFile file(gVFS, image->mID, LLAssetType::AT_TEXTURE, LLVFile::APPEND);
1605 if (! file.getSize())
1606 {
1607 BOOL write_to_vfs = FALSE;
1608 if (image->mPackets == 0)
1609 {
1610 // Uh oh, we don't have packet data size
1611 // This must be something from a local cache
1612 llwarns << "Creating VFS file even though we don't know the number of packets!" << llendl;
1613 }
1614 else
1615 {
1616 write_to_vfs = file.setMaxSize(image->mTotalBytes + IMAGE_HEADER_SIZE + image->mPackets * PACKET_HEADER_SIZE);
1617 }
1618
1619 // to avoid another dynamic allocation, just assume we won't be gettimg image packets > 1 MTU
1620 if (data_size > MTUBYTES)
1621 {
1622 llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
1623 }
1624
1625 if (write_to_vfs)
1626 {
1627 const S32 WRITE_BUF_SIZE = IMAGE_HEADER_SIZE + PACKET_HEADER_SIZE + MTUBYTES;
1628 U8 buffer[WRITE_BUF_SIZE];
1629 U8 *tmp = buffer;
1630
1631 // write current version byte to file, so we can change the format and detect old files later
1632 memcpy(tmp, &LLViewerImage::sCurrentFileVersion, 4);
1633 tmp += 4;
1634 memcpy(tmp, id.mData, 16);
1635 tmp += 16;
1636 memcpy(tmp, (U8*)&(image->mDataCodec), 1);
1637 tmp += 1;
1638 memcpy(tmp, (U8*)&(image->mPackets), 2);
1639 tmp += 2;
1640 memcpy(tmp, (U8*)&(image->mTotalBytes), 4);
1641 tmp += 4;
1642 U16 zero = 0;
1643 memcpy(tmp, (U8*)&zero, 2);
1644 tmp += 2;
1645 memcpy(tmp, (U8*)&(data_size), 2);
1646 tmp += 2;
1647
1648 // now copy in the image data
1649 // it's a shame we can't use the original data buffer
1650 // but this needs to be a single, atomic write
1651 memcpy(tmp, data, data_size);
1652
1653// llinfos << "Writing packet 0 to disk for " << image->getID() << llendl;
1654 file.write(buffer, IMAGE_HEADER_SIZE + PACKET_HEADER_SIZE + data_size);
1655 }
1656 // do this AFTER writing to the VFS since LLViewerImagePacket may delete 'data'
1657 llassert( image->mReceivedPacketMap.find(0) == image->mReceivedPacketMap.end() );
1658 image->mReceivedPacketMap[0] = new LLViewerImagePacket(data, data_size, 0, TRUE);
1659 }
1660
1661 image->checkPacketData();
1662 }
1663}
1664
1665
1666///////////////////////////////////////////////////////////////////////////////
1667// TODO: lastbytes vs. texturebits?
1668// TODO: is mRequested already used?
1669
1670// static
1671void LLViewerImage::receiveImagePacket(LLMessageSystem *msg, void **user_data)
1672{
1673 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1674 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1675
1676 // Receives image packet, copy into image object,
1677 // checks if all packets received, decompresses if so.
1678
1679 LLUUID id;
1680 U16 packet_num;
1681 char id_string[UUID_STR_LENGTH];
1682
1683 char ip_string[256];
1684 u32_to_ip_string(msg->getSenderIP(),ip_string);
1685
1686 if (msg->getReceiveCompressedSize())
1687 {
1688 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
1689 }
1690 else
1691 {
1692 gImageList.sTextureBits += msg->getReceiveSize() * 8;
1693 }
1694 gImageList.sTexturePackets++;
1695
1696 //llprintline("Start decode, image header...");
1697 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
1698 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num);
1699
1700 id.toString(id_string);
1701
1702 LLViewerImage *image = gImageList.hasImage(id); // Look up the correct image
1703 if (!image ||!(image->mRequested))
1704 {
1705 // Getting a packet for an unrequested image.
1706 lldebugst(LLERR_IMAGE) << "Img: " << (gTextureTable.getName(id).empty() ? id_string : gTextureTable.getName(id)) << " Packet ";
1707 llcont << packet_num << " for unrequested from " << ip_string << llendl;
1708
1709 // don't cancel the request - this might just be an out of order packet
1710 return;
1711 }
1712
1713 image->mLastPacketTimer.reset();
1714
1715 if (image->mReceivedPacketMap.find(packet_num) != image->mReceivedPacketMap.end())
1716 {
1717 return;
1718 }
1719
1720 // check to see if we already got this packet
1721 BOOL duplicate = FALSE;
1722 if (packet_num <= image->mLastPacketProcessed)
1723 {
1724 duplicate = TRUE;
1725 }
1726 else if (image->mReceivedPacketMap.find(packet_num) != image->mReceivedPacketMap.end())
1727 {
1728 duplicate = TRUE;
1729 }
1730
1731 if (duplicate)
1732 {
1733 //llinfos << image->mID << ": duplicate packet " << packet_num << " last " << image->mLastPacketProcessed << llendl;
1734 return;
1735 }
1736
1737 // Got a packet, reset the counter.
1738 image->mRequestTime.reset();
1739 image->mPacketsReceived++;
1740
1741 std::string tex_name = gTextureTable.getName(id);
1742 if (image->mPackets == 0)
1743 {
1744 lldebugst(LLERR_IMAGE) << "Img: " << (tex_name.empty() ? id_string : tex_name) << " Packet " << packet_num << " out of order " << llendl;
1745 }
1746 else
1747 {
1748 lldebugst(LLERR_IMAGE) << "Img: " << (tex_name.empty() ? id_string : tex_name) << " Packet " << packet_num << ":" << image->mPackets - 1 << llendl;
1749 }
1750
1751
1752 U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
1753 if (data_size)
1754 {
1755
1756 U8 *data = new U8[data_size];
1757 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
1758
1759 // as above assume we won't be gettimg image packets > 1 MTU
1760 if (data_size > MTUBYTES)
1761 {
1762 llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
1763 }
1764
1765 // We don't want to write it to disk yet, just put it on the queue.
1766 image->mReceivedPacketMap[packet_num] = new LLViewerImagePacket(data, data_size, packet_num, FALSE);
1767 // Process this packet.
1768 image->checkPacketData();
1769 }
1770}
1771
1772
1773BOOL LLViewerImage::checkPacketData()
1774{
1775 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1776
1777 S32 cur_size = 0;
1778 S32 next_size = 0;
1779 S32 next_discard = llmax(getDiscardLevel()-1,0);
1780
1781 // 1. Check if we already have formatted data to decode
1782 if (mFormattedImagep.notNull())
1783 {
1784 if ((mFormattedImagep->isDecoding()) || mStreamFile)
1785 {
1786 return TRUE; // we're busy decoding, don't request more data yet
1787 }
1788
1789 cur_size = mFormattedImagep->getDataSize();
1790 next_size = mFormattedImagep->calcDataSize(next_discard);
1791 next_size = llmin(next_size, (S32)mTotalBytes);
1792
1793 if (cur_size >= next_size)
1794 {
1795 setDecodeData(mFormattedImagep->getData(), cur_size);
1796 return TRUE;
1797 }
1798 }
1799
1800 if (mFullyLoaded)
1801 {
1802 // Somehow we think we have new packet data but are flagged as fully loaded
1803 resetPacketData();
1804 return TRUE;
1805 }
1806
1807 // 2. Check if we already have new packets
1808 if (!mPackets || !mGotFirstPacket)
1809 {
1810 return FALSE;
1811 }
1812 if (mReceivedPacketMap.empty() || mReceivedPacketMap.find(mLastPacketProcessed + 1) == mReceivedPacketMap.end())
1813 {
1814 return FALSE;
1815 }
1816
1817 // 3. Decide if we have enough new data to decode
1818 S32 new_size = cur_size;
1819 U16 next_packet_num = mLastPacketProcessed;
1820 for (vip_map_t::iterator iter = mReceivedPacketMap.begin();
1821 iter != mReceivedPacketMap.end() && iter->second->mPacketNum == ++next_packet_num;
1822 iter++)
1823 {
1824 new_size += iter->second->mDataSize;
1825 mLastPacket = iter->second->mPacketNum;
1826 }
1827 mLastBytesProcessed = new_size;
1828
1829 if (new_size < next_size)
1830 {
1831 return FALSE;
1832 }
1833
1834 if (!gVFS->getExists(mID, LLAssetType::AT_TEXTURE))
1835 {
1836 // We must have removed the file, probably because it was corrupted. Abort!
1837 //llinfos << "Reset on no VFS file!" << llendl;
1838 abortDecode();
1839 return FALSE;
1840 }
1841
1842 if (mLastPacketProcessed == -1 && cur_size != 0)
1843 {
1844 llerrs << "LLViewerImage: duplicate first packet!" << llendl;
1845 }
1846
1847 // 4. Append new data to existing data and decode
1848
1849 // 4a. Write the packets to disk
1850 LLVFile file(gVFS, mID, LLAssetType::AT_TEXTURE, LLVFile::APPEND);
1851 vip_map_t::iterator first_iter = mReceivedPacketMap.begin();
1852 S32 first_idx = 0;
1853 while (first_iter != mReceivedPacketMap.end())
1854 {
1855 S32 packet_data_size = 0;
1856 vip_map_t::iterator end_iter = first_iter;
1857 S32 end_idx = first_idx;
1858 while(end_iter != mReceivedPacketMap.end())
1859 {
1860 LLViewerImagePacket *vip = end_iter->second;
1861 if (!vip->mWroteToDisk)
1862 {
1863 packet_data_size += (PACKET_HEADER_SIZE + vip->mDataSize);
1864 }
1865 else
1866 {
1867 break;
1868 }
1869 ++end_iter;
1870 ++end_idx;
1871 }
1872 if (packet_data_size > 0)
1873 {
1874 U8* packet_data_buffer = new U8[packet_data_size];
1875 U8* packet_data = packet_data_buffer;
1876 for (vip_map_t::iterator iter = first_iter; iter != end_iter; ++iter)
1877 {
1878 LLViewerImagePacket *vip = iter->second;
1879
1880 memcpy(packet_data, &vip->mPacketNum, 2);
1881 memcpy(packet_data + 2, &(vip->mDataSize), 2);
1882 memcpy(packet_data + PACKET_HEADER_SIZE, vip->mData, vip->mDataSize);
1883 packet_data += (PACKET_HEADER_SIZE + vip->mDataSize);
1884
1885 vip->mWroteToDisk = TRUE;
1886 }
1887 if (packet_data - packet_data_buffer != packet_data_size) llerrs << "wtf?" << llendl;
1888
1889 // llinfos << mID << " Writing packets " << first_idx << "-" << end_idx << " to file." << llendl;
1890 file.write(packet_data_buffer, packet_data_size);
1891
1892 delete[] packet_data_buffer;
1893 }
1894 if (end_iter == first_iter)
1895 {
1896 ++end_iter;
1897 ++end_idx;
1898 }
1899 first_iter = end_iter;
1900 first_idx = end_idx;
1901 }
1902
1903 // 4b. Append the data
1904 U8* data = new U8[new_size];
1905 if (cur_size > 0)
1906 {
1907 memcpy(data, mFormattedImagep->getData(), cur_size);
1908 }
1909 LLViewerImagePacket *pkt = mReceivedPacketMap.begin()->second;
1910 while (pkt && pkt->mPacketNum == mLastPacketProcessed + 1)
1911 {
1912 memcpy((U8*)(data + cur_size), pkt->mData, pkt->mDataSize);
1913 cur_size += pkt->mDataSize;
1914 mLastPacketProcessed = pkt->mPacketNum;
1915 delete mReceivedPacketMap.begin()->second;
1916 mReceivedPacketMap.erase(mReceivedPacketMap.begin());
1917 pkt = NULL;
1918 if (!mReceivedPacketMap.empty())
1919 {
1920 pkt = mReceivedPacketMap.begin()->second;
1921 }
1922 }
1923
1924 llassert(cur_size == new_size);
1925 lldebugst(LLERR_IMAGE) << "IMAGE RECEIVED: " << mID.getString() << " Bytes: " << cur_size << "/" << mTotalBytes << llendl;
1926
1927 // 4c. Set the data to be decoded, and the number of bytes to use.
1928 setDecodeData(data, new_size);
1929
1930 // 5. Recalculate the image priority
1931 gImageList.removeImageFromList(this);
1932 F32 decode_priority = calcDecodePriority();
1933 setDecodePriority(decode_priority);
1934 gImageList.addImageToList(this);
1935
1936 return TRUE;
1937} 1125}
1938 1126
1939F32 LLViewerImage::getDecodeProgress(F32 *data_progress_p) 1127//============================================================================
1940{
1941 F32 decode_progress = 0.0f;
1942 F32 data_progress = 0.0f;
1943
1944 if (mLastPacket >= 0)
1945 {
1946 S32 max_bytes = mTotalBytes;
1947 S32 data_bytes = mLastBytesProcessed;
1948 S32 decode_bytes = mFormattedImagep.notNull() ? mFormattedImagep->getDataSize() : data_bytes;
1949 data_progress = (F32)data_bytes / (F32)max_bytes;
1950 decode_progress = (F32)decode_bytes / (F32)max_bytes;
1951 }
1952 if (data_progress_p) *data_progress_p = data_progress;
1953 return decode_progress;
1954}
1955 1128
1956// Call with 0,0 to turn this feature off. 1129// Call with 0,0 to turn this feature off.
1957void LLViewerImage::setKnownDrawSize(S32 width, S32 height) 1130void LLViewerImage::setKnownDrawSize(S32 width, S32 height)
@@ -1976,13 +1149,8 @@ BOOL LLViewerImage::bind(S32 stage) const
1976 BOOL res = bindTextureInternal(stage); 1149 BOOL res = bindTextureInternal(stage);
1977 if (res) 1150 if (res)
1978 { 1151 {
1979 if (mIsMissingAsset) 1152 //llassert_always(mIsMissingAsset == FALSE);
1980 { 1153
1981 // If we can bind, clearly we have an asset.
1982 // If mIsMissingAsset was true and we get here, it's likely
1983 // that the asset server was messed up and then it recovered.
1984 mIsMissingAsset = FALSE;
1985 }
1986 } 1154 }
1987 else 1155 else
1988 { 1156 {
@@ -2013,7 +1181,6 @@ BOOL LLViewerImage::bind(S32 stage) const
2013LLImageRaw* LLViewerImage::createRawImage(S8 discard_level, BOOL allocate) 1181LLImageRaw* LLViewerImage::createRawImage(S8 discard_level, BOOL allocate)
2014{ 1182{
2015 llassert(discard_level >= 0); 1183 llassert(discard_level >= 0);
2016 llassert(mFormattedImagep.isNull() || !mFormattedImagep->isDecoding());
2017 if (mRawImage.notNull()) 1184 if (mRawImage.notNull())
2018 { 1185 {
2019 llerrs << "createRawImage() called with existing mRawImage" << llendl; 1186 llerrs << "createRawImage() called with existing mRawImage" << llendl;