diff options
Diffstat (limited to 'linden/indra/newview/llviewerimagelist.cpp')
-rw-r--r-- | linden/indra/newview/llviewerimagelist.cpp | 1224 |
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 | ||
56 | void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL; | 59 | //////////////////////////////////////////////////////////////////////////// |
57 | 60 | ||
58 | const U32 SIXTEEN_MEG = 0x1000000; | 61 | void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL; |
59 | const F32 MAX_IMAGE_PRIORITY = 100000000.f; | ||
60 | 62 | ||
61 | U32 LLViewerImageList::sTextureBits = 0; | 63 | U32 LLViewerImageList::sTextureBits = 0; |
62 | U32 LLViewerImageList::sTexturePackets = 0; | 64 | U32 LLViewerImageList::sTexturePackets = 0; |
63 | 65 | ||
64 | struct 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. | ||
73 | const S32 CODEC_EXT_MAP_COUNT = 2; | ||
74 | const CodecExtMap CODEC_EXT_MAP[CODEC_EXT_MAP_COUNT] = | ||
75 | { | ||
76 | CodecExtMap( "_07", IMG_CODEC_J2C ), | ||
77 | CodecExtMap( ".tga", IMG_CODEC_TGA ) | ||
78 | }; | ||
79 | |||
80 | const 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. | ||
85 | const 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 | |||
93 | const S32 IMAGES_PER_REQUEST = 42; | 66 | const S32 IMAGES_PER_REQUEST = 42; |
94 | const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame | 67 | const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame |
95 | const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame | 68 | const 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); | |||
105 | LLStat LLViewerImageList::sRawMemStat(32, TRUE); | 78 | LLStat LLViewerImageList::sRawMemStat(32, TRUE); |
106 | LLStat LLViewerImageList::sFormattedMemStat(32, TRUE); | 79 | LLStat LLViewerImageList::sFormattedMemStat(32, TRUE); |
107 | 80 | ||
108 | //static | ||
109 | S32 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 | ||
126 | LLViewerImageList::LLViewerImageList() | 83 | LLViewerImageList::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 | ||
195 | void LLViewerImageList::doPreloadImages() | 117 | void 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 | ||
283 | static 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 | |||
289 | void 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 | ||
360 | LLViewerImageList::~LLViewerImageList() | 324 | LLViewerImageList::~LLViewerImageList() |
@@ -364,43 +328,70 @@ LLViewerImageList::~LLViewerImageList() | |||
364 | 328 | ||
365 | void LLViewerImageList::shutdown() | 329 | void 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 | ||
400 | void LLViewerImageList::dump() | 391 | void 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 | ||
459 | LLViewerImage * LLViewerImageList::getImage(const LLString& filename, | 450 | LLViewerImage* 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 | ||
467 | LLViewerImage * LLViewerImageList::getImageFromFile(const LLString& filename, | 458 | LLViewerImage* 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 | |||
729 | void image_request_callback(void **data, S32 number) | ||
730 | { | ||
731 | gImageList.handleIRCallback(data, number); | ||
732 | } | ||
733 | |||
734 | void 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 | ||
755 | void LLViewerImageList::updateMovieImage(const LLUUID& uuid, BOOL active) | 628 | void 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 | ||
788 | void LLViewerImageList::updateImages(const F32 decode_time_max) | 661 | //////////////////////////////////////////////////////////////////////////// |
662 | |||
663 | void LLViewerImageList::dirtyImage(LLViewerImage *image) | ||
664 | { | ||
665 | mDirtyTextureList.insert(image); | ||
666 | } | ||
667 | |||
668 | //////////////////////////////////////////////////////////////////////////// | ||
669 | |||
670 | void 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 | |||
814 | void LLViewerImageList::updateImagesDecodePriorities() | 708 | void 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 | /* | ||
845 | static U8 get_image_type(LLViewerImage* imagep, LLHost target_host) | 766 | static 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 | ||
870 | void LLViewerImageList::updateImagesSendRequests() | 792 | F32 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 | 820 | F32 LLViewerImageList::updateImagesFetchTextures(F32 max_time) | |
1154 | |||
1155 | void 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 | ||
1338 | void LLViewerImageList::updateImagesMediaStreams() | 871 | void 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 | ||
1407 | void 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 | |||
1424 | void LLViewerImageList::updateImagesUpdateStats() | 939 | void 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 | ||
1462 | void LLViewerImageList::decodeAllImages(F32 max_decode_time) | 954 | void 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!!!! | ||
1102 | LLPointer<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 |
1587 | S32 LLViewerImageList::getMaxVideoRamSetting(S32 max) | 1113 | S32 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 | ||
1158 | const 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 | |||
1166 | const S32 VIDEO_CARD_FRAMEBUFFER_MEM = 0xC00000; // 12MB | ||
1167 | |||
1632 | void LLViewerImageList::updateMaxResidentTexMem(S32 max, U32 fudge) | 1168 | void 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 | ||
1203 | void 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 | ||
1257 | void 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 |
1665 | void LLViewerImageList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data) | 1313 | void 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 | ||
1329 | const U32 SIXTEEN_MEG = 0x1000000; | ||
1330 | S32 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 | /////////////////////////////////////////////////////////////////////////////// | ||