00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llviewerimage.h"
00035
00036
00037 #include "imageids.h"
00038 #include "llmath.h"
00039 #include "llerror.h"
00040 #include "llgl.h"
00041 #include "llglheaders.h"
00042 #include "llhost.h"
00043 #include "llimage.h"
00044 #include "llimagebmp.h"
00045 #include "llimagej2c.h"
00046 #include "llimagetga.h"
00047 #include "llmemtype.h"
00048 #include "llstl.h"
00049 #include "llvfile.h"
00050 #include "llvfs.h"
00051 #include "message.h"
00052 #include "lltimer.h"
00053
00054
00055 #include "lldrawpool.h"
00056 #include "lltexturefetch.h"
00057 #include "llviewerimagelist.h"
00058 #include "llviewercontrol.h"
00059 #include "pipeline.h"
00060 #include "viewer.h"
00061
00063
00064
00065 LLPointer<LLViewerImage> LLViewerImage::sMissingAssetImagep = NULL;
00066 LLPointer<LLViewerImage> LLViewerImage::sWhiteImagep = NULL;
00067 LLPointer<LLImageGL> LLViewerImage::sDefaultImagep = NULL;
00068 LLPointer<LLViewerImage> LLViewerImage::sSmokeImagep = NULL;
00069 LLPointer<LLImageGL> LLViewerImage::sNullImagep = NULL;
00070
00071 S32 LLViewerImage::sImageCount = 0;
00072 LLTimer LLViewerImage::sEvaluationTimer;
00073 F32 LLViewerImage::sDesiredDiscardBias = 0.f;
00074 static F32 sDesiredDiscardBiasMin = -2.0f;
00075 static F32 sDesiredDiscardBiasMax = 1.5f;
00076 F32 LLViewerImage::sDesiredDiscardScale = 1.1f;
00077 S32 LLViewerImage::sBoundTextureMemory = 0;
00078 S32 LLViewerImage::sTotalTextureMemory = 0;
00079 S32 LLViewerImage::sMaxBoundTextureMem = 0;
00080 S32 LLViewerImage::sMaxTotalTextureMem = 0;
00081 BOOL LLViewerImage::sDontLoadVolumeTextures = FALSE;
00082
00083
00084 void LLViewerImage::initClass()
00085 {
00086 sNullImagep = new LLImageGL(1,1,3,TRUE);
00087 LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,3);
00088 raw->clear(0x77, 0x77, 0x77, 0xFF);
00089 sNullImagep->createGLTexture(0, raw);
00090
00091 #if 1
00092 LLViewerImage* imagep = new LLViewerImage(IMG_DEFAULT, TRUE);
00093 sDefaultImagep = imagep;
00094 const S32 dim = 128;
00095 LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
00096 U8* data = image_raw->getData();
00097 for (S32 i = 0; i<dim; i++)
00098 {
00099 for (S32 j = 0; j<dim; j++)
00100 {
00101 #if 0
00102 const S32 border = 2;
00103 if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
00104 {
00105 *data++ = 0xff;
00106 *data++ = 0xff;
00107 *data++ = 0xff;
00108 }
00109 else
00110 #endif
00111 {
00112 *data++ = 0x7f;
00113 *data++ = 0x7f;
00114 *data++ = 0x7f;
00115 }
00116 }
00117 }
00118 imagep->createGLTexture(0, image_raw);
00119 image_raw = NULL;
00120 gImageList.addImage(imagep);
00121 imagep->dontDiscard();
00122 #else
00123 sDefaultImagep = gImageList.getImage(IMG_DEFAULT, TRUE, TRUE);
00124 #endif
00125 sSmokeImagep = gImageList.getImage(IMG_SMOKE, TRUE, TRUE);
00126
00127 }
00128
00129
00130 void LLViewerImage::cleanupClass()
00131 {
00132 stop_glerror();
00133 sNullImagep = NULL;
00134 sDefaultImagep = NULL;
00135 sSmokeImagep = NULL;
00136 sMissingAssetImagep = NULL;
00137 sWhiteImagep = NULL;
00138 }
00139
00140
00141 const F32 discard_bias_delta = .05f;
00142 const F32 discard_delta_time = 0.5f;
00143 const S32 min_non_tex_system_mem = (128<<20);
00144
00145 F32 texmem_lower_bound_scale = 0.85f;
00146 F32 texmem_middle_bound_scale = 0.925f;
00147
00148
00149 void LLViewerImage::updateClass(const F32 velocity, const F32 angular_velocity)
00150 {
00151 sBoundTextureMemory = LLImageGL::sBoundTextureMemory;
00152 sTotalTextureMemory = LLImageGL::sGlobalTextureMemory;
00153 sMaxBoundTextureMem = gImageList.getMaxResidentTexMem();
00154
00155 sMaxTotalTextureMem = sMaxBoundTextureMem * 2;
00156 if (sMaxBoundTextureMem > 64000000)
00157 {
00158 sMaxTotalTextureMem -= sMaxBoundTextureMem/4;
00159 }
00160
00161 if ((U32)sMaxTotalTextureMem > gSysMemory.getPhysicalMemoryClamped() - (U32)min_non_tex_system_mem)
00162 {
00163 sMaxTotalTextureMem = (S32)gSysMemory.getPhysicalMemoryClamped() - min_non_tex_system_mem;
00164 }
00165
00166 if (sBoundTextureMemory >= sMaxBoundTextureMem ||
00167 sTotalTextureMemory >= sMaxTotalTextureMem)
00168 {
00169
00170
00171 if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time)
00172 {
00173 sDesiredDiscardBias += discard_bias_delta;
00174 sEvaluationTimer.reset();
00175 }
00176 }
00177 else if (sDesiredDiscardBias > 0.0f &&
00178 sBoundTextureMemory < sMaxBoundTextureMem*texmem_lower_bound_scale &&
00179 sTotalTextureMemory < sMaxTotalTextureMem*texmem_lower_bound_scale)
00180 {
00181
00182
00183 if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time)
00184 {
00185 sDesiredDiscardBias -= discard_bias_delta;
00186 sEvaluationTimer.reset();
00187 }
00188 }
00189 sDesiredDiscardBias = llclamp(sDesiredDiscardBias, sDesiredDiscardBiasMin, sDesiredDiscardBiasMax);
00190 }
00191
00192
00193
00194 const U32 LLViewerImage::sCurrentFileVersion = 1;
00195
00196 LLViewerImage::LLViewerImage(const LLUUID& id, BOOL usemipmaps)
00197 : LLImageGL(usemipmaps),
00198 mID(id)
00199 {
00200 init(true);
00201 sImageCount++;
00202 }
00203
00204 LLViewerImage::LLViewerImage(const U32 width, const U32 height, const U8 components, BOOL usemipmaps)
00205 : LLImageGL(width, height, components, usemipmaps)
00206 {
00207 init(true);
00208 mNeedsAux = FALSE;
00209
00210 mID.generate();
00211 mFullyLoaded = TRUE;
00212 sImageCount++;
00213 }
00214
00215 LLViewerImage::LLViewerImage(const LLImageRaw* raw, BOOL usemipmaps)
00216 : LLImageGL(raw, usemipmaps)
00217 {
00218 init(true);
00219 mNeedsAux = FALSE;
00220
00221 mID.generate();
00222 mFullyLoaded = TRUE;
00223 sImageCount++;
00224 }
00225
00226 void LLViewerImage::init(bool firstinit)
00227 {
00228 mFullWidth = 0;
00229 mFullHeight = 0;
00230 mNeedsAux = FALSE;
00231 mTexelsPerImage = 64.f*64.f;
00232 mMaxVirtualSize = 0.f;
00233 mDiscardVirtualSize = 0.f;
00234 mMaxCosAngle = -1.f;
00235 mRequestedDiscardLevel = -1;
00236 mRequestedDownloadPriority = 0.f;
00237 mFullyLoaded = FALSE;
00238 mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
00239 mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
00240 mCalculatedDiscardLevel = -1.f;
00241
00242 mDecodingAux = FALSE;
00243
00244 mKnownDrawWidth = 0;
00245 mKnownDrawHeight = 0;
00246
00247 if (firstinit)
00248 {
00249 mDecodePriority = 0.f;
00250 mInImageList = 0;
00251 }
00252 mIsMediaTexture = FALSE;
00253
00254 mBoostLevel = LLViewerImage::BOOST_NONE;
00255
00256
00257
00258 mIsMissingAsset = FALSE;
00259
00260 mNeedsCreateTexture = FALSE;
00261
00262 mIsRawImageValid = FALSE;
00263 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
00264 mMinDiscardLevel = 0;
00265
00266 mTargetHost = LLHost::invalid;
00267
00268 mHasFetcher = FALSE;
00269 mIsFetching = FALSE;
00270 mFetchState = 0;
00271 mFetchPriority = 0;
00272 mDownloadProgress = 0.f;
00273 mFetchDeltaTime = 999999.f;
00274 mDecodeFrame = 0;
00275 mVisibleFrame = 0;
00276 }
00277
00278
00279 void LLViewerImage::dump()
00280 {
00281 LLImageGL::dump();
00282
00283 llinfos << "LLViewerImage"
00284 << " mID " << mID
00285 << " mIsMissingAsset " << (S32)mIsMissingAsset
00286 << " mFullWidth " << mFullWidth
00287 << " mFullHeight " << mFullHeight
00288 << llendl;
00289 }
00290
00292
00293 LLViewerImage::~LLViewerImage()
00294 {
00295 if (mHasFetcher)
00296 {
00297 gTextureFetch->deleteRequest(getID(), true);
00298 }
00299
00300 LLViewerImage::cleanup();
00301 sImageCount--;
00302 }
00303
00304
00306
00307 void LLViewerImage::cleanup()
00308 {
00309 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
00310 iter != mLoadedCallbackList.end(); )
00311 {
00312 LLLoadedCallbackEntry *entryp = *iter++;
00313
00314
00315 entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData );
00316 delete entryp;
00317 }
00318 mLoadedCallbackList.clear();
00319
00320
00321 destroyRawImage();
00322
00323
00324 LLImageGL::cleanup();
00325 }
00326
00327 void LLViewerImage::reinit(BOOL usemipmaps )
00328 {
00329 LLViewerImage::cleanup();
00330 LLImageGL::init(usemipmaps);
00331 init(false);
00332 setSize(0,0,0);
00333 }
00334
00336
00337
00338 BOOL LLViewerImage::createTexture(S32 usename)
00339 {
00340 if (!mNeedsCreateTexture)
00341 {
00342 destroyRawImage();
00343 return FALSE;
00344 }
00345 mNeedsCreateTexture = FALSE;
00346 if (mRawImage.isNull())
00347 {
00348 llerrs << "LLViewerImage trying to create texture with no Raw Image" << llendl;
00349 }
00350
00351
00352
00353
00354 BOOL res = TRUE;
00355 if (!gNoRender)
00356 {
00357 if (LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
00358 {
00359 res = LLImageGL::createGLTexture(mRawDiscardLevel, mRawImage, usename);
00360 }
00361 else
00362 {
00363
00364
00365
00366 setIsMissingAsset();
00367 destroyRawImage();
00368 return FALSE;
00369 }
00370 }
00371
00372
00373
00374
00375
00376
00377 BOOL imageraw_callbacks = FALSE;
00378 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
00379 iter != mLoadedCallbackList.end(); )
00380 {
00381 LLLoadedCallbackEntry *entryp = *iter++;
00382 if (entryp->mNeedsImageRaw)
00383 {
00384 imageraw_callbacks = TRUE;
00385 break;
00386 }
00387 }
00388
00389 if (!imageraw_callbacks)
00390 {
00391 destroyRawImage();
00392 }
00393 return res;
00394 }
00395
00396
00397
00398 void LLViewerImage::addTextureStats(F32 pixel_area,
00399 F32 texel_area_ratio,
00400 F32 cos_center_angle) const
00401 {
00402 F32 virtual_size = pixel_area / texel_area_ratio;
00403 if (virtual_size > mMaxVirtualSize)
00404 {
00405 mMaxVirtualSize = virtual_size;
00406 }
00407 cos_center_angle = llclamp(cos_center_angle, -1.f, 1.f);
00408 if (cos_center_angle > mMaxCosAngle)
00409 {
00410 mMaxCosAngle = cos_center_angle;
00411 }
00412 }
00413
00414 void LLViewerImage::resetTextureStats(BOOL zero)
00415 {
00416 if (zero)
00417 {
00418 mMaxVirtualSize = 0.0f;
00419 mMaxCosAngle = -1.0f;
00420 }
00421 else
00422 {
00423 mMaxVirtualSize -= mMaxVirtualSize * .10f;
00424 mMaxCosAngle = -1.0f;
00425 }
00426 }
00427
00428
00429 void LLViewerImage::processTextureStats()
00430 {
00431
00432 if (mDontDiscard || !getUseMipMaps())
00433 {
00434 mDesiredDiscardLevel = 0;
00435 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
00436 mDesiredDiscardLevel = 1;
00437 }
00438 else if (mBoostLevel < LLViewerImage::BOOST_HIGH && mMaxVirtualSize <= 10.f)
00439 {
00440
00441 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1));
00442 }
00443 else if ((!mFullWidth && !mWidth) || (!mFullHeight && !mHeight))
00444 {
00445 mDesiredDiscardLevel = mMaxDiscardLevel;
00446 }
00447 else
00448 {
00449
00450 static const F64 log_4 = log(4.0);
00451
00452 S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT);
00453 S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT);
00454 mTexelsPerImage = (F32)fullwidth * fullheight;
00455
00456 F32 discard_level = 0.f;
00457
00458
00459
00460
00461 if (mBoostLevel == LLViewerImage::BOOST_UI ||
00462 mBoostLevel == LLViewerImage::BOOST_PREVIEW ||
00463 mBoostLevel == LLViewerImage::BOOST_AVATAR_SELF)
00464 {
00465 discard_level = 0;
00466 }
00467 else if (mKnownDrawWidth && mKnownDrawHeight)
00468 {
00469 S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight;
00470
00471
00472
00473
00474 discard_level = (F32)(log(mTexelsPerImage/draw_texels) / log_4);
00475 }
00476 else
00477 {
00478 if ((mCalculatedDiscardLevel >= 0.f) &&
00479 (llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f))
00480 {
00481
00482 discard_level = mCalculatedDiscardLevel;
00483 }
00484 else
00485 {
00486
00487 discard_level = (F32)(log(mTexelsPerImage/mMaxVirtualSize) / log_4);
00488 mDiscardVirtualSize = mMaxVirtualSize;
00489 mCalculatedDiscardLevel = discard_level;
00490 }
00491 }
00492 if (mBoostLevel < LLViewerImage::BOOST_HIGH)
00493 {
00494 static const F32 discard_bias = -.5f;
00495 discard_level += discard_bias;
00496 discard_level += sDesiredDiscardBias;
00497 discard_level *= sDesiredDiscardScale;
00498 }
00499 discard_level = floorf(discard_level);
00500
00501
00502 F32 min_discard = 0.f;
00503 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
00504 min_discard = 1.f;
00505
00506 discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL);
00507
00508
00509 mDesiredDiscardLevel = llmin((S32)mMaxDiscardLevel+1, (S32)discard_level);
00510
00511 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel);
00512
00513
00514
00515
00516
00517
00518
00519 BOOL increase_discard = FALSE;
00520 S32 current_discard = getDiscardLevel();
00521 if ((sDesiredDiscardBias > 0.0f) &&
00522 (current_discard >= 0 && mDesiredDiscardLevel >= current_discard))
00523 {
00524 if ( sBoundTextureMemory > sMaxBoundTextureMem*texmem_middle_bound_scale)
00525 {
00526
00527 if (mDesiredDiscardLevel > current_discard)
00528 {
00529 increase_discard = TRUE;
00530 }
00531 }
00532 if ( sTotalTextureMemory > sMaxTotalTextureMem*texmem_middle_bound_scale)
00533 {
00534
00535 if (!getBoundRecently())
00536 {
00537 increase_discard = TRUE;
00538 }
00539 }
00540 if (increase_discard)
00541 {
00542
00543 sBoundTextureMemory -= mTextureMemory;
00544 sTotalTextureMemory -= mTextureMemory;
00545
00546 S32 new_discard = current_discard+1;
00547 setDiscardLevel(new_discard);
00548 sBoundTextureMemory += mTextureMemory;
00549 sTotalTextureMemory += mTextureMemory;
00550 }
00551 }
00552 }
00553 }
00554
00555
00556
00557 F32 LLViewerImage::calcDecodePriority()
00558 {
00559 #ifndef LL_RELEASE_FOR_DOWNLOAD
00560 if (mID == gTextureFetch->mDebugID)
00561 {
00562 gTextureFetch->mDebugCount++;
00563 }
00564 #endif
00565
00566 if (mNeedsCreateTexture)
00567 {
00568 return mDecodePriority;
00569 }
00570
00571 F32 priority;
00572 S32 cur_discard = getDiscardLevel();
00573 F32 pixel_priority = fsqrtf(mMaxVirtualSize) * (1.f + mMaxCosAngle);
00574 const S32 MIN_NOT_VISIBLE_FRAMES = 30;
00575 mDecodeFrame++;
00576 if (pixel_priority > 0.f)
00577 {
00578 mVisibleFrame = mDecodeFrame;
00579 }
00580
00581 if (mIsMissingAsset)
00582 {
00583 priority = 0.0f;
00584 }
00585 else if (mDesiredDiscardLevel > mMaxDiscardLevel)
00586 {
00587
00588 priority = -1.0f;
00589 }
00590 else if (pixel_priority <= 0.f && (cur_discard < 0 || mDesiredDiscardLevel < cur_discard))
00591 {
00592
00593 if (mBoostLevel > BOOST_HIGH)
00594 {
00595
00596 priority = 1.f;
00597 }
00598 else if (mVisibleFrame == 0 || (mDecodeFrame - mVisibleFrame > MIN_NOT_VISIBLE_FRAMES))
00599 {
00600
00601 priority = -2.0f;
00602 }
00603 else
00604 {
00605
00606 return mDecodePriority;
00607 }
00608 }
00609 else if (cur_discard < 0)
00610 {
00611
00612
00613 static const F64 log_2 = log(2.0);
00614 F32 desired = (F32)(log(1024.0/pixel_priority) / log_2);
00615 S32 ddiscard = MAX_DISCARD_LEVEL - (S32)desired + 1;
00616 ddiscard = llclamp(ddiscard, 1, 9);
00617 priority = ddiscard*100000.f;
00618 }
00619 else if (cur_discard <= mMinDiscardLevel)
00620 {
00621
00622 priority = -3.0f;
00623 }
00624 else if (cur_discard <= mDesiredDiscardLevel)
00625 {
00626 priority = -4.0f;
00627 }
00628 else
00629 {
00630
00631 S32 ddiscard = cur_discard - mDesiredDiscardLevel;
00632 if (getDontDiscard())
00633 {
00634 ddiscard+=2;
00635 }
00636 else if (!getBoundRecently() && mBoostLevel == 0)
00637 {
00638 ddiscard-=2;
00639 }
00640 ddiscard = llclamp(ddiscard, 0, 4);
00641 priority = ddiscard*100000.f;
00642 }
00643 if (priority > 0.0f)
00644 {
00645 pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f);
00646 priority += pixel_priority;
00647 if ( mBoostLevel > BOOST_HIGH)
00648 {
00649 priority += 1000000.f + 1000.f * mBoostLevel;
00650 }
00651 else if ( mBoostLevel > 0)
00652 {
00653 priority += 0.f + 1000.f * mBoostLevel;
00654 }
00655 }
00656 return priority;
00657 }
00658
00659
00660
00661 F32 LLViewerImage::maxDecodePriority()
00662 {
00663 return 2000000.f;
00664 }
00665
00666 void LLViewerImage::setDecodePriority(F32 priority)
00667 {
00668 llassert(!mInImageList);
00669 if (priority < 0.0f)
00670 {
00671 mDecodePriority = calcDecodePriority();
00672 }
00673 else
00674 {
00675 mDecodePriority = priority;
00676 }
00677 }
00678
00679 void LLViewerImage::setBoostLevel(S32 level)
00680 {
00681 mBoostLevel = level;
00682 if (level >= LLViewerImage::BOOST_HIGH)
00683 {
00684 processTextureStats();
00685 }
00686 }
00687
00688
00689
00690 bool LLViewerImage::updateFetch()
00691 {
00692 mFetchState = 0;
00693 mFetchPriority = 0;
00694 mFetchDeltaTime = 999999.f;
00695 mRequestDeltaTime = 999999.f;
00696
00697 #ifndef LL_RELEASE_FOR_DOWNLOAD
00698 if (mID == gTextureFetch->mDebugID)
00699 {
00700 gTextureFetch->mDebugCount++;
00701 }
00702 #endif
00703
00704 if (mIsMediaTexture)
00705 {
00706 llassert_always(!mHasFetcher);
00707 return false;
00708 }
00709 if (mNeedsCreateTexture)
00710 {
00711
00712
00713 return false;
00714 }
00715 if (mFullyLoaded)
00716 {
00717 llassert_always(!mHasFetcher);
00718 return false;
00719 }
00720 if (mIsMissingAsset)
00721 {
00722 llassert_always(!mHasFetcher);
00723 return false;
00724 }
00725 if (!mLoadedCallbackList.empty() && mRawImage.notNull())
00726 {
00727 return false;
00728 }
00729
00730 S32 current_discard = getDiscardLevel();
00731 S32 desired_discard = getDesiredDiscardLevel();
00732 F32 decode_priority = getDecodePriority();
00733
00734 if (mIsFetching)
00735 {
00736
00737 S32 fetch_discard = current_discard;
00738 bool finished = gTextureFetch->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
00739 if (finished)
00740 {
00741 mIsFetching = FALSE;
00742 }
00743 else
00744 {
00745 mFetchState = gTextureFetch->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
00746 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
00747 }
00748
00749
00750 if (mRawImage.notNull())
00751 {
00752 mRawDiscardLevel = fetch_discard;
00753 if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) &&
00754 (current_discard < 0 || mRawDiscardLevel < current_discard))
00755 {
00756 if (getComponents() != mRawImage->getComponents())
00757 {
00758
00759
00760 mComponents = mRawImage->getComponents();
00761 gImageList.dirtyImage(this);
00762 }
00763 mIsRawImageValid = TRUE;
00764 gImageList.mCreateTextureList.insert(this);
00765 mNeedsCreateTexture = TRUE;
00766 mFullWidth = mRawImage->getWidth() << mRawDiscardLevel;
00767 mFullHeight = mRawImage->getHeight() << mRawDiscardLevel;
00768 }
00769 else
00770 {
00771
00772
00773 destroyRawImage();
00774 return false;
00775 }
00776 }
00777
00778 if (!mIsFetching)
00779 {
00780 if (mRawDiscardLevel < 0)
00781 {
00782
00783 if (current_discard < 0)
00784 {
00785 llwarns << mID << ": Marking image as missing" << llendl;
00786 setIsMissingAsset();
00787 desired_discard = -1;
00788 }
00789 else
00790 {
00791 llwarns << mID << ": Setting min discard to " << current_discard << llendl;
00792 mMinDiscardLevel = current_discard;
00793 desired_discard = current_discard;
00794 }
00795 destroyRawImage();
00796 }
00797 else if (mRawImage.isNull())
00798 {
00799
00800
00801 destroyRawImage();
00802 }
00803 }
00804 else if (mDecodePriority >= 0.f)
00805 {
00806 gTextureFetch->updateRequestPriority(mID, mDecodePriority);
00807 }
00808 }
00809
00810 bool make_request = true;
00811
00812 if (decode_priority <= 0)
00813 {
00814 make_request = false;
00815 }
00816 else if (mNeedsCreateTexture || mIsMissingAsset)
00817 {
00818 make_request = false;
00819 }
00820 else if (current_discard >= 0 && current_discard <= mMinDiscardLevel)
00821 {
00822 make_request = false;
00823 }
00824 else
00825 {
00826 if (mIsFetching)
00827 {
00828 if (mRequestedDiscardLevel <= desired_discard)
00829 {
00830 make_request = false;
00831 }
00832 }
00833 else
00834 {
00835 if (current_discard >= 0 && current_discard <= desired_discard)
00836 {
00837 make_request = false;
00838 }
00839 }
00840 }
00841
00842 if (make_request)
00843 {
00844 S32 w=0, h=0, c=0;
00845 if (current_discard >= 0)
00846 {
00847 w = getWidth(0);
00848 h = getHeight(0);
00849 c = getComponents();
00850 }
00851 if (!mDontDiscard)
00852 {
00853 if (mBoostLevel == 0)
00854 {
00855 desired_discard = llmax(desired_discard, current_discard-1);
00856 }
00857 else
00858 {
00859 desired_discard = llmax(desired_discard, current_discard-2);
00860 }
00861 }
00862 if (gTextureFetch->createRequest(getID(),getTargetHost(), decode_priority,
00863 w, h, c, desired_discard,
00864 needsAux()))
00865 {
00866 mHasFetcher = TRUE;
00867 mIsFetching = TRUE;
00868 mRequestedDiscardLevel = desired_discard;
00869 mFetchState = gTextureFetch->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
00870 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
00871 }
00872
00873
00874 }
00875 else if (mHasFetcher && !mIsFetching)
00876 {
00877
00878 const F32 FETCH_IDLE_TIME = 5.f;
00879 if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME)
00880 {
00881
00882 gTextureFetch->deleteRequest(getID(), true);
00883 mHasFetcher = FALSE;
00884 }
00885 }
00886
00887 llassert_always(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid));
00888
00889 return mIsFetching ? true : false;
00890 }
00891
00892 void LLViewerImage::setIsMissingAsset()
00893 {
00894 if (mHasFetcher)
00895 {
00896 gTextureFetch->deleteRequest(getID(), true);
00897 mHasFetcher = FALSE;
00898 mIsFetching = FALSE;
00899 mFetchState = 0;
00900 mFetchPriority = 0;
00901 }
00902 mIsMissingAsset = TRUE;
00903 }
00904
00905
00906
00907 void LLViewerImage::setLoadedCallback( loaded_callback_func loaded_callback, S32 discard_level, BOOL keep_imageraw, void* userdata)
00908 {
00909
00910
00911
00912 if (mLoadedCallbackList.empty())
00913 {
00914
00915 gImageList.mCallbackList.insert(this);
00916 }
00917 LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata);
00918 mLoadedCallbackList.push_back(entryp);
00919 }
00920
00921 bool LLViewerImage::doLoadedCallbacks()
00922 {
00923 if (mNeedsCreateTexture)
00924 {
00925 return false;
00926 }
00927
00928 bool res = false;
00929
00930 if (isMissingAsset())
00931 {
00932 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
00933 iter != mLoadedCallbackList.end(); )
00934 {
00935 LLLoadedCallbackEntry *entryp = *iter++;
00936
00937
00938 entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData);
00939 delete entryp;
00940 }
00941 mLoadedCallbackList.clear();
00942
00943
00944 gImageList.mCallbackList.erase(this);
00945 }
00946
00947 S32 gl_discard = getDiscardLevel();
00948
00949
00950 if (gl_discard == -1)
00951 {
00952 gl_discard = MAX_DISCARD_LEVEL + 1;
00953 }
00954
00955
00956
00957
00958
00959 S32 current_raw_discard = MAX_DISCARD_LEVEL + 1;
00960 S32 best_raw_discard = gl_discard;
00961 S32 current_aux_discard = MAX_DISCARD_LEVEL + 1;
00962 S32 best_aux_discard = MAX_DISCARD_LEVEL + 1;
00963
00964 if (mIsRawImageValid)
00965 {
00966
00967 best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel);
00968 best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel);
00969 current_aux_discard = llmin(current_aux_discard, best_aux_discard);
00970 }
00971 else
00972 {
00973
00974
00975 best_aux_discard = 0;
00976 }
00977
00978
00979
00980
00981
00982
00983 bool run_gl_callbacks = false;
00984 bool run_raw_callbacks = false;
00985 bool need_readback = false;
00986
00987 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
00988 iter != mLoadedCallbackList.end(); )
00989 {
00990 LLLoadedCallbackEntry *entryp = *iter++;
00991 if (entryp->mNeedsImageRaw)
00992 {
00993 if (mNeedsAux)
00994 {
00995
00996
00997
00998 if (entryp->mLastUsedDiscard > current_aux_discard)
00999 {
01000
01001 run_raw_callbacks = true;
01002 }
01003 }
01004 else
01005 {
01006 if (entryp->mLastUsedDiscard > current_raw_discard)
01007 {
01008
01009 run_raw_callbacks = true;
01010 }
01011 else if (entryp->mLastUsedDiscard > best_raw_discard)
01012 {
01013
01014 need_readback = true;
01015 run_raw_callbacks = true;
01016 }
01017 }
01018 }
01019 else
01020 {
01021
01022 if (entryp->mLastUsedDiscard > gl_discard)
01023 {
01024
01025 run_gl_callbacks = true;
01026 }
01027 }
01028 }
01029
01030
01031
01032
01033 if (need_readback && (mMaxDiscardLevel > gl_discard))
01034 {
01035
01036
01037
01038 destroyRawImage();
01039 createRawImage(gl_discard, TRUE);
01040 readBackRaw(gl_discard, mRawImage, false);
01041 mIsRawImageValid = TRUE;
01042 llassert_always(mRawImage.notNull());
01043 llassert_always(!mNeedsAux || mAuxRawImage.notNull());
01044 }
01045
01046
01047
01048
01049 if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= mMaxDiscardLevel))
01050 {
01051
01052
01053
01054
01055 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
01056 iter != mLoadedCallbackList.end(); )
01057 {
01058 callback_list_t::iterator curiter = iter++;
01059 LLLoadedCallbackEntry *entryp = *curiter;
01060 if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel))
01061 {
01062
01063
01064
01065
01066 llassert_always(mRawImage.notNull());
01067 if(mNeedsAux && mAuxRawImage.isNull())
01068 {
01069 llwarns << "Raw Image with no Aux Data for callback" << llendl;
01070 }
01071 BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE;
01072
01073
01074 if (final)
01075 {
01076
01077 }
01078 entryp->mLastUsedDiscard = mRawDiscardLevel;
01079 entryp->mCallback(TRUE, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData);
01080 if (final)
01081 {
01082 iter = mLoadedCallbackList.erase(curiter);
01083 delete entryp;
01084 }
01085 res = true;
01086 }
01087 }
01088 }
01089
01090
01091
01092
01093 if (run_gl_callbacks && (gl_discard <= mMaxDiscardLevel))
01094 {
01095
01096
01097
01098 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
01099 iter != mLoadedCallbackList.end(); )
01100 {
01101 callback_list_t::iterator curiter = iter++;
01102 LLLoadedCallbackEntry *entryp = *curiter;
01103 if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard))
01104 {
01105 BOOL final = gl_discard <= entryp->mDesiredDiscard ? TRUE : FALSE;
01106 entryp->mLastUsedDiscard = gl_discard;
01107 entryp->mCallback(TRUE, this, NULL, NULL, gl_discard, final, entryp->mUserData);
01108 if (final)
01109 {
01110 iter = mLoadedCallbackList.erase(curiter);
01111 delete entryp;
01112 }
01113 res = true;
01114 }
01115 }
01116 }
01117
01118
01119
01120
01121 if (mLoadedCallbackList.empty())
01122 {
01123 gImageList.mCallbackList.erase(this);
01124 }
01125
01126
01127 destroyRawImage();
01128
01129 return res;
01130 }
01131
01132
01133
01134
01135 void LLViewerImage::setKnownDrawSize(S32 width, S32 height)
01136 {
01137 mKnownDrawWidth = width;
01138 mKnownDrawHeight = height;
01139 addTextureStats((F32)(width * height));
01140 }
01141
01142
01143 BOOL LLViewerImage::bind(S32 stage) const
01144 {
01145 if (stage == -1)
01146 {
01147 return TRUE;
01148 }
01149
01150 if (gNoRender)
01151 {
01152 return true;
01153 }
01154 BOOL res = bindTextureInternal(stage);
01155 if (res)
01156 {
01157
01158
01159 }
01160 else
01161 {
01162
01163 if (mIsMissingAsset && !sMissingAssetImagep.isNull() && (this != (LLImageGL *)sMissingAssetImagep))
01164 {
01165 res = sMissingAssetImagep->bind( stage );
01166 }
01167 if (!res && !sDefaultImagep.isNull() && (this != (LLImageGL *)sDefaultImagep))
01168 {
01169
01170 res = sDefaultImagep->bind(stage);
01171 }
01172 if (!res && !sNullImagep.isNull() && (this != (LLImageGL *)sNullImagep))
01173 {
01174 res = sNullImagep->bind(stage);
01175 }
01176 if (!res)
01177 {
01178 llwarns << "LLViewerImage::bindTexture failed." << llendl;
01179 }
01180 stop_glerror();
01181 }
01182 return res;
01183 }
01184
01185
01186 LLImageRaw* LLViewerImage::createRawImage(S8 discard_level, BOOL allocate)
01187 {
01188 llassert(discard_level >= 0);
01189 if (mRawImage.notNull())
01190 {
01191 llerrs << "createRawImage() called with existing mRawImage" << llendl;
01192 mRawImage = NULL;
01193 mAuxRawImage = NULL;
01194 }
01195 if (allocate && mComponents)
01196 {
01197 mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), mComponents);
01198 mIsRawImageValid = TRUE;
01199 }
01200 else
01201 {
01202 mRawImage = new LLImageRaw;
01203 mIsRawImageValid = FALSE;
01204 }
01205 mRawDiscardLevel = discard_level;
01206
01207 return mRawImage;
01208 }
01209
01210 void LLViewerImage::destroyRawImage()
01211 {
01212 mRawImage = NULL;
01213 mAuxRawImage = NULL;
01214 mIsRawImageValid = FALSE;
01215 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
01216 }