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