llviewerimage.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llviewerimage.h"
00035 
00036 // Library includes
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 // viewer includes
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 // statics
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; // -max number of levels to improve image quality by
00074 static F32 sDesiredDiscardBiasMax = 1.5f; // max number of levels to reduce image quality by
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 // static
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 // static
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 // tuning params
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); // 128 MB
00143 // non-const (used externally
00144 F32 texmem_lower_bound_scale = 0.85f;
00145 F32 texmem_middle_bound_scale = 0.925f;
00146 
00147 //static
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                 // If we are using more texture memory than we should,
00169                 // scale up the desired discard level
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                 // If we are using less texture memory than we should,
00181                 // scale down the desired discard level
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 // static
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         // Create an empty image of the specified size and width
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         // Create an empty image of the specified size and width
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         // Only set mIsMissingAsset true when we know for certain that the database
00274         // does not contain this image.
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 // virtual
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         // Explicitly call LLViewerImage::cleanup since we're in a destructor and cleanup is virtual
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                 // We never finished loading the image.  Indicate failure.
00333                 // Note: this allows mLoadedCallbackUserData to be cleaned up.
00334                 entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData );
00335                 delete entryp;
00336         }
00337         mLoadedCallbackList.clear();
00338 
00339         // Clean up image data
00340         destroyRawImage();
00341         
00342         // LLImageGL::cleanup will get called more than once when this is used in the destructor.
00343         LLImageGL::cleanup();
00344 }
00345 
00346 void LLViewerImage::reinit(BOOL usemipmaps /* = TRUE */)
00347 {
00348         LLViewerImage::cleanup();
00349         LLImageGL::init(usemipmaps);
00350         init(false);
00351         setSize(0,0,0);
00352 }
00353 
00355 
00356 // ONLY called from LLViewerImageList
00357 BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
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 //      llinfos << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ",
00370 //                                              mRawDiscardLevel, 
00371 //                                              mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize())
00372 //                      << mID.getString() << llendl;
00373         BOOL res = TRUE;
00374         if (!gNoRender)
00375         {
00376                 // store original size only for locally-sourced images
00377                 if (!mLocalFileName.empty())
00378                 {
00379                         mOrigWidth = mRawImage->getWidth();
00380                         mOrigHeight = mRawImage->getHeight();
00381 
00382                         // leave black border, do not scale image content
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                         // A non power-of-two image was uploaded (through a non standard client)
00399                         // We treat these images as missing assets which causes them to
00400                         // be renderd as 'missing image' and to stop requesting data
00401                         setIsMissingAsset();
00402                         destroyRawImage();
00403                         return FALSE;
00404                 }
00405         }
00406 
00407         //
00408         // Iterate through the list of image loading callbacks to see
00409         // what sort of data they need.
00410         //
00411         // *TODO: Fix image callback code
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, // = 1.0
00435                                                                     F32 cos_center_angle) const // = 1.0
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) //don't decay sculpted prim textures
00457         {
00458                 mMaxVirtualSize -= mMaxVirtualSize * .10f; // decay by 5%/update
00459                 mMaxCosAngle = -1.0f;
00460         }
00461 }
00462 
00463 // This is gauranteed to get called periodically for every texture
00464 void LLViewerImage::processTextureStats()
00465 {
00466         // Generate the request priority and render priority
00467         if (mDontDiscard || !getUseMipMaps())
00468         {
00469                 mDesiredDiscardLevel = 0;
00470                 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
00471                         mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
00472         }
00473         else if (mBoostLevel < LLViewerImage::BOOST_HIGH && mMaxVirtualSize <= 10.f)
00474         {
00475                 // If the image has not been significantly visible in a while, we don't want it
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                 //static const F64 log_2 = log(2.0);
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                 // If we know the output width and height, we can force the discard
00494                 // level to the correct value, and thus not decode more texture
00495                 // data than we need to.
00496                 if (mBoostLevel == LLViewerImage::BOOST_UI ||
00497                         mBoostLevel == LLViewerImage::BOOST_PREVIEW ||
00498                         mBoostLevel == LLViewerImage::BOOST_AVATAR_SELF)        // JAMESDEBUG what about AVATAR_BAKED_SELF?
00499                 {
00500                         discard_level = 0; // full res
00501                 }
00502                 else if (mKnownDrawWidth && mKnownDrawHeight)
00503                 {
00504                         S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight;
00505 
00506                         // Use log_4 because we're in square-pixel space, so an image
00507                         // with twice the width and twice the height will have mTexelsPerImage
00508                         // 4 * draw_size
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                                 // < 20% change in virtual size = no change in desired discard
00517                                 discard_level = mCalculatedDiscardLevel; 
00518                         }
00519                         else
00520                         {
00521                                 // Calculate the required scale factor of the image using pixels per texel
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; // Must be < 1 or highest discard will never load!
00530                         discard_level += discard_bias;
00531                         discard_level += sDesiredDiscardBias;
00532                         discard_level *= sDesiredDiscardScale; // scale
00533                 }
00534                 discard_level = floorf(discard_level);
00535 //              discard_level -= (gImageList.mVideoMemorySetting>>1); // more video ram = higher detail
00536 
00537                 F32 min_discard = 0.f;
00538                 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
00539                         min_discard = 1.f; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
00540 
00541                 discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL);
00542                 
00543                 // Can't go higher than the max discard level
00544                 mDesiredDiscardLevel = llmin((S32)mMaxDiscardLevel+1, (S32)discard_level);
00545                 // Clamp to min desired discard
00546                 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel);
00547 
00548                 //
00549                 // At this point we've calculated the quality level that we want,
00550                 // if possible.  Now we check to see if we have it, and take the
00551                 // proper action if we don't.
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                                 // Limit the amount of GL memory bound each frame
00562                                 if (mDesiredDiscardLevel > current_discard)
00563                                 {
00564                                         increase_discard = TRUE;
00565                                 }
00566                         }
00567                         if ( sTotalTextureMemory > sMaxTotalTextureMem*texmem_middle_bound_scale)
00568                         {
00569                                 // Only allow GL to have 2x the video card memory
00570                                 if (!getBoundRecently())
00571                                 {
00572                                         increase_discard = TRUE;
00573                                 }
00574                         }
00575                         if (increase_discard)
00576                         {
00577                                 //                      llinfos << "DISCARDED: " << mID << " Discard: " << current_discard << llendl;
00578                                 sBoundTextureMemory -= mTextureMemory;
00579                                 sTotalTextureMemory -= mTextureMemory;
00580                                 // Increase the discard level (reduce the texture res)
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++; // for setting breakpoints
00598         }
00599 #endif
00600         
00601         if (mNeedsCreateTexture)
00602         {
00603                 return mDecodePriority; // no change while waiting to create
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; // NOTE: this function is not called every frame
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                 // Don't decode anything we don't need
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                 // Not on screen but we might want some data
00632                 if (mBoostLevel > BOOST_HIGH)
00633                 {
00634                         // Always want high boosted images
00635                         priority = 1.f;
00636                 }
00637                 else if (mVisibleFrame == 0 || (mDecodeFrame - mVisibleFrame > MIN_NOT_VISIBLE_FRAMES))
00638                 {
00639                         // Don't decode anything that isn't visible unless it's important
00640                         priority = -2.0f;
00641                 }
00642                 else
00643                 {
00644                         // Leave the priority as-is
00645                         return mDecodePriority;
00646                 }
00647         }
00648         else if (cur_discard < 0)
00649         {
00650                 // We don't have any data yet, so we don't know the size of the image, treat as 1024x1024
00651 //              priority = 900000.f;
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                 // larger mips are corrupted
00661                 priority = -3.0f;
00662         }
00663         else if (cur_discard <= mDesiredDiscardLevel)
00664         {
00665                 priority = -4.0f;
00666         }
00667         else
00668         {
00669                 // priority range = 100000-400000
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 // A value >= max value calculated above for normalization
00699 //static
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++; // for setting breakpoints
00740         }
00741 #endif
00742         
00743         if (mIsMediaTexture)
00744         {
00745                 llassert_always(!mHasFetcher);
00746                 return false; // skip
00747         }
00748         if (mNeedsCreateTexture)
00749         {
00750                 // We may be fetching still (e.g. waiting on write)
00751                 // but don't check until we've processed the raw data we have
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; // skip
00763         }
00764         if (!mLoadedCallbackList.empty() && mRawImage.notNull())
00765         {
00766                 return false; // process any raw image data in callbacks before replacing
00767         }
00768         
00769         S32 current_discard = getDiscardLevel();
00770         S32 desired_discard = getDesiredDiscardLevel();
00771         F32 decode_priority = getDecodePriority();
00772         
00773         if (mIsFetching)
00774         {
00775                 // Sets mRawDiscardLevel, mRawImage, mAuxRawImage
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                 // We may have data ready regardless of whether or not we are finished (e.g. waiting on write)
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                                         // We've changed the number of components, so we need to move any
00798                                         // objects using this pool to a different pool.
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                                 // Data is ready but we don't need it
00811                                 // (received it already while fetcher was writing to disk)
00812                                 destroyRawImage();
00813                                 return false; // done
00814                         }
00815                 }
00816                 
00817                 if (!mIsFetching)
00818                 {
00819                         if (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL)
00820                         {
00821                                 // We finished but received no data
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                                 // We have data, but our fetch failed to return raw data
00838                                 // *TODO: FIgure out why this is happening and fix it
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                 // bypass texturefetch directly by pulling from LLTextureCache
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                 // if createRequest() failed, we're finishing up a request for this UUID,
00926                 // wait for it to complete
00927         }
00928         else if (mHasFetcher && !mIsFetching)
00929         {
00930                 // Only delete requests that haven't receeived any network data for a while
00931                 const F32 FETCH_IDLE_TIME = 5.f;
00932                 if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME)
00933                 {
00934 //                      llinfos << "Deleting request: " << getID() << " Discard: " << current_discard << " <= min:" << mMinDiscardLevel << " or priority == 0: " << decode_priority << llendl;
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         // Don't do ANYTHING here, just add it to the global callback list
00965         //
00966         if (mLoadedCallbackList.empty())
00967         {
00968                 // Put in list to call this->doLoadedCallbacks() periodically
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                         // We never finished loading the image.  Indicate failure.
00991                         // Note: this allows mLoadedCallbackUserData to be cleaned up.
00992                         entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData);
00993                         delete entryp;
00994                 }
00995                 mLoadedCallbackList.clear();
00996 
00997                 // Remove ourself from the global list of textures with callbacks
00998                 gImageList.mCallbackList.erase(this);
00999         }
01000 
01001         S32 gl_discard = getDiscardLevel();
01002 
01003         // If we don't have a legit GL image, set it to be lower than the worst discard level
01004         if (gl_discard == -1)
01005         {
01006                 gl_discard = MAX_DISCARD_LEVEL + 1;
01007         }
01008 
01009         //
01010         // Determine the quality levels of textures that we can provide to callbacks
01011         // and whether we need to do decompression/readback to get it
01012         //
01013         S32 current_raw_discard = MAX_DISCARD_LEVEL + 1; // We can always do a readback to get a raw discard
01014         S32 best_raw_discard = gl_discard;      // Current GL quality level
01015         S32 current_aux_discard = MAX_DISCARD_LEVEL + 1;
01016         S32 best_aux_discard = MAX_DISCARD_LEVEL + 1;
01017 
01018         if (mIsRawImageValid)
01019         {
01020                 // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels.
01021                 best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel);
01022                 best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw
01023                 current_aux_discard = llmin(current_aux_discard, best_aux_discard);
01024         }
01025         else
01026         {
01027                 // We have no data at all, we need to get it
01028                 // Do this by forcing the best aux discard to be 0.
01029                 best_aux_discard = 0;
01030         }
01031 
01032 
01033         //
01034         // See if any of the callbacks would actually run using the data that we can provide,
01035         // and also determine if we need to perform any readbacks or decodes.
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                                 // Need raw and auxiliary channels
01051                                 //
01052                                 if (entryp->mLastUsedDiscard > current_aux_discard)
01053                                 {
01054                                         // We have useful data, run the callbacks
01055                                         run_raw_callbacks = true;
01056                                 }
01057                         }
01058                         else
01059                         {
01060                                 if (entryp->mLastUsedDiscard > current_raw_discard)
01061                                 {
01062                                         // We have useful data, just run the callbacks
01063                                         run_raw_callbacks = true;
01064                                 }
01065                                 else if (entryp->mLastUsedDiscard > best_raw_discard)
01066                                 {
01067                                         // We can readback data, and then run the callbacks
01068                                         need_readback = true;
01069                                         run_raw_callbacks = true;
01070                                 }
01071                         }
01072                 }
01073                 else
01074                 {
01075                         // Needs just GL
01076                         if (entryp->mLastUsedDiscard > gl_discard)
01077                         {
01078                                 // We have enough data, run this callback requiring GL data
01079                                 run_gl_callbacks = true;
01080                         }
01081                 }
01082         }
01083 
01084         //
01085         // Do a readback if required, OR start off a texture decode
01086         //
01087         if (need_readback && (mMaxDiscardLevel > gl_discard))
01088         {
01089                 // Do a readback to get the GL data into the raw image
01090                 // We have GL data.
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         // Run raw/auxiliary data callbacks
01102         //
01103         if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= mMaxDiscardLevel))
01104         {
01105                 // Do callbacks which require raw image data.
01106                 //llinfos << "doLoadedCallbacks raw for " << getID() << llendl;
01107 
01108                 // Call each party interested in the raw data.
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                                 // If we've loaded all the data there is to load or we've loaded enough
01117                                 // to satisfy the interested party, then this is the last time that
01118                                 // we're going to call them.
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                                 //llinfos << "Running callback for " << getID() << llendl;
01127                                 //llinfos << mRawImage->getWidth() << "x" << mRawImage->getHeight() << llendl;
01128                                 if (final)
01129                                 {
01130                                         //llinfos << "Final!" << llendl;
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         // Run GL callbacks
01146         //
01147         if (run_gl_callbacks && (gl_discard <= mMaxDiscardLevel))
01148         {
01149                 //llinfos << "doLoadedCallbacks GL for " << getID() << llendl;
01150 
01151                 // Call the callbacks interested in GL data.
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         // If we have no callbacks, take us off of the image callback list.
01174         //
01175         if (mLoadedCallbackList.empty())
01176         {
01177                 gImageList.mCallbackList.erase(this);
01178         }
01179 
01180         // Done with any raw image data at this point (will be re-created if we still have callbacks)
01181         destroyRawImage();
01182         
01183         return res;
01184 }
01185 
01186 //============================================================================
01187 
01188 // Call with 0,0 to turn this feature off.
01189 void LLViewerImage::setKnownDrawSize(S32 width, S32 height)
01190 {
01191         mKnownDrawWidth = width;
01192         mKnownDrawHeight = height;
01193         addTextureStats((F32)(width * height));
01194 }
01195 
01196 // virtual
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                 //llassert_always(mIsMissingAsset == FALSE);
01212                 
01213         }
01214         else
01215         {
01216                 // On failure to bind, what should we set the currently bound texture to?
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                         // use default if we've got it
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 // Was in LLImageGL
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 }

Generated on Fri May 16 08:34:09 2008 for SecondLife by  doxygen 1.5.5