00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llviewerimagelist.h"
00035
00036 #include "imageids.h"
00037 #include "llgl.h"
00038 #include "llimagegl.h"
00039 #include "llimagebmp.h"
00040 #include "llimagej2c.h"
00041 #include "llimagetga.h"
00042 #include "llimagejpeg.h"
00043 #include "llimagepng.h"
00044
00045 #include "llsdserialize.h"
00046 #include "llsys.h"
00047 #include "llvfs.h"
00048 #include "llvfile.h"
00049 #include "llvfsthread.h"
00050 #include "message.h"
00051
00052 #include "llagent.h"
00053 #include "lltexturecache.h"
00054 #include "lltexturefetch.h"
00055 #include "llviewercontrol.h"
00056 #include "llviewerimage.h"
00057 #include "llviewermedia.h"
00058 #include "llviewerregion.h"
00059 #include "pipeline.h"
00060 #include "llappviewer.h"
00061
00062 #include <sys/stat.h>
00063
00065
00066 void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL;
00067
00068 U32 LLViewerImageList::sTextureBits = 0;
00069 U32 LLViewerImageList::sTexturePackets = 0;
00070
00071 const S32 IMAGES_PER_REQUEST = 42;
00072 const S32 IMAGES_MIN_UPDATES = 4;
00073 const S32 IMAGES_MAX_PACKET_UPDATES = 1;
00074 const F32 RESEND_IMAGE_REQUEST_TIME = 15.f;
00075
00076 LLViewerImageList gImageList;
00077
00078 S32 LLViewerImageList::sNumImages = 0;
00079 LLStat LLViewerImageList::sNumImagesStat(32, TRUE);
00080 LLStat LLViewerImageList::sNumRawImagesStat(32, TRUE);
00081 LLStat LLViewerImageList::sGLTexMemStat(32, TRUE);
00082 LLStat LLViewerImageList::sGLBoundMemStat(32, TRUE);
00083 LLStat LLViewerImageList::sRawMemStat(32, TRUE);
00084 LLStat LLViewerImageList::sFormattedMemStat(32, TRUE);
00085
00087
00088 LLViewerImageList::LLViewerImageList()
00089 : mForceResetTextureStats(FALSE),
00090 mUpdateStats(FALSE),
00091 mMaxResidentTexMem(0)
00092 {
00093 }
00094
00095 void LLViewerImageList::init()
00096 {
00097 sNumImages = 0;
00098 mMaxResidentTexMem = 0;
00099
00100 if (gNoRender)
00101 {
00102
00103 return;
00104 }
00105
00106 mUpdateStats = TRUE;
00107
00108
00109 updateMaxResidentTexMem(0);
00110
00111 doPreloadImages();
00112 }
00113
00114
00115 void LLViewerImageList::doPreloadImages()
00116 {
00117 LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL;
00118
00119
00120 LLViewerImage::sMissingAssetImagep = getImageFromFile("missing_asset.tga");
00121
00122
00123 LLViewerImage::sWhiteImagep = getImageFromFile("white.tga");
00124
00125 LLUIImageList* image_list = LLUIImageList::getInstance();
00126
00127 image_list->initFromFile(gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", "textures.xml"));
00128
00129
00130 getImage(IMG_SHOT, TRUE);
00131 getImage(IMG_SMOKE_POOF, TRUE);
00132 LLViewerImage* image = getImageFromFile("silhouette.j2c", MIPMAP_YES, IMMEDIATE_YES);
00133 if (image)
00134 {
00135 image->setClamp(FALSE, FALSE);
00136 mImagePreloads.insert(image);
00137 }
00138 image = getImageFromFile("noentrylines.j2c", MIPMAP_YES, IMMEDIATE_YES);
00139 if (image)
00140 {
00141 image->setClamp(FALSE, FALSE);
00142 mImagePreloads.insert(image);
00143 }
00144 image = getImageFromFile("noentrypasslines.j2c", MIPMAP_YES, IMMEDIATE_YES);
00145 if (image)
00146 {
00147 image->setClamp(FALSE, FALSE);
00148 mImagePreloads.insert(image);
00149 }
00150 image = getImage(DEFAULT_WATER_NORMAL, MIPMAP_YES, IMMEDIATE_YES);
00151 if (image)
00152 {
00153 image->setClamp(FALSE, FALSE);
00154 mImagePreloads.insert(image);
00155 }
00156 }
00157
00158 static std::string get_texture_list_name()
00159 {
00160 BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
00161 return std::string("texture_list_") + (login_last?"last":"home") + ".xml";
00162 }
00163
00164 void LLViewerImageList::doPrefetchImages()
00165 {
00166 if (LLAppViewer::instance()->getPurgeCache())
00167 {
00168
00169 return;
00170 }
00171
00172
00173 LLSD imagelist;
00174 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
00175 llifstream file;
00176 file.open(filename.c_str());
00177 if (file.is_open())
00178 {
00179 LLSDSerialize::fromXML(imagelist, file);
00180 }
00181 for (LLSD::array_iterator iter = imagelist.beginArray();
00182 iter != imagelist.endArray(); ++iter)
00183 {
00184 LLSD imagesd = *iter;
00185 LLUUID uuid = imagesd["uuid"];
00186 S32 pixel_area = imagesd["area"];
00187 LLViewerImage* image = getImage(uuid, MIPMAP_TRUE, FALSE);
00188 if (image)
00189 {
00190 image->addTextureStats((F32)pixel_area);
00191 }
00192 }
00193
00194
00195 }
00196
00198
00199 LLViewerImageList::~LLViewerImageList()
00200 {
00201 llassert(mIRCallbackData.empty());
00202 }
00203
00204 void LLViewerImageList::shutdown()
00205 {
00206
00207 mImagePreloads.clear();
00208
00209
00210 typedef std::set<std::pair<S32,LLViewerImage*> > image_area_list_t;
00211 image_area_list_t image_area_list;
00212 for (image_priority_list_t::iterator iter = mImageList.begin();
00213 iter != mImageList.end(); ++iter)
00214 {
00215 LLViewerImage* image = *iter;
00216 if (!image->getUseDiscard() ||
00217 image->needsAux() ||
00218 image->getTargetHost() != LLHost::invalid)
00219 {
00220 continue;
00221 }
00222 S32 desired = image->getDesiredDiscardLevel();
00223 if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
00224 {
00225 S32 pixel_area = image->getWidth(desired) * image->getHeight(desired);
00226 image_area_list.insert(std::make_pair(pixel_area, image));
00227 }
00228 }
00229
00230 LLSD imagelist;
00231 const S32 max_count = 1000;
00232 S32 count = 0;
00233 for (image_area_list_t::reverse_iterator riter = image_area_list.rbegin();
00234 riter != image_area_list.rend(); ++riter)
00235 {
00236 LLViewerImage* image = riter->second;
00237 imagelist[count]["area"] = riter->first;
00238 imagelist[count]["uuid"] = image->getID();
00239 if (++count >= max_count)
00240 break;
00241 }
00242
00243 if (count > 0 && !gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "").empty())
00244 {
00245 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
00246 llofstream file;
00247 file.open(filename.c_str());
00248 LLSDSerialize::toPrettyXML(imagelist, file);
00249 }
00250
00251
00252
00253
00254 mCallbackList.clear();
00255 mIRCallbackData.clear();
00256
00257
00258 mLoadingStreamList.clear();
00259 mCreateTextureList.clear();
00260
00261 mUUIDMap.clear();
00262
00263 mImageList.clear();
00264 }
00265
00266 void LLViewerImageList::dump()
00267 {
00268 llinfos << "LLViewerImageList::dump()" << llendl;
00269 for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
00270 {
00271 LLViewerImage* image = *it;
00272
00273 llinfos << "priority " << image->getDecodePriority()
00274 << " boost " << image->getBoostLevel()
00275 << " size " << image->getWidth() << "x" << image->getHeight()
00276 << " discard " << image->getDiscardLevel()
00277 << " desired " << image->getDesiredDiscardLevel()
00278 << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
00279 << llendl;
00280 }
00281 }
00282
00283 void LLViewerImageList::destroyGL(BOOL save_state)
00284 {
00285 LLImageGL::destroyGL(save_state);
00286 }
00287
00288 void LLViewerImageList::restoreGL()
00289 {
00290 LLImageGL::restoreGL();
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00301
00302 LLViewerImage* LLViewerImageList::getImageFromFile(const LLString& filename,
00303 BOOL usemipmaps,
00304 BOOL level_immediate,
00305 LLGLint internal_format,
00306 LLGLenum primary_format,
00307 const LLUUID& force_id)
00308 {
00309 if (gNoRender)
00310 {
00311
00312
00313 return getImage(IMG_DEFAULT, TRUE, TRUE);
00314 }
00315
00316 if (filename.empty())
00317 {
00318 return getImage(IMG_DEFAULT, TRUE, TRUE);
00319 }
00320
00321
00322 LLUUID new_id;
00323 if (force_id.notNull())
00324 {
00325 new_id = force_id;
00326 }
00327 else
00328 {
00329 new_id.generate(std::string(filename));
00330 }
00331
00332 LLPointer<LLViewerImage> imagep = hasImage(new_id);
00333
00334 if (imagep.isNull())
00335 {
00336 imagep = new LLViewerImage(filename, new_id, usemipmaps);
00337
00338 if (internal_format && primary_format)
00339 {
00340 imagep->setExplicitFormat(internal_format, primary_format);
00341 }
00342
00343 addImage(imagep);
00344
00345 if (level_immediate)
00346 {
00347 imagep->dontDiscard();
00348 imagep->setBoostLevel(LLViewerImage::BOOST_UI);
00349 }
00350 }
00351
00352 return imagep;
00353 }
00354
00355
00356 LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
00357 BOOL usemipmaps,
00358 BOOL level_immediate,
00359 LLGLint internal_format,
00360 LLGLenum primary_format,
00361 LLHost request_from_host)
00362 {
00363
00364
00365
00366
00367 if ((&image_id == NULL) || image_id.isNull())
00368 {
00369 return (getImage(IMG_DEFAULT, TRUE, TRUE));
00370 }
00371
00372 LLPointer<LLViewerImage> imagep = hasImage(image_id);
00373
00374 if (imagep.isNull())
00375 {
00376 imagep = new LLViewerImage(image_id, usemipmaps);
00377
00378 imagep->setTargetHost(request_from_host);
00379
00380 if (internal_format && primary_format)
00381 {
00382 imagep->setExplicitFormat(internal_format, primary_format);
00383 }
00384
00385 addImage(imagep);
00386
00387 if (level_immediate)
00388 {
00389 imagep->dontDiscard();
00390 imagep->setBoostLevel(LLViewerImage::BOOST_UI);
00391 }
00392 }
00393
00394 return imagep;
00395 }
00396
00397 LLViewerImage *LLViewerImageList::hasImage(const LLUUID &image_id)
00398 {
00399 uuid_map_t::iterator iter = mUUIDMap.find(image_id);
00400 if(iter == mUUIDMap.end())
00401 return NULL;
00402 return iter->second;
00403 }
00404
00405 void LLViewerImageList::addImageToList(LLViewerImage *image)
00406 {
00407 llassert(image);
00408 if (image->mInImageList)
00409 {
00410 llerrs << "LLViewerImageList::addImageToList - Image already in list" << llendl;
00411 }
00412 llverify((mImageList.insert(image)).second == true);
00413 image->mInImageList = TRUE;
00414 }
00415
00416 void LLViewerImageList::removeImageFromList(LLViewerImage *image)
00417 {
00418 llassert(image);
00419 if (!image->mInImageList)
00420 {
00421 llerrs << "LLViewerImageList::removeImageFromList - Image not in list" << llendl;
00422 }
00423 llverify(mImageList.erase(image) == 1);
00424 image->mInImageList = FALSE;
00425 }
00426
00427 void LLViewerImageList::addImage(LLViewerImage *new_image)
00428 {
00429 if (!new_image)
00430 {
00431 llwarning("No image to add to image list", 0);
00432 return;
00433 }
00434 LLUUID image_id = new_image->getID();
00435
00436 LLViewerImage *image = hasImage(image_id);
00437 if (image)
00438 {
00439 llerrs << "Image with ID " << image_id << " already in list" << llendl;
00440 }
00441 sNumImages++;
00442
00443 addImageToList(new_image);
00444 mUUIDMap[image_id] = new_image;
00445 }
00446
00447
00448 void LLViewerImageList::deleteImage(LLViewerImage *image)
00449 {
00450 if( image)
00451 {
00452 if (image->hasCallbacks())
00453 {
00454 mCallbackList.erase((LLViewerImage*)image);
00455 }
00456
00457 llverify(mUUIDMap.erase(image->getID()) == 1);
00458 sNumImages--;
00459 removeImageFromList(image);
00460 }
00461 }
00462
00464
00465
00467
00468 void LLViewerImageList::dirtyImage(LLViewerImage *image)
00469 {
00470 mDirtyTextureList.insert(image);
00471 }
00472
00474
00475 void LLViewerImageList::updateImages(F32 max_time)
00476 {
00477 sNumImagesStat.addValue(sNumImages);
00478 sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
00479 sGLTexMemStat.addValue(LLImageGL::sGlobalTextureMemory/(1024.f*1024.f));
00480 sGLBoundMemStat.addValue(LLImageGL::sBoundTextureMemory/(1024.f*1024.f));
00481 sRawMemStat.addValue(LLImageRaw::sGlobalRawMemory/(1024.f*1024.f));
00482 sFormattedMemStat.addValue(LLImageFormatted::sGlobalFormattedMemory/(1024.f*1024.f));
00483
00484 updateImagesDecodePriorities();
00485 max_time -= updateImagesFetchTextures(max_time);
00486 max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f);
00487 max_time -= updateImagesCreateTextures(max_time);
00488 max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f);
00489
00490 if (!mDirtyTextureList.empty())
00491 {
00492 LLFastTimer t(LLFastTimer::FTM_IMAGE_MARK_DIRTY);
00493 gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
00494 mDirtyTextureList.clear();
00495 }
00496
00497 bool didone = false;
00498 for (image_list_t::iterator iter = mCallbackList.begin();
00499 iter != mCallbackList.end(); )
00500 {
00501
00502 LLViewerImage* image = *iter++;
00503 if (!image->mLocalFileName.empty())
00504 {
00505
00506 didone = image->doLoadedCallbacks();
00507 }
00508 else if (!didone)
00509 {
00510
00511 didone = image->doLoadedCallbacks();
00512 }
00513 }
00514
00515 if (!gNoRender && !gGLManager.mIsDisabled)
00516 {
00517 LLViewerMedia::updateImagesMediaStreams();
00518 }
00519
00520 updateImagesUpdateStats();
00521 }
00522
00523 void LLViewerImageList::updateImagesDecodePriorities()
00524 {
00525
00526 {
00527 const size_t max_update_count = llmin((S32) (1024*gFrameIntervalSeconds) + 1, 32);
00528 S32 update_counter = llmin(max_update_count, mUUIDMap.size()/10);
00529 uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID);
00530 while(update_counter > 0)
00531 {
00532 if (iter == mUUIDMap.end())
00533 {
00534 iter = mUUIDMap.begin();
00535 }
00536 mLastUpdateUUID = iter->first;
00537 LLPointer<LLViewerImage> imagep = iter->second;
00538 ++iter;
00539
00540
00541
00542
00543 const F32 LAZY_FLUSH_TIMEOUT = 30.f;
00544 S32 min_refs = 3;
00545 if (imagep->hasCallbacks())
00546 {
00547 min_refs++;
00548 }
00549 S32 num_refs = imagep->getNumRefs();
00550 if (num_refs == min_refs)
00551 {
00552 if (imagep->mLastReferencedTimer.getElapsedTimeF32() > LAZY_FLUSH_TIMEOUT)
00553 {
00554
00555 deleteImage(imagep);
00556 imagep = NULL;
00557 continue;
00558 }
00559 }
00560 else
00561 {
00562 imagep->mLastReferencedTimer.reset();
00563 }
00564
00565 imagep->processTextureStats();
00566 F32 old_priority = imagep->getDecodePriority();
00567 F32 decode_priority = imagep->calcDecodePriority();
00568
00569 if ((decode_priority < old_priority * .8f || decode_priority > old_priority * 1.25f))
00570 {
00571 removeImageFromList(imagep);
00572 imagep->setDecodePriority(decode_priority);
00573 addImageToList(imagep);
00574 }
00575 update_counter--;
00576 }
00577 }
00578 }
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 F32 LLViewerImageList::updateImagesCreateTextures(F32 max_time)
00608 {
00609 if (gNoRender || gGLManager.mIsDisabled) return 0.0f;
00610
00611
00612
00613
00614
00615 LLFastTimer t(LLFastTimer::FTM_IMAGE_CREATE);
00616
00617 LLTimer create_timer;
00618 image_list_t::iterator enditer = mCreateTextureList.begin();
00619 for (image_list_t::iterator iter = mCreateTextureList.begin();
00620 iter != mCreateTextureList.end();)
00621 {
00622 image_list_t::iterator curiter = iter++;
00623 enditer = iter;
00624 LLViewerImage *imagep = *curiter;
00625 imagep->createTexture();
00626 if (create_timer.getElapsedTimeF32() > max_time)
00627 {
00628 break;
00629 }
00630 }
00631 mCreateTextureList.erase(mCreateTextureList.begin(), enditer);
00632 return create_timer.getElapsedTimeF32();
00633 }
00634
00635 F32 LLViewerImageList::updateImagesFetchTextures(F32 max_time)
00636 {
00637 LLTimer image_op_timer;
00638
00639
00640
00641 const size_t max_priority_count = llmin((S32) (256*10.f*gFrameIntervalSeconds)+1, 32);
00642 const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256);
00643
00644
00645 std::set<LLViewerImage*> entries;
00646 size_t update_counter = llmin(max_priority_count, mImageList.size());
00647 image_priority_list_t::iterator iter1 = mImageList.begin();
00648 while(update_counter > 0)
00649 {
00650
00651 if(iter1 == mImageList.end())
00652 {
00653 llerrs << "DEV-12002: update_counter not calculated correctly!" << llendl;
00654 }
00655
00656 LLPointer<LLViewerImage> const & ptr = *iter1;
00657
00658 LLViewerImage * img = ptr.get();
00659
00660
00661 if(img == NULL)
00662 {
00663 llwarns << "DEV-12002: image is NULL!" << llendl;
00664 }
00665
00666 entries.insert(img);
00667
00668 ++iter1;
00669 update_counter--;
00670 }
00671
00672
00673 update_counter = llmin(max_update_count, mUUIDMap.size());
00674 uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
00675 while(update_counter > 0)
00676 {
00677 if (iter2 == mUUIDMap.end())
00678 {
00679 iter2 = mUUIDMap.begin();
00680 }
00681 mLastFetchUUID = iter2->first;
00682 entries.insert(iter2->second);
00683 ++iter2;
00684 update_counter--;
00685 }
00686
00687 S32 min_count = max_priority_count + max_update_count/4;
00688 for (std::set<LLViewerImage*>::iterator iter3 = entries.begin();
00689 iter3 != entries.end(); )
00690 {
00691 LLPointer<LLViewerImage> imagep = *iter3++;
00692
00693 imagep->updateFetch();
00694 if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
00695 {
00696 break;
00697 }
00698 min_count--;
00699 }
00700 return image_op_timer.getElapsedTimeF32();
00701 }
00702
00703 void LLViewerImageList::updateImagesUpdateStats()
00704 {
00705 if (mUpdateStats)
00706 {
00707 for (image_priority_list_t::iterator iter = mImageList.begin();
00708 iter != mImageList.end(); )
00709 {
00710 LLViewerImage* imagep = *iter++;
00711 imagep->resetTextureStats(mForceResetTextureStats);
00712 }
00713 mUpdateStats = FALSE;
00714 mForceResetTextureStats = FALSE;
00715 }
00716 }
00717
00718 void LLViewerImageList::decodeAllImages(F32 max_time)
00719 {
00720 LLTimer timer;
00721 if(gNoRender) return;
00722
00723
00724 std::vector<LLPointer<LLViewerImage> > image_list;
00725 for (image_priority_list_t::iterator iter = mImageList.begin();
00726 iter != mImageList.end(); )
00727 {
00728 LLViewerImage* imagep = *iter++;
00729 image_list.push_back(imagep);
00730 imagep->mInImageList = FALSE;
00731 }
00732 mImageList.clear();
00733 for (std::vector<LLPointer<LLViewerImage> >::iterator iter = image_list.begin();
00734 iter != image_list.end(); ++iter)
00735 {
00736 LLViewerImage* imagep = *iter;
00737 imagep->processTextureStats();
00738 F32 decode_priority = imagep->calcDecodePriority();
00739 imagep->setDecodePriority(decode_priority);
00740 mImageList.insert(imagep);
00741 imagep->mInImageList = TRUE;
00742 }
00743 image_list.clear();
00744
00745
00746 for (image_priority_list_t::iterator iter = mImageList.begin();
00747 iter != mImageList.end(); )
00748 {
00749 LLViewerImage* imagep = *iter++;
00750 imagep->updateFetch();
00751 }
00752
00753 S32 fetch_pending = 0;
00754 while (1)
00755 {
00756 LLAppViewer::instance()->getTextureCache()->update(1);
00757 LLAppViewer::instance()->getImageDecodeThread()->update(1);
00758 fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1);
00759 if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time)
00760 {
00761 break;
00762 }
00763 }
00764
00765 for (image_priority_list_t::iterator iter = mImageList.begin();
00766 iter != mImageList.end(); )
00767 {
00768 LLViewerImage* imagep = *iter++;
00769 imagep->updateFetch();
00770 }
00771 max_time -= timer.getElapsedTimeF32();
00772 max_time = llmax(max_time, .001f);
00773 F32 create_time = updateImagesCreateTextures(max_time);
00774
00775 LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. "
00776 << " fetch_pending " << fetch_pending
00777 << " create_time " << create_time
00778 << LL_ENDL;
00779 }
00780
00781
00782 BOOL LLViewerImageList::createUploadFile(const LLString& filename,
00783 const LLString& out_filename,
00784 const U8 codec)
00785 {
00786
00787 LLPointer<LLImageRaw> raw_image = new LLImageRaw;
00788
00789 switch (codec)
00790 {
00791 case IMG_CODEC_BMP:
00792 {
00793 LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
00794
00795 if (!bmp_image->load(filename))
00796 {
00797 return FALSE;
00798 }
00799
00800 if (!bmp_image->decode(raw_image, 0.0f))
00801 {
00802 return FALSE;
00803 }
00804 }
00805 break;
00806 case IMG_CODEC_TGA:
00807 {
00808 LLPointer<LLImageTGA> tga_image = new LLImageTGA;
00809
00810 if (!tga_image->load(filename))
00811 {
00812 return FALSE;
00813 }
00814
00815 if (!tga_image->decode(raw_image))
00816 {
00817 return FALSE;
00818 }
00819
00820 if( (tga_image->getComponents() != 3) &&
00821 (tga_image->getComponents() != 4) )
00822 {
00823 tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
00824 return FALSE;
00825 }
00826 }
00827 break;
00828 case IMG_CODEC_JPEG:
00829 {
00830 LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
00831
00832 if (!jpeg_image->load(filename))
00833 {
00834 return FALSE;
00835 }
00836
00837 if (!jpeg_image->decode(raw_image, 0.0f))
00838 {
00839 return FALSE;
00840 }
00841 }
00842 break;
00843 case IMG_CODEC_PNG:
00844 {
00845 LLPointer<LLImagePNG> png_image = new LLImagePNG;
00846
00847 if (!png_image->load(filename))
00848 {
00849 return FALSE;
00850 }
00851
00852 if (!png_image->decode(raw_image, 0.0f))
00853 {
00854 return FALSE;
00855 }
00856 }
00857 break;
00858 default:
00859 return FALSE;
00860 }
00861
00862 LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
00863
00864 if( !compressedImage->save(out_filename) )
00865 {
00866 llinfos << "Couldn't create output file " << out_filename << llendl;
00867 return FALSE;
00868 }
00869
00870
00871 LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
00872 if( !integrity_test->loadAndValidate( out_filename ) )
00873 {
00874 llinfos << "Image: " << out_filename << " is corrupt." << llendl;
00875 return FALSE;
00876 }
00877
00878 return TRUE;
00879 }
00880
00881
00882 LLPointer<LLImageJ2C> LLViewerImageList::convertToUploadFile(LLPointer<LLImageRaw> raw_image)
00883 {
00884 raw_image->biasedScaleToPowerOfTwo(LLViewerImage::MAX_IMAGE_SIZE_DEFAULT);
00885 LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
00886 compressedImage->setRate(0.f);
00887
00888 if (gSavedSettings.getBOOL("LosslessJ2CUpload") &&
00889 (raw_image->getWidth() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF) &&
00890 (raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF))
00891 compressedImage->setReversible(TRUE);
00892
00893 compressedImage->encode(raw_image, 0.0f);
00894
00895 return compressedImage;
00896 }
00897
00898 const S32 MIN_VIDEO_RAM = 32;
00899 const S32 MAX_VIDEO_RAM = 2048;
00900
00901
00902 S32 LLViewerImageList::getMinVideoRamSetting()
00903 {
00904 return MIN_VIDEO_RAM;
00905 }
00906
00907
00908
00909 S32 LLViewerImageList::getMaxVideoRamSetting(bool get_recommended)
00910 {
00911 S32 max_texmem;
00912 if (gGLManager.mVRAM != 0)
00913 {
00914
00915
00916 S32 max_vram = gGLManager.mVRAM;
00917 max_vram = llmax(max_vram, getMinVideoRamSetting());
00918 max_texmem = max_vram;
00919 if (!get_recommended)
00920 max_texmem *= 2;
00921 }
00922 else
00923 {
00924 if (get_recommended)
00925 max_texmem = 128;
00926 else
00927 max_texmem = 512;
00928 llwarns << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << llendl;
00929 }
00930
00931 S32 system_ram = (S32)(gSysMemory.getPhysicalMemoryClamped() >> 20);
00932
00933 if (get_recommended)
00934 max_texmem = llmin(max_texmem, (S32)(system_ram/2));
00935 else
00936 max_texmem = llmin(max_texmem, (S32)(system_ram));
00937
00938 max_texmem = llclamp(max_texmem, MIN_VIDEO_RAM, MAX_VIDEO_RAM);
00939
00940 return max_texmem;
00941 }
00942
00943 const S32 VIDEO_CARD_FRAMEBUFFER_MEM = 12;
00944
00945 void LLViewerImageList::updateMaxResidentTexMem(S32 mem)
00946 {
00947
00948 S32 cur_mem = gSavedSettings.getS32("TextureMemory");
00949 F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
00950 S32 default_mem = getMaxVideoRamSetting(true);
00951 if (mem == 0)
00952 {
00953 mem = cur_mem > 0 ? cur_mem : default_mem;
00954 }
00955 else if (mem < 0)
00956 {
00957 mem = default_mem;
00958 }
00959
00960
00961 mem = llmin(mem, (S32) (mem_multiplier * (F32) default_mem));
00962
00963 mem = llclamp(mem, getMinVideoRamSetting(), getMaxVideoRamSetting());
00964 if (mem != cur_mem)
00965 {
00966 gSavedSettings.setS32("TextureMemory", mem);
00967 return;
00968 }
00969
00970
00971
00972
00973 S32 vb_mem = mem;
00974 S32 fb_mem = llmax(VIDEO_CARD_FRAMEBUFFER_MEM, vb_mem/4);
00975 mMaxResidentTexMem = (vb_mem - fb_mem)<<20;
00976
00977 llinfos << "Total Video Memory set to: " << vb_mem << " MB" << llendl;
00978 llinfos << "Available Texture Memory set to: " << (vb_mem - fb_mem) << " MB" << llendl;
00979 }
00980
00982
00983
00984 void LLViewerImageList::receiveImageHeader(LLMessageSystem *msg, void **user_data)
00985 {
00986 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
00987
00988
00989
00990
00991 LLUUID id;
00992
00993 char ip_string[256];
00994 u32_to_ip_string(msg->getSenderIP(),ip_string);
00995
00996 if (msg->getReceiveCompressedSize())
00997 {
00998 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
00999 }
01000 else
01001 {
01002 gImageList.sTextureBits += msg->getReceiveSize() * 8;
01003 }
01004 gImageList.sTexturePackets++;
01005
01006 U8 codec;
01007 U16 packets;
01008 U32 totalbytes;
01009 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
01010 msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, codec);
01011 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, packets);
01012 msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, totalbytes);
01013
01014 S32 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
01015 if (!data_size)
01016 {
01017 return;
01018 }
01019 if (data_size < 0)
01020 {
01021
01022
01023 llerrs << "image header chunk size was negative: "
01024 << data_size << llendl;
01025 return;
01026 }
01027
01028
01029 U8 *data = new U8[data_size];
01030 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
01031
01032 LLViewerImage *image = gImageList.getImage(id);
01033 if (!image)
01034 {
01035 delete [] data;
01036 return;
01037 }
01038 image->mLastPacketTimer.reset();
01039 bool res = LLAppViewer::getTextureFetch()->receiveImageHeader(msg->getSender(), id, codec, packets, totalbytes, data_size, data);
01040 if (!res)
01041 {
01042 delete[] data;
01043 }
01044 }
01045
01046
01047 void LLViewerImageList::receiveImagePacket(LLMessageSystem *msg, void **user_data)
01048 {
01049 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
01050 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
01051
01052
01053
01054
01055 LLUUID id;
01056 U16 packet_num;
01057
01058 char ip_string[256];
01059 u32_to_ip_string(msg->getSenderIP(),ip_string);
01060
01061 if (msg->getReceiveCompressedSize())
01062 {
01063 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
01064 }
01065 else
01066 {
01067 gImageList.sTextureBits += msg->getReceiveSize() * 8;
01068 }
01069 gImageList.sTexturePackets++;
01070
01071
01072 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
01073 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num);
01074 S32 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
01075
01076 if (!data_size)
01077 {
01078 return;
01079 }
01080 if (data_size < 0)
01081 {
01082
01083
01084 llerrs << "image data chunk size was negative: "
01085 << data_size << llendl;
01086 return;
01087 }
01088 if (data_size > MTUBYTES)
01089 {
01090 llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
01091 return;
01092 }
01093 U8 *data = new U8[data_size];
01094 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
01095
01096 LLViewerImage *image = gImageList.getImage(id);
01097 if (!image)
01098 {
01099 delete [] data;
01100 return;
01101 }
01102 image->mLastPacketTimer.reset();
01103 bool res = LLAppViewer::getTextureFetch()->receiveImagePacket(msg->getSender(), id, packet_num, data_size, data);
01104 if (!res)
01105 {
01106 delete[] data;
01107 }
01108 }
01109
01110
01111
01112
01113 void LLViewerImageList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
01114 {
01115 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
01116 LLUUID image_id;
01117 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
01118
01119 LLViewerImage* image = gImageList.hasImage( image_id );
01120 if( image )
01121 {
01122 image->setIsMissingAsset();
01123 }
01124 }
01125
01127
01128
01129 const U32 SIXTEEN_MEG = 0x1000000;
01130 S32 LLViewerImageList::calcMaxTextureRAM()
01131 {
01132
01133 LLMemoryInfo memory_info;
01134 U32 available_memory = memory_info.getPhysicalMemoryClamped();
01135
01136 clamp_rescale((F32)available_memory,
01137 (F32)(SIXTEEN_MEG * 16),
01138 (F32)U32_MAX,
01139 (F32)(SIXTEEN_MEG * 4),
01140 (F32)(U32_MAX >> 1));
01141 return available_memory;
01142 }
01143
01145
01146
01147
01148
01149 void LLUIImageList::cleanUp()
01150 {
01151 mUIImages.clear();
01152 }
01153
01154 LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id)
01155 {
01156
01157 LLString image_name = image_id.asString();
01158
01159
01160 uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
01161 if (found_it != mUIImages.end())
01162 {
01163 return found_it->second;
01164 }
01165
01166 return loadUIImageByID(image_id);
01167 }
01168
01169 LLUIImagePtr LLUIImageList::getUIImage(const LLString& image_name)
01170 {
01171
01172 uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name);
01173 if (found_it != mUIImages.end())
01174 {
01175 return found_it->second;
01176 }
01177
01178 return loadUIImageByName(image_name, image_name);
01179 }
01180
01181 LLUIImagePtr LLUIImageList::loadUIImageByName(const LLString& name, const LLString& filename, BOOL use_mips, const LLRect& scale_rect)
01182 {
01183 LLViewerImage* imagep = gImageList.getImageFromFile(filename, MIPMAP_NO, IMMEDIATE_YES);
01184 return loadUIImage(imagep, name, use_mips, scale_rect);
01185 }
01186
01187 LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id, BOOL use_mips, const LLRect& scale_rect)
01188 {
01189 LLViewerImage* imagep = gImageList.getImage(id, MIPMAP_NO, IMMEDIATE_YES);
01190 return loadUIImage(imagep, id.asString(), use_mips, scale_rect);
01191 }
01192
01193 LLUIImagePtr LLUIImageList::loadUIImage(LLViewerImage* imagep, const LLString& name, BOOL use_mips, const LLRect& scale_rect)
01194 {
01195 if (!imagep) return NULL;
01196
01197 imagep->setClamp(TRUE, TRUE);
01198
01199 LLUIImagePtr new_imagep = new LLUIImage(name, imagep);
01200 mUIImages.insert(std::make_pair(name, new_imagep));
01201
01202 LLUIImageLoadData* datap = new LLUIImageLoadData;
01203 datap->mImageName = name;
01204 datap->mImageScaleRegion = scale_rect;
01205
01206 imagep->setLoadedCallback(onUIImageLoaded, 0, FALSE, datap);
01207
01208 return new_imagep;
01209 }
01210
01211 LLUIImagePtr LLUIImageList::preloadUIImage(const LLString& name, const LLString& filename, BOOL use_mips, const LLRect& scale_rect)
01212 {
01213
01214 uuid_ui_image_map_t::iterator found_it = mUIImages.find(name);
01215 if (found_it != mUIImages.end())
01216 {
01217
01218 llerrs << "UI Image " << name << " already loaded." << llendl;
01219 }
01220
01221 return loadUIImageByName(name, filename, use_mips, scale_rect);
01222 }
01223
01224
01225 void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* user_data )
01226 {
01227 if(!success || !user_data)
01228 {
01229 return;
01230 }
01231
01232 LLString ui_image_name ;
01233 LLRect scale_rect ;
01234 {
01235 LLUIImageLoadData* image_datap = (LLUIImageLoadData*)user_data;
01236
01237 ui_image_name = image_datap->mImageName;
01238 scale_rect = image_datap->mImageScaleRegion;
01239 if(final)
01240 {
01241 delete image_datap;
01242 }
01243 }
01244
01245 LLUIImageList* instance = getInstance();
01246
01247 uuid_ui_image_map_t::iterator found_it = instance->mUIImages.find(ui_image_name);
01248 if (found_it != instance->mUIImages.end())
01249 {
01250 LLUIImagePtr imagep = found_it->second;
01251
01252
01253
01254 if (success && imagep.notNull() && src_vi && !src_vi->mLocalFileName.empty())
01255 {
01256 F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getWidth(0);
01257 F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getHeight(0);
01258 imagep->setClipRegion(LLRectf(0.f, clip_y, clip_x, 0.f));
01259 if (scale_rect != LLRect::null)
01260 {
01261 imagep->setScaleRegion(
01262 LLRectf(llclamp((F32)scale_rect.mLeft / (F32)imagep->getWidth(), 0.f, 1.f),
01263 llclamp((F32)scale_rect.mTop / (F32)imagep->getHeight(), 0.f, 1.f),
01264 llclamp((F32)scale_rect.mRight / (F32)imagep->getWidth(), 0.f, 1.f),
01265 llclamp((F32)scale_rect.mBottom / (F32)imagep->getHeight(), 0.f, 1.f)));
01266 }
01267 }
01268 }
01269 }
01270
01271 bool LLUIImageList::initFromFile(const LLString& filename)
01272 {
01273 LLXmlTree xml_tree;
01274
01275 if (!xml_tree.parseFile(filename))
01276 {
01277 llwarns << "Unable to parse UI image list file " << filename << llendl;
01278 return false;
01279 }
01280
01281 LLXmlTreeNode* rootp = xml_tree.getRoot();
01282 if (!rootp || !rootp->hasAttribute("version"))
01283 {
01284 llwarns << "No valid version number in UI image list file " << filename << llendl;
01285 return false;
01286 }
01287
01288 enum
01289 {
01290 PASS_DECODE_NOW,
01291 PASS_DECODE_LATER,
01292 NUM_PASSES
01293 };
01294
01295 for (S32 pass = PASS_DECODE_NOW; pass < NUM_PASSES; pass++)
01296 {
01297 LLXmlTreeNode* child_nodep = rootp->getFirstChild();
01298 while(child_nodep)
01299 {
01300 LLString image_name = child_nodep->getName();
01301 LLString file_name = image_name;
01302 LLRect scale_rect;
01303 BOOL use_mip_maps = FALSE;
01304
01305 BOOL preload = FALSE;
01306 child_nodep->getAttributeBOOL("preload", preload);
01307
01308
01309 if (preload)
01310 {
01311 if (pass == PASS_DECODE_LATER)
01312 {
01313 child_nodep = rootp->getNextChild();
01314 continue;
01315 }
01316 }
01317 else
01318 {
01319 if (pass == PASS_DECODE_NOW)
01320 {
01321 child_nodep = rootp->getNextChild();
01322 continue;
01323 }
01324 }
01325
01326 child_nodep->getAttributeString("file_name", file_name);
01327 child_nodep->getAttributeBOOL("use_mips", use_mip_maps);
01328
01329 LLXmlTreeNode* rect_node = child_nodep->getChildByName("scale_rect");
01330 if (rect_node)
01331 {
01332 rect_node->getAttributeS32("left", scale_rect.mLeft);
01333 rect_node->getAttributeS32("right", scale_rect.mRight);
01334 rect_node->getAttributeS32("bottom", scale_rect.mBottom);
01335 rect_node->getAttributeS32("top", scale_rect.mTop);
01336 }
01337
01338 preloadUIImage(image_name, file_name, use_mip_maps, scale_rect);
01339
01340 child_nodep = rootp->getNextChild();
01341 }
01342
01343 if (pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload"))
01344 {
01345 gImageList.decodeAllImages(2.f);
01346 }
01347 }
01348 return true;
01349 }
01350