aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerimagelist.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:50 -0500
committerJacek Antonelli2008-08-15 23:44:50 -0500
commit89fe5dab825a62a0e3fd8d248cbc91c65eb2a426 (patch)
treebcff14b7888d04a2fec799c59369f6095224bd08 /linden/indra/newview/llviewerimagelist.cpp
parentSecond Life viewer sources 1.13.3.2 (diff)
downloadmeta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.zip
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.gz
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.bz2
meta-impy-89fe5dab825a62a0e3fd8d248cbc91c65eb2a426.tar.xz
Second Life viewer sources 1.14.0.0
Diffstat (limited to 'linden/indra/newview/llviewerimagelist.cpp')
-rw-r--r--linden/indra/newview/llviewerimagelist.cpp1224
1 files changed, 446 insertions, 778 deletions
diff --git a/linden/indra/newview/llviewerimagelist.cpp b/linden/indra/newview/llviewerimagelist.cpp
index 20ca3bf..456afdb 100644
--- a/linden/indra/newview/llviewerimagelist.cpp
+++ b/linden/indra/newview/llviewerimagelist.cpp
@@ -39,57 +39,30 @@
39#include "llimagejpeg.h" 39#include "llimagejpeg.h"
40#include "llmediaengine.h" 40#include "llmediaengine.h"
41 41
42#include "llsdserialize.h"
43#include "llsys.h"
42#include "llvfs.h" 44#include "llvfs.h"
43#include "llvfile.h" 45#include "llvfile.h"
44#include "llvfsthread.h" 46#include "llvfsthread.h"
45#include "message.h" 47#include "message.h"
46 48
47#include "llagent.h" 49#include "llagent.h"
48#include "llviewercontrol.h" 50#include "lltexturecache.h"
51#include "lltexturefetch.h"
49#include "lltexturetable.h" // For looking up names from uuid's. 52#include "lltexturetable.h" // For looking up names from uuid's.
53#include "llviewercontrol.h"
50#include "llviewerimage.h" 54#include "llviewerimage.h"
51#include "llviewerregion.h" 55#include "llviewerregion.h"
56#include "pipeline.h"
52#include "viewer.h" 57#include "viewer.h"
53#include "llsys.h"
54#include "llpaneldisplay.h" // for LL_MAX_VRAM_INDEX
55 58
56void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL; 59////////////////////////////////////////////////////////////////////////////
57 60
58const U32 SIXTEEN_MEG = 0x1000000; 61void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL;
59const F32 MAX_IMAGE_PRIORITY = 100000000.f;
60 62
61U32 LLViewerImageList::sTextureBits = 0; 63U32 LLViewerImageList::sTextureBits = 0;
62U32 LLViewerImageList::sTexturePackets = 0; 64U32 LLViewerImageList::sTexturePackets = 0;
63 65
64struct CodecExtMap
65{
66 CodecExtMap( const char* ext, U8 codec ) : mExt( ext ), mCodec( codec ) {}
67 const char* mExt;
68 U8 mCodec;
69};
70
71// Note: Keep codec extensions in order of likelihood the image
72// will be found.
73const S32 CODEC_EXT_MAP_COUNT = 2;
74const CodecExtMap CODEC_EXT_MAP[CODEC_EXT_MAP_COUNT] =
75{
76 CodecExtMap( "_07", IMG_CODEC_J2C ),
77 CodecExtMap( ".tga", IMG_CODEC_TGA )
78};
79
80const U32 MIN_AVAIL_MEM_FOR_DECODE = 1048576;
81
82// HACK: We have to try to allocate a constant fraction of this
83// memory for AGP. This isn't worthwhile on 128 meg cards.
84// So for 128 meg cards, only alloc 64 megs.
85const S32 VIDEO_CARD_MEM_SIZES[6] = { 0x1000000, // 16MB
86 0x2000000, // 32MB
87 0x4000000, // 64MB+
88 0x8000000, // 128MB
89 0x10000000, // 256MB
90 0x20000000, // 512MB
91 };
92
93const S32 IMAGES_PER_REQUEST = 42; 66const S32 IMAGES_PER_REQUEST = 42;
94const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame 67const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame
95const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame 68const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame
@@ -105,22 +78,6 @@ LLStat LLViewerImageList::sGLBoundMemStat(32, TRUE);
105LLStat LLViewerImageList::sRawMemStat(32, TRUE); 78LLStat LLViewerImageList::sRawMemStat(32, TRUE);
106LLStat LLViewerImageList::sFormattedMemStat(32, TRUE); 79LLStat LLViewerImageList::sFormattedMemStat(32, TRUE);
107 80
108//static
109S32 LLViewerImageList::calcMaxTextureRAM()
110{
111 // Decide the maximum amount of RAM we should allow the user to allocate to texture cache
112 LLMemoryInfo memory_info;
113 U32 available_memory = memory_info.getPhysicalMemory();
114
115 clamp_rescale((F32)available_memory,
116 (F32)(SIXTEEN_MEG * 16),
117 (F32)U32_MAX,
118 (F32)(SIXTEEN_MEG * 4),
119 (F32)(U32_MAX >> 1));
120 return available_memory;
121}
122
123
124/////////////////////////////////////////////////////////////////////////////// 81///////////////////////////////////////////////////////////////////////////////
125 82
126LLViewerImageList::LLViewerImageList() 83LLViewerImageList::LLViewerImageList()
@@ -145,57 +102,22 @@ void LLViewerImageList::init()
145 return; 102 return;
146 } 103 }
147 104
148 // This stuff is global! Bad behavior if more than one image list.
149
150 // Set the fallback GL texture to smoke...
151 LLViewerImage::sSmokeImagep = getImage(IMG_SMOKE, TRUE, TRUE);
152 // Set the fallback GL texture to gray with a white border...
153#if 0
154 LLViewerImage* imagep = new LLViewerImage(IMG_DEFAULT, TRUE);
155 LLViewerImage::sDefaultImagep = imagep;
156 const S32 dim = 128;
157 const S32 border = 2;
158 LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
159 U8* data = image_raw->getData();
160 for (S32 i = 0; i<dim; i++)
161 {
162 for (S32 j = 0; j<dim; j++)
163 {
164 if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
165 {
166 *data++ = 0xff;
167 *data++ = 0xff;
168 *data++ = 0xff;
169 }
170 else
171 {
172 *data++ = 0x7f;
173 *data++ = 0x7f;
174 *data++ = 0x7f;
175 }
176 }
177 }
178 imagep->createGLTexture(0, image_raw);
179 image_raw = NULL;
180 addImage(imagep);
181 imagep->dontDiscard();
182#else
183 LLViewerImage::sDefaultImagep = getImage(IMG_DEFAULT, TRUE, TRUE);
184#endif
185
186
187 mUpdateStats = TRUE; 105 mUpdateStats = TRUE;
188 106
189 // Update how much texture RAM we're allowed to use. 107 // Update how much texture RAM we're allowed to use.
190 updateMaxResidentTexMem(); 108 updateMaxResidentTexMem();
191 109
192 mMovieImageHasMips = FALSE; 110 mMovieImageHasMips = FALSE;
111
112 doPreloadImages();
113
114 decodeAllImages(5.f); // decode preloaded images
193} 115}
194 116
195void LLViewerImageList::doPreloadImages() 117void LLViewerImageList::doPreloadImages()
196{ 118{
197 llinfos << "Preloading images..." << llendl; 119 llinfos << "Preloading images..." << llendl;
198 120
199 // Set the "missing asset" image 121 // Set the "missing asset" image
200 LLViewerImage::sMissingAssetImagep = preloadImage("missing_asset.tga" , LLUUID::null, TRUE); 122 LLViewerImage::sMissingAssetImagep = preloadImage("missing_asset.tga" , LLUUID::null, TRUE);
201 123
@@ -335,6 +257,7 @@ void LLViewerImageList::doPreloadImages()
335 preloadImage("spin_up_in_blue.tga", LLUUID::null, FALSE); 257 preloadImage("spin_up_in_blue.tga", LLUUID::null, FALSE);
336 preloadImage("spin_up_out_blue.tga", LLUUID::null, FALSE); 258 preloadImage("spin_up_out_blue.tga", LLUUID::null, FALSE);
337 preloadImage("square_btn_32x128.tga", LLUUID::null, FALSE); 259 preloadImage("square_btn_32x128.tga", LLUUID::null, FALSE);
260 preloadImage("square_btn_selected_32x128.tga", LLUUID::null, FALSE);
338 preloadImage("startup_logo.tga", LLUUID::null, FALSE); 261 preloadImage("startup_logo.tga", LLUUID::null, FALSE);
339 preloadImage("status_build.tga", LLUUID::null, FALSE); 262 preloadImage("status_build.tga", LLUUID::null, FALSE);
340 preloadImage("status_buy_currency.tga", LLUUID::null, FALSE); 263 preloadImage("status_buy_currency.tga", LLUUID::null, FALSE);
@@ -346,6 +269,8 @@ void LLViewerImageList::doPreloadImages()
346 preloadImage("status_scripts.tga", LLUUID::null, FALSE); 269 preloadImage("status_scripts.tga", LLUUID::null, FALSE);
347 preloadImage("tab_bottom_blue.tga", LLUUID::null, FALSE); 270 preloadImage("tab_bottom_blue.tga", LLUUID::null, FALSE);
348 preloadImage("tab_bottom_selected_blue.tga", LLUUID::null, FALSE); 271 preloadImage("tab_bottom_selected_blue.tga", LLUUID::null, FALSE);
272 preloadImage("tab_left.tga", LLUUID::null, FALSE);
273 preloadImage("tab_left_selected.tga", LLUUID::null, FALSE);
349 preloadImage("tab_top_blue.tga", LLUUID::null, FALSE); 274 preloadImage("tab_top_blue.tga", LLUUID::null, FALSE);
350 preloadImage("tab_top_selected_blue.tga", LLUUID::null, FALSE); 275 preloadImage("tab_top_selected_blue.tga", LLUUID::null, FALSE);
351 preloadImage("tool_dozer.tga", LLUUID::null, FALSE); 276 preloadImage("tool_dozer.tga", LLUUID::null, FALSE);
@@ -355,6 +280,45 @@ void LLViewerImageList::doPreloadImages()
355 preloadImage("white.tga", LLUUID::null, TRUE); 280 preloadImage("white.tga", LLUUID::null, TRUE);
356} 281}
357 282
283static std::string get_texture_list_name()
284{
285 BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
286 return std::string("texture_list_") + (login_last?"last":"home") + ".xml";
287}
288
289void LLViewerImageList::doPrefetchImages()
290{
291 if (gPurgeCache)
292 {
293 // cache was purged, no point
294 return;
295 }
296
297 // Pre-fetch textures from last logout
298 LLSD imagelist;
299 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
300 llifstream file;
301 file.open(filename.c_str());
302 if (file.is_open())
303 {
304 LLSDSerialize::fromXML(imagelist, file);
305 }
306 for (LLSD::array_iterator iter = imagelist.beginArray();
307 iter != imagelist.endArray(); ++iter)
308 {
309 LLSD imagesd = *iter;
310 LLUUID uuid = imagesd["uuid"];
311 S32 pixel_area = imagesd["area"];
312 LLViewerImage* image = getImage(uuid, MIPMAP_TRUE, FALSE);
313 if (image)
314 {
315 image->addTextureStats((F32)pixel_area);
316 }
317 }
318
319
320}
321
358/////////////////////////////////////////////////////////////////////////////// 322///////////////////////////////////////////////////////////////////////////////
359 323
360LLViewerImageList::~LLViewerImageList() 324LLViewerImageList::~LLViewerImageList()
@@ -364,43 +328,70 @@ LLViewerImageList::~LLViewerImageList()
364 328
365void LLViewerImageList::shutdown() 329void LLViewerImageList::shutdown()
366{ 330{
367 // Clean up potential callback data 331 // Write out list of currently loaded textures for precaching on startup
368 // mIRCallbackData is now stl and will clean itself up 332 typedef std::set<std::pair<S32,LLViewerImage*> > image_area_list_t;
333 image_area_list_t image_area_list;
334 for (image_priority_list_t::iterator iter = mImageList.begin();
335 iter != mImageList.end(); ++iter)
336 {
337 LLViewerImage* image = *iter;
338 if (!image->getUseDiscard() ||
339 image->needsAux() ||
340 image->getTargetHost() != LLHost::invalid)
341 {
342 continue; // avoid UI, baked, and other special images
343 }
344 S32 desired = image->getDesiredDiscardLevel();
345 if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
346 {
347 S32 pixel_area = image->getWidth(desired) * image->getHeight(desired);
348 image_area_list.insert(std::make_pair(pixel_area, image));
349 }
350 }
351
352 LLSD imagelist;
353 const S32 max_count = 1000;
354 S32 count = 0;
355 for (image_area_list_t::reverse_iterator riter = image_area_list.rbegin();
356 riter != image_area_list.rend(); ++riter)
357 {
358 LLViewerImage* image = riter->second;
359 imagelist[count]["area"] = riter->first;
360 imagelist[count]["uuid"] = image->getID();
361 if (++count >= max_count)
362 break;
363 }
369 364
365 if (count > 0 && !gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "").empty())
366 {
367 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name());
368 llofstream file;
369 file.open(filename.c_str());
370 LLSDSerialize::toPrettyXML(imagelist, file);
371 }
372
370 // 373 //
371 // Clean up "loaded" callbacks. 374 // Clean up "loaded" callbacks.
372 // 375 //
373 mCallbackList.clear(); 376 mCallbackList.clear();
374 377 mIRCallbackData.clear();
378
375 // Clean up preloaded images 379 // Clean up preloaded images
376 mPreloadedImages.clear(); 380 mPreloadedImages.clear();
377 381
378 //
379 // If we're working on decoding an image, finish it off so we can clean it up.
380 //
381 LLViewerImage *imagep = mCurrentDecodeImagep;
382 if (imagep)
383 {
384 imagep->abortDecode();
385 imagep->destroyRawImage();
386 mCurrentDecodeImagep = NULL;
387 }
388
389 // Flush all of the references 382 // Flush all of the references
390 mLoadingStreamList.clear(); 383 mLoadingStreamList.clear();
384 mCreateTextureList.clear();
391 385
392 mUUIDMap.clear(); 386 mUUIDMap.clear();
393 387
394 // This stuff is global!
395 LLViewerImage::sDefaultImagep = NULL;
396
397 mImageList.clear(); 388 mImageList.clear();
398} 389}
399 390
400void LLViewerImageList::dump() 391void LLViewerImageList::dump()
401{ 392{
402 llinfos << "LLViewerImageList::dump()" << llendl; 393 llinfos << "LLViewerImageList::dump()" << llendl;
403 for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) 394 for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
404 { 395 {
405 LLViewerImage* image = *it; 396 LLViewerImage* image = *it;
406 397
@@ -456,20 +447,20 @@ LLViewerImage* LLViewerImageList::preloadImage(const LLString& filename, const L
456 447
457/////////////////////////////////////////////////////////////////////////////// 448///////////////////////////////////////////////////////////////////////////////
458 449
459LLViewerImage * LLViewerImageList::getImage(const LLString& filename, 450LLViewerImage* LLViewerImageList::getImage(const LLString& filename,
460 const LLUUID &image_set_id, 451 const LLUUID &image_set_id,
461 BOOL usemipmaps, 452 BOOL usemipmaps,
462 BOOL level_immediate) 453 BOOL level_immediate)
463{ 454{
464 return getImageFromFile(filename, image_set_id, usemipmaps, level_immediate, 0, 0); 455 return getImageFromFile(filename, image_set_id, usemipmaps, level_immediate, 0, 0);
465} 456}
466 457
467LLViewerImage * LLViewerImageList::getImageFromFile(const LLString& filename, 458LLViewerImage* LLViewerImageList::getImageFromFile(const LLString& filename,
468 const LLUUID &image_set_id, 459 const LLUUID &image_set_id,
469 BOOL usemipmaps, 460 BOOL usemipmaps,
470 BOOL level_immediate, 461 BOOL level_immediate,
471 LLGLint internal_format, 462 LLGLint internal_format,
472 LLGLenum primary_format) 463 LLGLenum primary_format)
473{ 464{
474 if (gNoRender) 465 if (gNoRender)
475 { 466 {
@@ -485,7 +476,7 @@ LLViewerImage * LLViewerImageList::getImageFromFile(const LLString& filename,
485 LLUUID image_id = LLUUID( gViewerArt.getString(filename.c_str()) ); 476 LLUUID image_id = LLUUID( gViewerArt.getString(filename.c_str()) );
486 if (image_id.isNull()) 477 if (image_id.isNull())
487 { 478 {
488 llwarns << "Unable to find inage " << filename << " in gViewerArt" << llendl; 479 llwarns << "Unable to find image " << filename << " in gViewerArt" << llendl;
489 if (image_set_id.notNull()) 480 if (image_set_id.notNull())
490 { 481 {
491 // We *know* that missing_asset.tga exists, 482 // We *know* that missing_asset.tga exists,
@@ -512,58 +503,9 @@ LLViewerImage * LLViewerImageList::getImageFromFile(const LLString& filename,
512 image_id = image_set_id; 503 image_id = image_set_id;
513 } 504 }
514 505
515 // First see if we already have this image loaded. 506 // Load the image
516 LLPointer<LLViewerImage> imagep = hasImage(image_id); 507 LLViewerImage* imagep = getImageFromUUID(image_id, usemipmaps, level_immediate,
517 508 internal_format, primary_format, LLHost());
518 if (imagep.isNull())
519 {
520 // No image loaded. Try to read the filename given.
521 bool success = false;
522 if (!filename.empty())
523 {
524 // This is strictly for local .tga files not in the static VFS
525 LLString image_file = gDirUtilp->getExpandedFilename(LL_PATH_TOP_SKIN, filename);
526 imagep = new LLViewerImage(image_id, usemipmaps);
527 LLPointer<LLImageRaw> image_raw = new LLImageRaw(image_file);
528 if ( image_raw->getDataSize() > 0 )
529 {
530 imagep->createGLTexture(0, image_raw);
531 image_raw = NULL;
532
533 if (usemipmaps == FALSE)
534 {
535 // num mipmaped textures are almost always clamped, so clamp by default
536 imagep->bind();
537 imagep->setClamp(TRUE, TRUE);
538 }
539
540 if (internal_format && primary_format)
541 {
542 imagep->setExplicitFormat(internal_format, primary_format);
543 }
544
545 addImage(imagep);
546
547 if (level_immediate)
548 {
549 imagep->dontDiscard();
550 }
551
552 success = true;
553 }
554 else
555 {
556 imagep = NULL;
557 }
558 }
559
560 if (!success)
561 {
562 // We couldn't load from a file. Try the VFS.
563 imagep = getImageFromUUID(image_id, usemipmaps, level_immediate,
564 internal_format, primary_format, LLHost());
565 }
566 }
567 509
568 return imagep; 510 return imagep;
569} 511}
@@ -609,40 +551,7 @@ LLViewerImage* LLViewerImageList::getImageFromUUID(const LLUUID &image_id,
609 if (level_immediate) 551 if (level_immediate)
610 { 552 {
611 imagep->dontDiscard(); 553 imagep->dontDiscard();
612 } 554 imagep->setBoostLevel(LLViewerImage::BOOST_UI);
613
614 // if rendering enabled, actually try to load this image
615 if (!gNoRender)
616 {
617 // First check the local image cache to see if it's there.
618 if (imagep->loadLocalImage(image_id))
619 {
620// llinfos << "Loading Local Image: " << image_id
621// << llformat(" MIP:%d IMM:%d",usemipmaps,level_immediate)
622// << llendl;
623 if( level_immediate )
624 {
625 if (imagep->needsDecode())
626 {
627 imagep->decodeImage(0.f); // getImage (local image)
628 }
629
630 if (imagep->getNeedsCreateTexture())
631 {
632 imagep->createTexture();
633 }
634 }
635 }
636 else
637 {
638 // if we don't have this locally, we'll want to start on the highest discard
639 if (!imagep->getDontDiscard())
640 {
641 imagep->setDesiredDiscardLevel(imagep->getMaxDiscardLevel());
642 }
643
644 imagep->startVFSLoad();
645 }
646 } 555 }
647 } 556 }
648 557
@@ -695,13 +604,6 @@ void LLViewerImageList::addImage(LLViewerImage *new_image)
695 } 604 }
696 sNumImages++; 605 sNumImages++;
697 606
698#if 0
699 // Add this image to the viewer image list.
700 if (new_image->getDecodePriority() == 0.0f)
701 {
702 new_image->setDecodePriority(MAX_IMAGE_PRIORITY); // Initially put in front of list
703 }
704#endif
705 addImageToList(new_image); 607 addImageToList(new_image);
706 mUUIDMap[image_id] = new_image; 608 mUUIDMap[image_id] = new_image;
707} 609}
@@ -721,35 +623,6 @@ void LLViewerImageList::deleteImage(LLViewerImage *image)
721 } 623 }
722} 624}
723 625
724
725
726
727///////////////////////////////////////////////////////////////////////////////
728
729void image_request_callback(void **data, S32 number)
730{
731 gImageList.handleIRCallback(data, number);
732}
733
734void LLViewerImageList::handleIRCallback(void **data, const S32 number)
735{
736 callback_data_t* requested_images = (callback_data_t*)data;
737 if (number == LL_ERR_TCP_TIMEOUT)
738 {
739 for (callback_data_t::iterator iter = requested_images->begin();
740 iter != requested_images->end();)
741 {
742 LLViewerImage* image = *iter++;
743 image->mRequested = FALSE;
744 image->mRequestedDiscardLevel = -1; // Indicates we need to re-request this
745 }
746 }
747
748 // Delete and remove from our list of callback data
749 delete requested_images;
750 llverify(mIRCallbackData.erase(requested_images) == 1);
751}
752
753/////////////////////////////////////////////////////////////////////////////// 626///////////////////////////////////////////////////////////////////////////////
754 627
755void LLViewerImageList::updateMovieImage(const LLUUID& uuid, BOOL active) 628void LLViewerImageList::updateMovieImage(const LLUUID& uuid, BOOL active)
@@ -785,7 +658,16 @@ void LLViewerImageList::updateMovieImage(const LLUUID& uuid, BOOL active)
785 } 658 }
786} 659}
787 660
788void LLViewerImageList::updateImages(const F32 decode_time_max) 661////////////////////////////////////////////////////////////////////////////
662
663void LLViewerImageList::dirtyImage(LLViewerImage *image)
664{
665 mDirtyTextureList.insert(image);
666}
667
668////////////////////////////////////////////////////////////////////////////
669
670void LLViewerImageList::updateImages(F32 max_time)
789{ 671{
790 sNumImagesStat.addValue(sNumImages); 672 sNumImagesStat.addValue(sNumImages);
791 sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount); 673 sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
@@ -795,28 +677,40 @@ void LLViewerImageList::updateImages(const F32 decode_time_max)
795 sFormattedMemStat.addValue(LLImageFormatted::sGlobalFormattedMemory/(1024.f*1024.f)); 677 sFormattedMemStat.addValue(LLImageFormatted::sGlobalFormattedMemory/(1024.f*1024.f));
796 678
797 updateImagesDecodePriorities(); 679 updateImagesDecodePriorities();
798 updateImagesSendRequests(); 680 max_time -= updateImagesFetchTextures(max_time);
799 681 max_time = llmax(max_time, 0.001f);
800 if (gGLManager.mIsDisabled) 682 max_time -= updateImagesCreateTextures(max_time);
683 max_time = llmax(max_time, 0.001f);
684
685 if (!mDirtyTextureList.empty())
801 { 686 {
802 // We don't want to run this part of the texture system while we don't have 687 LLFastTimer t(LLFastTimer::FTM_IMAGE_MARK_DIRTY);
803 // a GL context - we COULD probably do some of it, but that's tricky - djs 10/29/03 688 gPipeline.dirtyPoolObjectTextures(mDirtyTextureList);
804 return; 689 mDirtyTextureList.clear();
805 } 690 }
806 691
807 updateImagesDecodeTextures(decode_time_max); 692 for (image_list_t::iterator iter = mCallbackList.begin();
693 iter != mCallbackList.end(); )
694 {
695 LLViewerImage* image = *iter++;
696 // Do stuff to handle callbacks, update priorities, etc.
697 bool res = image->doLoadedCallbacks();
698 if (res)
699 {
700 break; // only actually do one callback per frame
701 }
702 }
703
808 updateImagesMediaStreams(); 704 updateImagesMediaStreams();
809 updateImagesPollVFS();
810 updateImagesUpdateStats(); 705 updateImagesUpdateStats();
811} 706}
812 707
813
814void LLViewerImageList::updateImagesDecodePriorities() 708void LLViewerImageList::updateImagesDecodePriorities()
815{ 709{
816 // Update the decode priority for N images each frame 710 // Update the decode priority for N images each frame
817 { 711 {
818 const size_t max_update_count = 256; 712 const size_t max_update_count = 256;
819 S32 update_counter = llmin(max_update_count, mUUIDMap.size()); 713 S32 update_counter = llmin(max_update_count, mUUIDMap.size()/10);
820 uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID); 714 uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID);
821 while(update_counter > 0) 715 while(update_counter > 0)
822 { 716 {
@@ -826,6 +720,33 @@ void LLViewerImageList::updateImagesDecodePriorities()
826 } 720 }
827 mLastUpdateUUID = iter->first; 721 mLastUpdateUUID = iter->first;
828 LLPointer<LLViewerImage> imagep = iter->second; 722 LLPointer<LLViewerImage> imagep = iter->second;
723 ++iter; // safe to incrament now
724
725 //
726 // Flush formatted images using a lazy flush
727 //
728 const F32 LAZY_FLUSH_TIMEOUT = 30.f;
729 S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference
730 if (imagep->hasCallbacks())
731 {
732 min_refs++; // Add an extra reference if we're on the loaded callback list
733 }
734 S32 num_refs = imagep->getNumRefs();
735 if (num_refs == min_refs)
736 {
737 if (imagep->mLastReferencedTimer.getElapsedTimeF32() > LAZY_FLUSH_TIMEOUT)
738 {
739 // Remove the unused image from the image list
740 deleteImage(imagep);
741 imagep = NULL; // should destroy the image
742 continue;
743 }
744 }
745 else
746 {
747 imagep->mLastReferencedTimer.reset();
748 }
749
829 imagep->processTextureStats(); 750 imagep->processTextureStats();
830 F32 old_priority = imagep->getDecodePriority(); 751 F32 old_priority = imagep->getDecodePriority();
831 F32 decode_priority = imagep->calcDecodePriority(); 752 F32 decode_priority = imagep->calcDecodePriority();
@@ -836,12 +757,12 @@ void LLViewerImageList::updateImagesDecodePriorities()
836 imagep->setDecodePriority(decode_priority); 757 imagep->setDecodePriority(decode_priority);
837 addImageToList(imagep); 758 addImageToList(imagep);
838 } 759 }
839 iter++;
840 update_counter--; 760 update_counter--;
841 } 761 }
842 } 762 }
843} 763}
844 764
765/*
845static U8 get_image_type(LLViewerImage* imagep, LLHost target_host) 766static U8 get_image_type(LLViewerImage* imagep, LLHost target_host)
846{ 767{
847 // Having a target host implies this is a baked image. I don't 768 // Having a target host implies this is a baked image. I don't
@@ -866,478 +787,90 @@ static U8 get_image_type(LLViewerImage* imagep, LLHost target_host)
866 } 787 }
867 return type_from_host; 788 return type_from_host;
868} 789}
790*/
869 791
870void LLViewerImageList::updateImagesSendRequests() 792F32 LLViewerImageList::updateImagesCreateTextures(F32 max_time)
871{ 793{
872 // Send requests for images based on priority. 794 if (gNoRender || gGLManager.mIsDisabled) return 0.0f;
873 {
874 S32 request_count = 0;
875 S32 request_packets_sent = 0;
876 S32 update_count = 0;
877 795
878 callback_data_t *requested_images = NULL; 796 //
879 797 // Create GL textures for all textures that need them (images which have been
880 // Baked texture images may live on a separate host. JC 798 // decoded, but haven't been pushed into GL).
881 std::vector< LLPointer<LLViewerImage> > images_on_other_hosts; 799 //
882 LLHost agent_host = gAgent.getRegionHost(); 800 LLFastTimer t(LLFastTimer::FTM_IMAGE_CREATE);
883
884 for (image_list_t::iterator iter = mImageList.begin();
885 iter != mImageList.end(); )
886 {
887 image_list_t::iterator curiter = iter++;
888 LLPointer<LLViewerImage> imagep = *curiter;
889
890 if (imagep->mIsMediaTexture)
891 {
892 continue; // skip
893 }
894
895 F32 decode_priority = imagep->getDecodePriority();
896
897 update_count++;
898 if (mUpdateStats == FALSE &&
899 update_count >= IMAGES_MIN_UPDATES &&
900 decode_priority < MAX_IMAGE_PRIORITY)
901 {
902 break;
903 }
904
905 //
906 // Flush formatted images using a lazy flush
907 //
908 const F32 LAZY_FLUSH_TIMEOUT = 30.f;
909 S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference
910 if (imagep->hasCallbacks())
911 {
912 min_refs++; // Add an extra reference if we're on the loaded callback list
913 }
914 S32 num_refs = imagep->getNumRefs();
915 if (num_refs == min_refs)
916 {
917 if (!(imagep->isDecoding()))
918 {
919 if (imagep->mLastReferencedTimer.getElapsedTimeF32() > LAZY_FLUSH_TIMEOUT)
920 {
921 if (imagep->mStreamFile && !imagep->mStreamFile->isReadComplete())
922 {
923 llwarns << "Stream file is still reading data, delaying flush!" << llendl;
924 }
925 else
926 {
927 // Remove the unused image from the image list
928 deleteImage(imagep);
929 imagep = NULL; // should destroy the image
930 continue;
931 }
932 }
933 }
934 }
935 else
936 {
937 imagep->mLastReferencedTimer.reset();
938 }
939
940 if (decode_priority <= 0)
941 {
942 continue;
943 }
944 if (imagep->isMissingAsset())
945 {
946 continue;
947 }
948 if (imagep->checkPacketData())
949 {
950 // New packets have been processed, re-evaluate next time
951 continue;
952 }
953 if (request_packets_sent >= IMAGES_MAX_PACKET_UPDATES)
954 {
955 continue;
956 }
957 if (!gAgent.getRegion())
958 {
959 //llinfos << "Skipping request for " << imagep->getID() << " while waiting for a region" << llendl;
960 continue;
961 }
962
963 F32 old_priority = imagep->mRequestedDownloadPriority;
964 S32 current_discard = imagep->getDiscardLevel();
965 S32 desired_discard = imagep->getDesiredDiscardLevel();
966
967 if (current_discard >= 0 && current_discard <= desired_discard)
968 {
969 continue;
970 }
971
972 if (imagep->mRequestTime.getElapsedTimeF32() <= RESEND_IMAGE_REQUEST_TIME)
973 {
974 // Ignore < 20% difference, or no change in requested discard level
975 if ((decode_priority > old_priority * .8f && decode_priority < old_priority * 1.25f) &&
976 (desired_discard == imagep->mRequestedDiscardLevel))
977 {
978 continue;
979 }
980 }
981
982 // Send the request
983 {
984 // Baked avatar textures may live on other hosts. JC
985 LLHost target_host = imagep->getTargetHost();
986
987 // This file is in the static VFS, we don't ever need to request it from the network.
988 if (imagep->mInStaticVFS && imagep->mFormattedFlushed)
989 {
990 // Unneeded? JC 8/2006
991 imagep->mRequestedDiscardLevel = desired_discard;
992 imagep->mRequestedDownloadPriority = decode_priority;
993
994 // It's in the static VFS but not loaded, just load it from disk instead of sending a request.
995 imagep->startVFSLoad();
996 }
997 else if (target_host.isOk() && target_host != agent_host)
998 {
999 // This is a special texture to request off a sim other than
1000 // the one the agent is on. We'll deal with it later.
1001 images_on_other_hosts.push_back(imagep);
1002 }
1003 else
1004 {
1005 imagep->mRequestedDiscardLevel = desired_discard;
1006 imagep->mRequestedDownloadPriority = decode_priority;
1007
1008 if (0 == request_count)
1009 {
1010 // Create a message if this is the first image request.
1011 gMessageSystem->newMessageFast(_PREHASH_RequestImage);
1012 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
1013 gMessageSystem->addUUIDFast(
1014 _PREHASH_AgentID, gAgent.getID());
1015 gMessageSystem->addUUIDFast(
1016 _PREHASH_SessionID, gAgent.getSessionID());
1017 requested_images = new callback_data_t;
1018 // verify that requested_images is placed uniquely in the list
1019 llverify((mIRCallbackData.insert(requested_images)).second);
1020 }
1021
1022 requested_images->push_back(imagep);
1023 request_count++;
1024
1025 gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
1026 S32 packet = imagep->getLastPacket() + 1;
1027 gMessageSystem->addUUIDFast(_PREHASH_Image, imagep->getID());
1028 gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)desired_discard);
1029 gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, decode_priority);
1030 gMessageSystem->addU32Fast(_PREHASH_Packet, packet);
1031 U8 type = get_image_type(imagep, target_host);
1032 gMessageSystem->addU8Fast(_PREHASH_Type, type);
1033
1034 lldebugst(LLERR_IMAGE)
1035 << "IMAGE REQUEST: " << imagep->getID().getString()
1036 << " discard: " << desired_discard
1037 << " old_pri: " << old_priority
1038 << " dld_pri: " << decode_priority
1039 << " dec_pri: " << imagep->getDecodePriority()
1040 << llendl;
1041
1042 }
1043
1044 imagep->mRequested = TRUE;
1045 imagep->mRequestTime.reset();
1046
1047 if (request_count >= IMAGES_PER_REQUEST)
1048 {
1049 // IMAGES_PER_REQUEST packets combined, send packet.
1050 gMessageSystem->sendSemiReliable(gAgent.getRegion()->getHost(), image_request_callback, (void **)requested_images);
1051 801
1052 requested_images = NULL; 802 LLTimer create_timer;
1053 request_count = 0; 803 image_list_t::iterator enditer = mCreateTextureList.begin();
1054 ++request_packets_sent; 804 for (image_list_t::iterator iter = mCreateTextureList.begin();
1055 } 805 iter != mCreateTextureList.end();)
1056 } 806 {
1057 } 807 image_list_t::iterator curiter = iter++;
1058 808 enditer = iter;
1059 if (request_count != 0) 809 LLViewerImage *imagep = *curiter;
1060 { 810 imagep->createTexture();
1061 // fill in the unused requested_images w/ NULL 811 if (create_timer.getElapsedTimeF32() > max_time)
1062 gMessageSystem->sendSemiReliable(gAgent.getRegion()->getHost(), image_request_callback, (void **)requested_images);
1063 requested_images = NULL;
1064 ++request_packets_sent;
1065 }
1066
1067 // We might have picked up some images on other hosts.
1068 if (!images_on_other_hosts.empty())
1069 { 812 {
1070 // llinfos << "TAT: images_on_other_hosts " << images_on_other_hosts.size() << llendl; 813 break;
1071
1072 std::sort(images_on_other_hosts.begin(), images_on_other_hosts.end(), LLViewerImage::CompareByHostAndPriority());
1073
1074 LLMessageSystem* msg = gMessageSystem;
1075 LLHost current_host = images_on_other_hosts[0]->getTargetHost();
1076 request_count = 0;
1077
1078 for (std::vector<LLPointer<LLViewerImage> >::iterator it = images_on_other_hosts.begin();
1079 it != images_on_other_hosts.end();
1080 ++it)
1081 {
1082 LLPointer<LLViewerImage> imagep = *it;
1083
1084 F32 decode_priority = imagep->getDecodePriority();
1085 S32 desired_discard = imagep->getDesiredDiscardLevel();
1086
1087 imagep->mRequestedDiscardLevel = desired_discard;
1088 imagep->mRequestedDownloadPriority = decode_priority;
1089
1090 if ((current_host != imagep->getTargetHost() || request_count >= IMAGES_PER_REQUEST) && request_count)
1091 {
1092 // llinfos << "TAT: Sending " << request_count << " image requests for host: " << current_host << llendl;
1093
1094 // Need to flush to current host.
1095 gMessageSystem->sendSemiReliable(current_host, image_request_callback, (void **)requested_images);
1096
1097 requested_images = NULL;
1098 current_host = imagep->getTargetHost();
1099 request_count = 0;
1100 }
1101
1102 if (request_count == 0)
1103 {
1104 // Start a packet and build a new callback list for dropped
1105 // packet handler.
1106 msg->newMessageFast(_PREHASH_RequestImage);
1107 msg->nextBlockFast(_PREHASH_AgentData);
1108 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1109 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1110 requested_images = new callback_data_t;
1111 mIRCallbackData.insert(requested_images);
1112 current_host = imagep->getTargetHost();
1113 }
1114
1115 requested_images->push_back(imagep);
1116 request_count++;
1117
1118 msg->nextBlockFast(_PREHASH_RequestImage);
1119 S32 packet = imagep->getLastPacket() + 1;
1120 msg->addUUIDFast(_PREHASH_Image, imagep->getID());
1121 msg->addS8Fast(_PREHASH_DiscardLevel, (S8)desired_discard);
1122 msg->addF32Fast(_PREHASH_DownloadPriority, decode_priority);
1123 msg->addU32Fast(_PREHASH_Packet, packet);
1124 U8 type = get_image_type(imagep, current_host);
1125 gMessageSystem->addU8Fast(_PREHASH_Type, type);
1126
1127 if (!gMessageSystem->checkCircuitAlive(current_host))
1128 {
1129 llinfos << "TAT: Image request for dead circuit " << current_host << ", " << imagep->getID() << llendl;
1130 imagep->setTargetHost(agent_host);
1131 }
1132
1133 if (!gMessageSystem->checkCircuitAlive(current_host))
1134 {
1135 llinfos << "TAT: Image request for dead circuit " << current_host << ", " << imagep->getID() << llendl;
1136 imagep->setTargetHost(agent_host);
1137 }
1138
1139 imagep->mRequested = TRUE;
1140 imagep->mRequestTime.reset();
1141 }
1142
1143 if (request_count != 0)
1144 {
1145 // fill in the unused requested_images w/ NULL
1146 msg->sendSemiReliable(current_host, image_request_callback, (void **)requested_images);
1147 requested_images = NULL;
1148 }
1149 } 814 }
1150 } 815 }
816 mCreateTextureList.erase(mCreateTextureList.begin(), enditer);
817 return create_timer.getElapsedTimeF32();
1151} 818}
1152 819
1153 820F32 LLViewerImageList::updateImagesFetchTextures(F32 max_time)
1154
1155void LLViewerImageList::updateImagesDecodeTextures(F32 decode_time_max)
1156{ 821{
1157 if (gNoRender) return; 822 LLTimer image_op_timer;
1158 823
1159 LLTimer image_op_timer; 824 // Update the decode priority for N images each frame
1160 825 // Make a list with 32 high priority entries + 256 cycled entries
1161 BOOL done_one = FALSE; 826 const size_t max_priority_count = 32;
1162 image_op_timer.reset(); 827 const size_t max_update_count = 256;
1163 828
1164 S32 create_count = 0; 829 // 32 high priority entries
1165 830 std::set<LLViewerImage*> entries;
1166 // added by IW to help track down a bug 831 size_t update_counter = llmin(max_priority_count, mImageList.size());
1167 stop_glerror(); 832 image_priority_list_t::iterator iter1 = mImageList.begin();
1168 833 while(update_counter > 0)
1169 // 834 {
1170 // Create GL textures for all textures that need them (images which have been 835 entries.insert(*iter1);
1171 // decoded, but haven't been pushed into GL). 836 ++iter1;
1172 // 837 update_counter--;
1173 { 838 }
1174 LLFastTimer t(LLFastTimer::FTM_IMAGE_CREATE); 839
1175 840 // 256 cycled entries
1176 for (image_list_t::iterator iter = mImageList.begin(); 841 update_counter = llmin(max_update_count, mUUIDMap.size());
1177 iter != mImageList.end(); ) 842 uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
1178 { 843 while(update_counter > 0)
1179 LLPointer<LLViewerImage> imagep = *iter++; 844 {
1180 if (imagep->getNeedsCreateTexture()) 845 if (iter2 == mUUIDMap.end())
1181 {
1182 create_count++;
1183 imagep->createTexture();
1184 if (decode_time_max != 0.f)
1185 {
1186 if (image_op_timer.getElapsedTimeF32() > decode_time_max)
1187 {
1188 lldebugst(LLERR_IMAGE) << "Broke out of create texture!" << llendl;
1189 break;
1190 }
1191 }
1192 }
1193 }
1194 }
1195
1196 //
1197 // Work on decoding any image that's partially decoded, first
1198 //
1199 // Everything after here is time-sliced
1200 //
1201
1202 if (mCurrentDecodeImagep.notNull()
1203 && mCurrentDecodeImagep->needsDecode()
1204 && mCurrentDecodeImagep->isDecoding())
1205 {
1206 //llinfos << "Continue decoding " << mCurrentDecodeImagep->getID() << llendl;
1207 LLFastTimer t(LLFastTimer::FTM_IMAGE_DECODE);
1208 if (decode_time_max != 0.f)
1209 {
1210 if (done_one && image_op_timer.getElapsedTimeF32() >= decode_time_max)
1211 {
1212 lldebugst(LLERR_IMAGE) << "Broke out of partial decode!" << llendl;
1213 }
1214 else
1215 {
1216 F32 decode_time = decode_time_max - image_op_timer.getElapsedTimeF32();
1217 decode_time = llmax(decode_time, .0001f); // min .1 ms
1218 mCurrentDecodeImagep->decodeImage(decode_time); // Partial decode
1219 done_one = TRUE;
1220 }
1221 }
1222 else
1223 {
1224 mCurrentDecodeImagep->decodeImage(0.0f); // Partial decode
1225 done_one = TRUE;
1226 }
1227 }
1228
1229 //
1230 // Reprioritize any image that we just finished decoding
1231 //
1232 if (mCurrentDecodeImagep.notNull()
1233 && (!mCurrentDecodeImagep->needsDecode()
1234 || !mCurrentDecodeImagep->isDecoding()))
1235 { 846 {
1236 // Reprioritize this image 847 iter2 = mUUIDMap.begin();
1237 if (mCurrentDecodeImagep->mInImageList)
1238 {
1239 removeImageFromList(mCurrentDecodeImagep);
1240 mCurrentDecodeImagep->setDecodePriority();
1241 addImageToList(mCurrentDecodeImagep);
1242 }
1243 mCurrentDecodeImagep = NULL;
1244 } 848 }
849 mLastFetchUUID = iter2->first;
850 entries.insert(iter2->second);
851 ++iter2;
852 update_counter--;
853 }
1245 854
1246 // 855 S32 min_count = max_priority_count + max_update_count/4;
1247 // At this point, we're going to check out the status of anything that's 856 for (std::set<LLViewerImage*>::iterator iter3 = entries.begin();
1248 // on our callback list. Instead of calling the callback lists from a 857 iter3 != entries.end(); )
1249 // billion different places, we're ONLY going to handle them here. 858 {
1250 // 859 LLPointer<LLViewerImage> imagep = *iter3++;
1251 // Do this here so if the callbacks take a lot of time, it counts
1252 // against our decode timer totals
1253
1254 // For right now, just be really lame and just iterate through all images.
1255 // This WILL be optimized soon.
1256
1257 if (mUpdateStats)
1258 {
1259 // This is somewhat intensive, and it doesn't need to happen
1260 // immediately, so only do it when we update stats.
1261 for (image_callback_list_t::iterator iter = mCallbackList.begin();
1262 iter != mCallbackList.end(); )
1263 {
1264 LLViewerImage* image = *iter++;
1265 // Do stuff to handle callbacks, update priorities, etc.
1266 image->doLoadedCallbacks();
1267 }
1268 }
1269 860
1270 // 861 imagep->updateFetch();
1271 // Decode as many images as we can at this point. 862 if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
1272 // If we're in the middle of finishing up one still,
1273 // don't decode any more textures
1274 //
1275 if (mCurrentDecodeImagep.isNull() || mCurrentDecodeImagep->getBoostLevel())
1276 { 863 {
1277 LLFastTimer t(LLFastTimer::FTM_IMAGE_DECODE); 864 break;
1278 do
1279 {
1280 BOOL did_decode = FALSE;
1281 BOOL have_map_image = FALSE;
1282 for (image_list_t::iterator iter = mImageList.begin();
1283 iter != mImageList.end(); )
1284 {
1285 image_list_t::iterator curiter = iter++;
1286 LLPointer<LLViewerImage> imagep = *curiter;
1287 if (imagep->needsDecode())
1288 {
1289 if (decode_time_max != 0.f)
1290 {
1291 if (!imagep->getBoostLevel() && done_one &&
1292 image_op_timer.getElapsedTimeF32() >= decode_time_max)
1293 {
1294 break;
1295 }
1296 F32 decode_time = decode_time_max - image_op_timer.getElapsedTimeF32();
1297 decode_time = llmax(decode_time, .0001f); // min .1 ms
1298 imagep->decodeImage(decode_time);
1299 }
1300 else
1301 {
1302 imagep->decodeImage(0.0f);
1303 }
1304
1305 if (imagep->needsDecode())
1306 {
1307 mCurrentDecodeImagep = imagep;
1308 }
1309 else
1310 {
1311 // Reprioritize this image
1312 removeImageFromList(imagep);
1313 imagep->setDecodePriority();
1314 addImageToList(imagep);
1315
1316 mCurrentDecodeImagep = NULL;
1317 }
1318 done_one = TRUE;
1319 did_decode = TRUE;
1320 }
1321 if (imagep->getBoostLevel() >= LLViewerImage::BOOST_MAP)
1322 {
1323 have_map_image = TRUE;
1324 }
1325 else if (have_map_image)
1326 {
1327 break; // skip other images if we are decoding map images
1328 }
1329 }
1330 if (!did_decode)
1331 {
1332 break;
1333 }
1334 } while (image_op_timer.getElapsedTimeF32() < decode_time_max);
1335 } 865 }
866 min_count--;
867 }
868 return image_op_timer.getElapsedTimeF32();
1336} 869}
1337 870
1338void LLViewerImageList::updateImagesMediaStreams() 871void LLViewerImageList::updateImagesMediaStreams()
1339{ 872{
1340 if (gNoRender) return; 873 if (gNoRender || gGLManager.mIsDisabled) return;
1341 874
1342 // update media stream if required 875 // update media stream if required
1343 LLMediaEngine* media_engine = LLMediaEngine::getInstance(); 876 LLMediaEngine* media_engine = LLMediaEngine::getInstance();
@@ -1358,8 +891,6 @@ void LLViewerImageList::updateImagesMediaStreams()
1358 (renderer->getTextureDepth() != viewerImage->getComponents()) || 891 (renderer->getTextureDepth() != viewerImage->getComponents()) ||
1359 (viewerImage->getHasGLTexture() == FALSE)) 892 (viewerImage->getHasGLTexture() == FALSE))
1360 { 893 {
1361 llassert(!viewerImage->getUseMipMaps());
1362
1363 // destroy existing GL image 894 // destroy existing GL image
1364 viewerImage->destroyGLTexture(); 895 viewerImage->destroyGLTexture();
1365 896
@@ -1380,14 +911,15 @@ void LLViewerImageList::updateImagesMediaStreams()
1380 renderer->getTextureFormatPrimary(), 911 renderer->getTextureFormatPrimary(),
1381 renderer->getTextureFormatType(), 912 renderer->getTextureFormatType(),
1382 renderer->getTextureFormatSwapBytes()); 913 renderer->getTextureFormatSwapBytes());
914 // This should be redundant, but just in case:
915 viewerImage->setUseMipMaps(FALSE);
1383 916
1384 LLImageRaw* rawImage = media_engine->getImageRaw(); 917 LLImageRaw* rawImage = media_engine->getImageRaw();
1385
1386 if ( rawImage ) 918 if ( rawImage )
1387 { 919 {
1388 ((LLImageGL*)viewerImage)->setSubImage(rawImage, 0, 0, 920 viewerImage->setSubImage(rawImage, 0, 0,
1389 renderer->getMediaWidth(), 921 renderer->getMediaWidth(),
1390 renderer->getMediaHeight()); 922 renderer->getMediaHeight());
1391 } 923 }
1392 } 924 }
1393 else 925 else
@@ -1404,89 +936,76 @@ void LLViewerImageList::updateImagesMediaStreams()
1404 } 936 }
1405} 937}
1406 938
1407void LLViewerImageList::updateImagesPollVFS()
1408{
1409 // Sigh, VFS stuff has to be polled. The VFS really needs some sort
1410 // of mechanism to avoid this issue.
1411 for (image_loading_list_t::iterator iter = mLoadingStreamList.begin();
1412 iter != mLoadingStreamList.end();)
1413 {
1414 image_loading_list_t::iterator curiter = iter++;
1415 LLViewerImage *imagep = *curiter;
1416 imagep->loadStreamFile();
1417 if (!imagep->mStreamFile)
1418 {
1419 iter = mLoadingStreamList.erase(curiter);
1420 }
1421 }
1422}
1423
1424void LLViewerImageList::updateImagesUpdateStats() 939void LLViewerImageList::updateImagesUpdateStats()
1425{ 940{
1426 if (mUpdateStats) 941 if (mUpdateStats)
1427 { 942 {
1428 for (image_list_t::iterator iter = mImageList.begin(); 943 for (image_priority_list_t::iterator iter = mImageList.begin();
1429 iter != mImageList.end(); ) 944 iter != mImageList.end(); )
1430 { 945 {
1431 LLViewerImage* imagep = *iter++; 946 LLViewerImage* imagep = *iter++;
1432 imagep->resetTextureStats(mForceResetTextureStats); 947 imagep->resetTextureStats(mForceResetTextureStats);
1433 } 948 }
1434#if 0
1435 S32 needs_decode_count = 0;
1436 for (image_list_t::iterator iter = mImageList.begin();
1437 iter != mImageList.end(); )
1438 {
1439 LLViewerImage* imagep = *iter++;
1440 // count priority images in need of decode (10000 ~= 100x100 pixels)
1441 if (imagep->getDecodePriority() > 10000.f && (imagep->needsDecode() || imagep->getNeedsCreateTexture()))
1442 {
1443 needs_decode_count++;
1444 }
1445 }
1446
1447 // If we have a lot of priority decodes pending, take some time to decode them
1448 const S32 force_decode_count = 20;
1449 const F32 force_decode_time = 2.f; // seconds
1450 const F32 force_decode_delay = 30.f; // seconds
1451 if (needs_decode_count > force_decode_count && mForceDecodeTimer.hasExpired())
1452 {
1453 decodeAllImages(force_decode_time); // spend some time decoding images
1454 mForceDecodeTimer.setTimerExpirySec(force_decode_delay); // wait 10 seconds
1455 }
1456#endif
1457 mUpdateStats = FALSE; 949 mUpdateStats = FALSE;
1458 mForceResetTextureStats = FALSE; 950 mForceResetTextureStats = FALSE;
1459 } 951 }
1460} 952}
1461 953
1462void LLViewerImageList::decodeAllImages(F32 max_decode_time) 954void LLViewerImageList::decodeAllImages(F32 max_time)
1463{ 955{
1464 LLTimer timer; 956 LLTimer timer;
1465 if(!gNoRender) 957 if(!gNoRender)
1466 { 958 {
1467 for (image_list_t::iterator iter = mImageList.begin(); 959 // Update texture stats and priorities
960 std::vector<LLPointer<LLViewerImage> > image_list;
961 for (image_priority_list_t::iterator iter = mImageList.begin();
1468 iter != mImageList.end(); ) 962 iter != mImageList.end(); )
1469 { 963 {
1470 LLViewerImage* imagep = *iter++; 964 LLViewerImage* imagep = *iter++;
1471 if (imagep->needsDecode()) 965 image_list.push_back(imagep);
1472 { 966 imagep->mInImageList = FALSE;
1473 imagep->decodeImage(0.f); // LLViewerImageList::decodeAllImages 967 }
1474 } 968 mImageList.clear();
1475 if (max_decode_time > 0.0f && timer.getElapsedTimeF32() > max_decode_time) 969 for (std::vector<LLPointer<LLViewerImage> >::iterator iter = image_list.begin();
970 iter != image_list.end(); ++iter)
971 {
972 LLViewerImage* imagep = *iter;
973 imagep->processTextureStats();
974 F32 decode_priority = imagep->calcDecodePriority();
975 imagep->setDecodePriority(decode_priority);
976 mImageList.insert(imagep);
977 imagep->mInImageList = TRUE;
978 }
979 image_list.clear();
980
981 // Update fetch (decode)
982 for (image_priority_list_t::iterator iter = mImageList.begin();
983 iter != mImageList.end(); )
984 {
985 LLViewerImage* imagep = *iter++;
986 imagep->updateFetch();
987 }
988 // Run threads
989 while (1)
990 {
991 gTextureCache->update(1); // unpauses the texture cache thread
992 gImageDecodeThread->update(1); // unpauses the image thread
993 S32 fetch_pending = gTextureFetch->update(1); // unpauses the texture fetch thread
994 if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time)
1476 { 995 {
1477 break; 996 break;
1478 } 997 }
1479 } 998 }
1480 999 // Update fetch again
1481 for (image_list_t::iterator iter = mImageList.begin(); 1000 for (image_priority_list_t::iterator iter = mImageList.begin();
1482 iter != mImageList.end(); ) 1001 iter != mImageList.end(); )
1483 { 1002 {
1484 LLViewerImage* imagep = *iter++; 1003 LLViewerImage* imagep = *iter++;
1485 if (imagep->getNeedsCreateTexture()) 1004 imagep->updateFetch();
1486 {
1487 imagep->createTexture();
1488 }
1489 } 1005 }
1006 max_time -= timer.getElapsedTimeF32();
1007 max_time = llmax(max_time, .01f);
1008 updateImagesCreateTextures(max_time);
1490 } 1009 }
1491 if (timer.getElapsedTimeF32() > .5f) // seconds 1010 if (timer.getElapsedTimeF32() > .5f) // seconds
1492 { 1011 {
@@ -1560,12 +1079,8 @@ BOOL LLViewerImageList::createUploadFile(const LLString& filename,
1560 return FALSE; 1079 return FALSE;
1561 } 1080 }
1562 1081
1563 raw_image->biasedScaleToPowerOfTwo(LLViewerImage::MAX_IMAGE_SIZE_DEFAULT); 1082 LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
1564
1565 LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C;
1566 1083
1567 compressedImage->setRate(0.f);
1568 compressedImage->encode(raw_image);
1569 if( !compressedImage->save(out_filename) ) 1084 if( !compressedImage->save(out_filename) )
1570 { 1085 {
1571 llinfos << "Couldn't create output file " << out_filename << llendl; 1086 llinfos << "Couldn't create output file " << out_filename << llendl;
@@ -1583,6 +1098,17 @@ BOOL LLViewerImageList::createUploadFile(const LLString& filename,
1583 return TRUE; 1098 return TRUE;
1584} 1099}
1585 1100
1101// note: modifies the argument raw_image!!!!
1102LLPointer<LLImageJ2C> LLViewerImageList::convertToUploadFile(LLPointer<LLImageRaw> raw_image)
1103{
1104 raw_image->biasedScaleToPowerOfTwo(LLViewerImage::MAX_IMAGE_SIZE_DEFAULT);
1105 LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C();
1106 compressedImage->setRate(0.f);
1107 compressedImage->encode(raw_image);
1108
1109 return compressedImage;
1110}
1111
1586//static 1112//static
1587S32 LLViewerImageList::getMaxVideoRamSetting(S32 max) 1113S32 LLViewerImageList::getMaxVideoRamSetting(S32 max)
1588{ 1114{
@@ -1606,7 +1132,7 @@ S32 LLViewerImageList::getMaxVideoRamSetting(S32 max)
1606 llwarns << "VRAM amount not detected, defaulting to " << max_vram/(double)(1<<20) << " MB" << llendl; 1132 llwarns << "VRAM amount not detected, defaulting to " << max_vram/(double)(1<<20) << " MB" << llendl;
1607 } 1133 }
1608 U32 system_ram = gSysMemory.getPhysicalMemory(); 1134 U32 system_ram = gSysMemory.getPhysicalMemory();
1609 llinfos << "*** DETECTED " << system_ram/(double)(1<<20) << " MB of system memory." << llendl; // TomY TESTING DNCI 1135 //llinfos << "*** DETECTED " << system_ram/(double)(1<<20) << " MB of system memory." << llendl; // TomY TESTING DNCI
1610 if (max == -2) 1136 if (max == -2)
1611 { 1137 {
1612 max_vram = llmin(max_vram, (U32)(system_ram/2)); // max recommended setting 1138 max_vram = llmin(max_vram, (U32)(system_ram/2)); // max recommended setting
@@ -1629,6 +1155,16 @@ S32 LLViewerImageList::getMaxVideoRamSetting(S32 max)
1629 return idx; 1155 return idx;
1630} 1156}
1631 1157
1158const S32 VIDEO_CARD_MEM_SIZES[6] = { 0x1000000, // 16MB
1159 0x2000000, // 32MB
1160 0x4000000, // 64MB
1161 0x8000000, // 128MB
1162 0x10000000, // 256MB
1163 0x20000000, // 512MB
1164 };
1165
1166const S32 VIDEO_CARD_FRAMEBUFFER_MEM = 0xC00000; // 12MB
1167
1632void LLViewerImageList::updateMaxResidentTexMem(S32 max, U32 fudge) 1168void LLViewerImageList::updateMaxResidentTexMem(S32 max, U32 fudge)
1633{ 1169{
1634 // Initialize the image pipeline VRAM settings 1170 // Initialize the image pipeline VRAM settings
@@ -1651,15 +1187,127 @@ void LLViewerImageList::updateMaxResidentTexMem(S32 max, U32 fudge)
1651 } 1187 }
1652 mVideoMemorySetting = cur_setting; 1188 mVideoMemorySetting = cur_setting;
1653 // TODO: set available resident texture mem based on use by other subsystems 1189 // TODO: set available resident texture mem based on use by other subsystems
1654 // currently 12MB assumed... 1190 // currently max(12MB, VRAM/4) assumed...
1191
1192 S32 vram_amt = VIDEO_CARD_MEM_SIZES[cur_setting];
1193 S32 fb_mem = llmax(VIDEO_CARD_FRAMEBUFFER_MEM, vram_amt/4);
1194 mMaxResidentTexMem = vram_amt - fb_mem - fudge;
1655 1195
1656 mMaxResidentTexMem = VIDEO_CARD_MEM_SIZES[cur_setting] - 0xC00000 - fudge; // - 12MB 1196// llinfos << "Graphics Card memory set to " << (VIDEO_CARD_MEM_SIZES[cur_setting]>>20)
1657 mMaxResidentTexMem -= mMaxResidentTexMem/8; 1197// << " MB" << llendl;
1198}
1199
1200///////////////////////////////////////////////////////////////////////////////
1201
1202// static
1203void LLViewerImageList::receiveImageHeader(LLMessageSystem *msg, void **user_data)
1204{
1205 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1206
1207 // Receive image header, copy into image object and decompresses
1208 // if this is a one-packet image.
1209
1210 LLUUID id;
1211
1212 char ip_string[256];
1213 u32_to_ip_string(msg->getSenderIP(),ip_string);
1214
1215 if (msg->getReceiveCompressedSize())
1216 {
1217 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
1218 }
1219 else
1220 {
1221 gImageList.sTextureBits += msg->getReceiveSize() * 8;
1222 }
1223 gImageList.sTexturePackets++;
1224
1225 U8 codec;
1226 U16 packets;
1227 U32 totalbytes;
1228 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
1229 msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, codec);
1230 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, packets);
1231 msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, totalbytes);
1232
1233 U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
1234 if (!data_size)
1235 {
1236 return;
1237 }
1658 1238
1659 llinfos << "Graphics Card memory set to " << (VIDEO_CARD_MEM_SIZES[cur_setting]>>20) 1239 // this buffer gets saved off in the packet list
1660 << " MB" << llendl; 1240 U8 *data = new U8[data_size];
1241 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
1242
1243 LLViewerImage *image = gImageList.getImage(id);
1244 if (!image)
1245 {
1246 return;
1247 }
1248 image->mLastPacketTimer.reset();
1249 bool res = gTextureFetch->receiveImageHeader(msg->getSender(), id, codec, packets, totalbytes, data_size, data);
1250 if (!res)
1251 {
1252 delete[] data;
1253 }
1661} 1254}
1662 1255
1256// static
1257void LLViewerImageList::receiveImagePacket(LLMessageSystem *msg, void **user_data)
1258{
1259 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1260 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1261
1262 // Receives image packet, copy into image object,
1263 // checks if all packets received, decompresses if so.
1264
1265 LLUUID id;
1266 U16 packet_num;
1267
1268 char ip_string[256];
1269 u32_to_ip_string(msg->getSenderIP(),ip_string);
1270
1271 if (msg->getReceiveCompressedSize())
1272 {
1273 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
1274 }
1275 else
1276 {
1277 gImageList.sTextureBits += msg->getReceiveSize() * 8;
1278 }
1279 gImageList.sTexturePackets++;
1280
1281 //llprintline("Start decode, image header...");
1282 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
1283 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num);
1284 U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
1285
1286 if (!data_size)
1287 {
1288 return;
1289 }
1290 if (data_size > MTUBYTES)
1291 {
1292 llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
1293 }
1294 U8 *data = new U8[data_size];
1295 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
1296
1297 LLViewerImage *image = gImageList.getImage(id);
1298 if (!image)
1299 {
1300 return;
1301 }
1302 image->mLastPacketTimer.reset();
1303 bool res = gTextureFetch->receiveImagePacket(msg->getSender(), id, packet_num, data_size, data);
1304 if (!res)
1305 {
1306 delete[] data;
1307 }
1308}
1309
1310
1663// We've been that the asset server does not contain the requested image id. 1311// We've been that the asset server does not contain the requested image id.
1664// static 1312// static
1665void LLViewerImageList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data) 1313void LLViewerImageList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
@@ -1671,6 +1319,26 @@ void LLViewerImageList::processImageNotInDatabase(LLMessageSystem *msg,void **us
1671 LLViewerImage* image = gImageList.hasImage( image_id ); 1319 LLViewerImage* image = gImageList.hasImage( image_id );
1672 if( image ) 1320 if( image )
1673 { 1321 {
1674 image->setIsMissingAsset( TRUE ); 1322 image->setIsMissingAsset();
1675 } 1323 }
1676} 1324}
1325
1326///////////////////////////////////////////////////////////////////////////////
1327
1328//static
1329const U32 SIXTEEN_MEG = 0x1000000;
1330S32 LLViewerImageList::calcMaxTextureRAM()
1331{
1332 // Decide the maximum amount of RAM we should allow the user to allocate to texture cache
1333 LLMemoryInfo memory_info;
1334 U32 available_memory = memory_info.getPhysicalMemory();
1335
1336 clamp_rescale((F32)available_memory,
1337 (F32)(SIXTEEN_MEG * 16),
1338 (F32)U32_MAX,
1339 (F32)(SIXTEEN_MEG * 4),
1340 (F32)(U32_MAX >> 1));
1341 return available_memory;
1342}
1343
1344///////////////////////////////////////////////////////////////////////////////