aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerimagelist.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerimagelist.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llviewerimagelist.cpp')
-rw-r--r--linden/indra/newview/llviewerimagelist.cpp1676
1 files changed, 1676 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerimagelist.cpp b/linden/indra/newview/llviewerimagelist.cpp
new file mode 100644
index 0000000..20ca3bf
--- /dev/null
+++ b/linden/indra/newview/llviewerimagelist.cpp
@@ -0,0 +1,1676 @@
1/**
2 * @file llviewerimagelist.cpp
3 * @brief Object for managing the list of images within a region
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include <sys/stat.h>
31
32#include "llviewerimagelist.h"
33#include "imageids.h"
34#include "llgl.h" // fot gathering stats from GL
35#include "llimagegl.h"
36#include "llimagebmp.h"
37#include "llimagej2c.h"
38#include "llimagetga.h"
39#include "llimagejpeg.h"
40#include "llmediaengine.h"
41
42#include "llvfs.h"
43#include "llvfile.h"
44#include "llvfsthread.h"
45#include "message.h"
46
47#include "llagent.h"
48#include "llviewercontrol.h"
49#include "lltexturetable.h" // For looking up names from uuid's.
50#include "llviewerimage.h"
51#include "llviewerregion.h"
52#include "viewer.h"
53#include "llsys.h"
54#include "llpaneldisplay.h" // for LL_MAX_VRAM_INDEX
55
56void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL;
57
58const U32 SIXTEEN_MEG = 0x1000000;
59const F32 MAX_IMAGE_PRIORITY = 100000000.f;
60
61U32 LLViewerImageList::sTextureBits = 0;
62U32 LLViewerImageList::sTexturePackets = 0;
63
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;
94const 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
96const F32 RESEND_IMAGE_REQUEST_TIME = 15.f; // seconds
97
98LLViewerImageList gImageList;
99
100S32 LLViewerImageList::sNumImages = 0;
101LLStat LLViewerImageList::sNumImagesStat(32, TRUE);
102LLStat LLViewerImageList::sNumRawImagesStat(32, TRUE);
103LLStat LLViewerImageList::sGLTexMemStat(32, TRUE);
104LLStat LLViewerImageList::sGLBoundMemStat(32, TRUE);
105LLStat LLViewerImageList::sRawMemStat(32, TRUE);
106LLStat LLViewerImageList::sFormattedMemStat(32, TRUE);
107
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///////////////////////////////////////////////////////////////////////////////
125
126LLViewerImageList::LLViewerImageList()
127 : LLImageProviderInterface(),
128 mForceResetTextureStats(FALSE),
129 mUpdateStats(FALSE),
130 mMaxResidentTexMem(0),
131 mVideoMemorySetting(0),
132 mMovieImageHasMips(FALSE)
133{
134}
135
136void LLViewerImageList::init()
137{
138 sNumImages = 0;
139 mMaxResidentTexMem = 0;
140 mVideoMemorySetting = 0;
141
142 if (gNoRender)
143 {
144 // Don't initialize GL stuff if we're not rendering.
145 return;
146 }
147
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;
188
189 // Update how much texture RAM we're allowed to use.
190 updateMaxResidentTexMem();
191
192 mMovieImageHasMips = FALSE;
193}
194
195void LLViewerImageList::doPreloadImages()
196{
197 llinfos << "Preloading images..." << llendl;
198
199 // Set the "missing asset" image
200 LLViewerImage::sMissingAssetImagep = preloadImage("missing_asset.tga" , LLUUID::null, TRUE);
201
202 // Set the "white" image
203 LLViewerImage::sWhiteImagep = preloadImage("white.tga", LLUUID::null, TRUE);;
204
205 // Preload some images
206 preloadImage("button_anim_pause.tga", LLUUID::null, FALSE);
207 preloadImage("button_anim_pause_selected.tga", LLUUID::null, FALSE);
208 preloadImage("button_anim_play.tga", LLUUID::null, FALSE);
209 preloadImage("button_anim_play_selected.tga", LLUUID::null, FALSE);
210 preloadImage("button_anim_stop.tga", LLUUID::null, FALSE);
211 preloadImage("button_anim_stop_selected.tga", LLUUID::null, FALSE);
212 preloadImage("button_disabled_32x128.tga", LLUUID::null, FALSE);
213 preloadImage("button_enabled_32x128.tga", LLUUID::null, FALSE);
214 preloadImage("button_enabled_selected_32x128.tga", LLUUID::null, FALSE);
215 preloadImage("checkbox_disabled_false.tga", LLUUID::null, FALSE);
216 preloadImage("checkbox_disabled_true.tga", LLUUID::null, FALSE);
217 preloadImage("checkbox_enabled_false.tga", LLUUID::null, FALSE);
218 preloadImage("checkbox_enabled_true.tga", LLUUID::null, FALSE);
219 preloadImage("close_in_blue.tga", LLUUID::null, FALSE);
220 preloadImage("combobox_arrow.tga", LLUUID::null, FALSE);
221 preloadImage("crosshairs.tga", LLUUID::null, FALSE);
222 preloadImage("direction_arrow.tga", LLUUID::null, FALSE);
223 preloadImage("eyes.tga", LLUUID::null, TRUE);
224 preloadImage("foot_shadow.tga", LLUUID::null, TRUE);
225 preloadImage("hair.tga", LLUUID::null, TRUE);
226 preloadImage("icon_for_sale.tga", LLUUID::null, FALSE);
227 preloadImage("icon_popular.tga", LLUUID::null, FALSE);
228 preloadImage("icon_top_pick.tga", LLUUID::null, FALSE);
229 preloadImage("img_shot.tga", IMG_SHOT, TRUE);
230 preloadImage("img_smoke_poof.tga", IMG_SMOKE_POOF, TRUE);
231 preloadImage("inv_folder_animation.tga", LLUUID::null, FALSE);
232 preloadImage("inv_folder_bodypart.tga", LLUUID::null, FALSE);
233 preloadImage("inv_folder_callingcard.tga", LLUUID::null, FALSE);
234 preloadImage("inv_folder_clothing.tga", LLUUID::null, FALSE);
235 preloadImage("inv_folder_gesture.tga", LLUUID::null, FALSE);
236 preloadImage("inv_folder_landmark.tga", LLUUID::null, FALSE);
237 preloadImage("inv_folder_lostandfound.tga", LLUUID::null, FALSE);
238 preloadImage("inv_folder_notecard.tga", LLUUID::null, FALSE);
239 preloadImage("inv_folder_object.tga", LLUUID::null, FALSE);
240 preloadImage("inv_folder_plain_closed.tga", LLUUID::null, FALSE);
241 preloadImage("inv_folder_script.tga", LLUUID::null, FALSE);
242 preloadImage("inv_folder_snapshot.tga", LLUUID::null, FALSE);
243 preloadImage("inv_folder_sound.tga", LLUUID::null, FALSE);
244 preloadImage("inv_folder_texture.tga", LLUUID::null, FALSE);
245 preloadImage("inv_folder_trash.tga", LLUUID::null, FALSE);
246 preloadImage("inv_item_animation.tga", LLUUID::null, FALSE);
247 preloadImage("inv_item_bodypart.tga", LLUUID::null, FALSE);
248 preloadImage("inv_item_callingcard_offline.tga", LLUUID::null, FALSE);
249 preloadImage("inv_item_callingcard_online.tga", LLUUID::null, FALSE);
250 preloadImage("inv_item_eyes.tga", LLUUID::null, FALSE);
251 preloadImage("inv_item_gesture.tga", LLUUID::null, FALSE);
252 preloadImage("inv_item_gloves.tga", LLUUID::null, FALSE);
253 preloadImage("inv_item_hair.tga", LLUUID::null, FALSE);
254 preloadImage("inv_item_jacket.tga", LLUUID::null, FALSE);
255 preloadImage("inv_item_landmark.tga", LLUUID::null, FALSE);
256 preloadImage("inv_item_landmark_visited.tga", LLUUID::null, FALSE);
257 preloadImage("inv_item_notecard.tga", LLUUID::null, FALSE);
258 preloadImage("inv_item_object.tga", LLUUID::null, FALSE);
259 preloadImage("inv_item_pants.tga", LLUUID::null, FALSE);
260 preloadImage("inv_item_script.tga", LLUUID::null, FALSE);
261 preloadImage("inv_item_shape.tga", LLUUID::null, FALSE);
262 preloadImage("inv_item_shirt.tga", LLUUID::null, FALSE);
263 preloadImage("inv_item_shoes.tga", LLUUID::null, FALSE);
264 preloadImage("inv_item_skirt.tga", LLUUID::null, FALSE);
265 preloadImage("inv_item_snapshot.tga", LLUUID::null, FALSE);
266 preloadImage("inv_item_socks.tga", LLUUID::null, FALSE);
267 preloadImage("inv_item_sound.tga", LLUUID::null, FALSE);
268 preloadImage("inv_item_texture.tga", LLUUID::null, FALSE);
269 preloadImage("inv_item_underpants.tga", LLUUID::null, FALSE);
270 preloadImage("inv_item_undershirt.tga", LLUUID::null, FALSE);
271 preloadImage("legend.tga", LLUUID::null, FALSE);
272 preloadImage("map_avatar_16.tga", LLUUID::null, FALSE);
273 preloadImage("map_avatar_8.tga", LLUUID::null, FALSE);
274 preloadImage("map_avatar_you_8.tga", LLUUID::null, FALSE);
275 preloadImage("map_event.tga", LLUUID::null, FALSE);
276 preloadImage("map_event_mature.tga", LLUUID::null, FALSE);
277 preloadImage("map_home.tga", LLUUID::null, FALSE);
278 preloadImage("map_infohub.tga", LLUUID::null, FALSE);
279 preloadImage("map_telehub.tga", LLUUID::null, FALSE);
280 preloadImage("map_track_16.tga", LLUUID::null, FALSE);
281 preloadImage("minimize.tga", LLUUID::null, FALSE);
282 preloadImage("minimize_pressed.tga", LLUUID::null, FALSE);
283 preloadImage("noentrylines.tga", LLUUID::null, TRUE);
284 preloadImage("noentrypasslines.tga", LLUUID::null, TRUE);
285 preloadImage("notify_tip_icon.tga", LLUUID::null, FALSE);
286 preloadImage("object_cone.tga", LLUUID::null, FALSE);
287 preloadImage("object_cone_active.tga", LLUUID::null, FALSE);
288 preloadImage("object_cube.tga", LLUUID::null, FALSE);
289 preloadImage("object_cube_active.tga", LLUUID::null, FALSE);
290 preloadImage("object_cylinder.tga", LLUUID::null, FALSE);
291 preloadImage("object_cylinder_active.tga", LLUUID::null, FALSE);
292 preloadImage("object_grass.tga", LLUUID::null, FALSE);
293 preloadImage("object_grass_active.tga", LLUUID::null, FALSE);
294 preloadImage("object_hemi_cone.tga", LLUUID::null, FALSE);
295 preloadImage("object_hemi_cone_active.tga", LLUUID::null, FALSE);
296 preloadImage("object_hemi_cylinder.tga", LLUUID::null, FALSE);
297 preloadImage("object_hemi_cylinder_active.tga", LLUUID::null, FALSE);
298 preloadImage("object_hemi_sphere.tga", LLUUID::null, FALSE);
299 preloadImage("object_hemi_sphere_active.tga", LLUUID::null, FALSE);
300 preloadImage("object_prism.tga", LLUUID::null, FALSE);
301 preloadImage("object_prism_active.tga", LLUUID::null, FALSE);
302 preloadImage("object_pyramid.tga", LLUUID::null, FALSE);
303 preloadImage("object_pyramid_active.tga", LLUUID::null, FALSE);
304 preloadImage("object_ring.tga", LLUUID::null, FALSE);
305 preloadImage("object_ring_active.tga", LLUUID::null, FALSE);
306 preloadImage("object_sphere.tga", LLUUID::null, FALSE);
307 preloadImage("object_sphere_active.tga", LLUUID::null, FALSE);
308 preloadImage("object_tetrahedron.tga", LLUUID::null, FALSE);
309 preloadImage("object_tetrahedron_active.tga", LLUUID::null, FALSE);
310 preloadImage("object_torus.tga", LLUUID::null, FALSE);
311 preloadImage("object_torus_active.tga", LLUUID::null, FALSE);
312 preloadImage("object_tree.tga", LLUUID::null, FALSE);
313 preloadImage("object_tree_active.tga", LLUUID::null, FALSE);
314 preloadImage("object_tube.tga", LLUUID::null, FALSE);
315 preloadImage("object_tube_active.tga", LLUUID::null, FALSE);
316 preloadImage("pixiesmall.tga", LLUUID::null, TRUE);
317 preloadImage("radio_active_false.tga", LLUUID::null, FALSE);
318 preloadImage("radio_active_true.tga", LLUUID::null, FALSE);
319 preloadImage("radio_inactive_false.tga", LLUUID::null, FALSE);
320 preloadImage("radio_inactive_true.tga", LLUUID::null, FALSE);
321 preloadImage("resize_handle_bottom_right_blue.tga", LLUUID::null, FALSE);
322 preloadImage("rounded_square.tga", LLUUID::null, FALSE);
323 preloadImage("rounded_square_soft.tga", LLUUID::null, FALSE);
324 preloadImage("scrollbutton_down_in_blue.tga", LLUUID::null, FALSE);
325 preloadImage("scrollbutton_down_out_blue.tga", LLUUID::null, FALSE);
326 preloadImage("scrollbutton_left_in_blue.tga", LLUUID::null, FALSE);
327 preloadImage("scrollbutton_left_out_blue.tga", LLUUID::null, FALSE);
328 preloadImage("scrollbutton_right_in_blue.tga", LLUUID::null, FALSE);
329 preloadImage("scrollbutton_right_out_blue.tga", LLUUID::null, FALSE);
330 preloadImage("scrollbutton_up_in_blue.tga", LLUUID::null, FALSE);
331 preloadImage("scrollbutton_up_out_blue.tga", LLUUID::null, FALSE);
332 preloadImage("silhouette.tga", LLUUID::null, TRUE);
333 preloadImage("spin_down_in_blue.tga", LLUUID::null, FALSE);
334 preloadImage("spin_down_out_blue.tga", LLUUID::null, FALSE);
335 preloadImage("spin_up_in_blue.tga", LLUUID::null, FALSE);
336 preloadImage("spin_up_out_blue.tga", LLUUID::null, FALSE);
337 preloadImage("square_btn_32x128.tga", LLUUID::null, FALSE);
338 preloadImage("startup_logo.tga", LLUUID::null, FALSE);
339 preloadImage("status_build.tga", LLUUID::null, FALSE);
340 preloadImage("status_buy_currency.tga", LLUUID::null, FALSE);
341 preloadImage("status_buy_currency_pressed.tga", LLUUID::null, FALSE);
342 preloadImage("status_buy_land.tga", LLUUID::null, FALSE);
343 preloadImage("status_buy_land_pressed.tga", LLUUID::null, FALSE);
344 preloadImage("status_fly.tga", LLUUID::null, FALSE);
345 preloadImage("status_health.tga", LLUUID::null, FALSE);
346 preloadImage("status_scripts.tga", LLUUID::null, FALSE);
347 preloadImage("tab_bottom_blue.tga", LLUUID::null, FALSE);
348 preloadImage("tab_bottom_selected_blue.tga", LLUUID::null, FALSE);
349 preloadImage("tab_top_blue.tga", LLUUID::null, FALSE);
350 preloadImage("tab_top_selected_blue.tga", LLUUID::null, FALSE);
351 preloadImage("tool_dozer.tga", LLUUID::null, FALSE);
352 preloadImage("tool_dozer_active.tga", LLUUID::null, FALSE);
353 preloadImage("tool_zoom.tga", LLUUID::null, FALSE);
354 preloadImage("tool_zoom_active.tga", LLUUID::null, FALSE);
355 preloadImage("white.tga", LLUUID::null, TRUE);
356}
357
358///////////////////////////////////////////////////////////////////////////////
359
360LLViewerImageList::~LLViewerImageList()
361{
362 llassert(mIRCallbackData.empty());
363}
364
365void LLViewerImageList::shutdown()
366{
367 // Clean up potential callback data
368 // mIRCallbackData is now stl and will clean itself up
369
370 //
371 // Clean up "loaded" callbacks.
372 //
373 mCallbackList.clear();
374
375 // Clean up preloaded images
376 mPreloadedImages.clear();
377
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
390 mLoadingStreamList.clear();
391
392 mUUIDMap.clear();
393
394 // This stuff is global!
395 LLViewerImage::sDefaultImagep = NULL;
396
397 mImageList.clear();
398}
399
400void LLViewerImageList::dump()
401{
402 llinfos << "LLViewerImageList::dump()" << llendl;
403 for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it)
404 {
405 LLViewerImage* image = *it;
406
407 llinfos << "priority " << image->getDecodePriority()
408 << " boost " << image->getBoostLevel()
409 << " size " << image->getWidth() << "x" << image->getHeight()
410 << " discard " << image->getDiscardLevel()
411 << " desired " << image->getDesiredDiscardLevel()
412 << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture"
413 << llendl;
414 }
415}
416
417void LLViewerImageList::destroyGL(BOOL save_state)
418{
419 LLImageGL::destroyGL(save_state);
420}
421
422void LLViewerImageList::restoreGL()
423{
424 LLImageGL::restoreGL();
425}
426
427/* Vertical tab container button image IDs
428Seem to not decode when running app in debug.
429
430const LLUUID BAD_IMG_ONE("1097dcb3-aef9-8152-f471-431d840ea89e");
431const LLUUID BAD_IMG_TWO("bea77041-5835-1661-f298-47e2d32b7a70");
432*/
433
434LLImageGL* LLViewerImageList::getUIImageByID(const LLUUID& image_id, BOOL clamped)
435{
436 LLViewerImage* imagep = getImage(image_id, MIPMAP_FALSE, TRUE);
437 // force a high resolution decode for all UI images (pulled this from LLTextEditor)
438 // this might not make any difference
439 imagep->setBoostLevel(LLViewerImage::BOOST_UI);
440 LLViewerImage::bindTexture(imagep);
441 imagep->setClamp(clamped, clamped);
442 imagep->unbindTexture(0, GL_TEXTURE_2D);
443
444 return (LLImageGL*)imagep;
445}
446
447///////////////////////////////////////////////////////////////////////////////
448
449LLViewerImage* LLViewerImageList::preloadImage(const LLString& filename, const LLUUID &image_set_id, BOOL use_mips)
450{
451 LLViewerImage* image = getImage(filename, image_set_id, use_mips, TRUE);
452 image->dontDiscard();
453 mPreloadedImages.push_back(image);
454 return image;
455}
456
457///////////////////////////////////////////////////////////////////////////////
458
459LLViewerImage * LLViewerImageList::getImage(const LLString& filename,
460 const LLUUID &image_set_id,
461 BOOL usemipmaps,
462 BOOL level_immediate)
463{
464 return getImageFromFile(filename, image_set_id, usemipmaps, level_immediate, 0, 0);
465}
466
467LLViewerImage * LLViewerImageList::getImageFromFile(const LLString& filename,
468 const LLUUID &image_set_id,
469 BOOL usemipmaps,
470 BOOL level_immediate,
471 LLGLint internal_format,
472 LLGLenum primary_format)
473{
474 if (gNoRender)
475 {
476 // Never mind that this ignores image_set_id;
477 // getImage() will handle that later.
478 return getImage(IMG_DEFAULT, TRUE, TRUE);
479 }
480
481 // Try to load an image from the skins directory.
482 // Fall back to loading from the VFS if not found.
483
484 // First verify that the image exists in gViewerArt
485 LLUUID image_id = LLUUID( gViewerArt.getString(filename.c_str()) );
486 if (image_id.isNull())
487 {
488 llwarns << "Unable to find inage " << filename << " in gViewerArt" << llendl;
489 if (image_set_id.notNull())
490 {
491 // We *know* that missing_asset.tga exists,
492 // but for paranoia's sake and to avoid infinite recursion, check anyway
493 image_id = LLUUID(gViewerArt.getString("missing_asset.tga"));
494 if (image_id.isNull())
495 {
496 llerrs << "Missing missing_asset.tga!" << llendl;
497 }
498 return getImageFromFile(LLString("missing_asset.tga"), image_set_id,
499 usemipmaps, level_immediate,
500 internal_format, primary_format);
501 }
502 else
503 {
504 return (getImage(IMG_DEFAULT, TRUE, TRUE));
505 }
506 }
507
508 // Now that we have verified that filename exists, load it and assign it to
509 // the filename's UUID, or image_set_id if non null.
510 if (image_set_id.notNull())
511 {
512 image_id = image_set_id;
513 }
514
515 // First see if we already have this image loaded.
516 LLPointer<LLViewerImage> imagep = hasImage(image_id);
517
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
568 return imagep;
569}
570
571LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
572 BOOL usemipmaps,
573 BOOL level_immediate)
574{
575 return getImageFromUUID(image_id, usemipmaps, level_immediate, 0, 0, LLHost());
576}
577
578LLViewerImage* LLViewerImageList::getImageFromUUID(const LLUUID &image_id,
579 BOOL usemipmaps,
580 BOOL level_immediate,
581 LLGLint internal_format,
582 LLGLenum primary_format,
583 LLHost request_from_host)
584{
585 // Return the image with ID image_id
586 // If the image is not found, creates new image and
587 // enqueues a request for transmission
588
589 if ((&image_id == NULL) || image_id.isNull())
590 {
591 return (getImage(IMG_DEFAULT, TRUE, TRUE));
592 }
593
594 LLPointer<LLViewerImage> imagep = hasImage(image_id);
595
596 if (imagep.isNull())
597 {
598 imagep = new LLViewerImage(image_id, usemipmaps);
599 // Might want to request from host other than where the agent is. JC
600 imagep->setTargetHost(request_from_host);
601
602 if (internal_format && primary_format)
603 {
604 imagep->setExplicitFormat(internal_format, primary_format);
605 }
606
607 addImage(imagep);
608
609 if (level_immediate)
610 {
611 imagep->dontDiscard();
612 }
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 }
647 }
648
649 return imagep;
650}
651
652LLViewerImage *LLViewerImageList::hasImage(const LLUUID &image_id)
653{
654 uuid_map_t::iterator iter = mUUIDMap.find(image_id);
655 if(iter == mUUIDMap.end())
656 return NULL;
657 return iter->second;
658}
659
660void LLViewerImageList::addImageToList(LLViewerImage *image)
661{
662 llassert(image);
663 if (image->mInImageList)
664 {
665 llerrs << "LLViewerImageList::addImageToList - Image already in list" << llendl;
666 }
667 llverify((mImageList.insert(image)).second == true);
668 image->mInImageList = TRUE;
669}
670
671void LLViewerImageList::removeImageFromList(LLViewerImage *image)
672{
673 llassert(image);
674 if (!image->mInImageList)
675 {
676 llerrs << "LLViewerImageList::removeImageFromList - Image not in list" << llendl;
677 }
678 llverify(mImageList.erase(image) == 1);
679 image->mInImageList = FALSE;
680}
681
682void LLViewerImageList::addImage(LLViewerImage *new_image)
683{
684 if (!new_image)
685 {
686 llwarning("No image to add to image list", 0);
687 return;
688 }
689 LLUUID image_id = new_image->getID();
690
691 LLViewerImage *image = hasImage(image_id);
692 if (image)
693 {
694 llerrs << "Image with ID " << image_id << " already in list" << llendl;
695 }
696 sNumImages++;
697
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);
706 mUUIDMap[image_id] = new_image;
707}
708
709
710void LLViewerImageList::deleteImage(LLViewerImage *image)
711{
712 if( image)
713 {
714 if (image->hasCallbacks())
715 {
716 mCallbackList.erase((LLViewerImage*)image);
717 }
718 llverify(mUUIDMap.erase(image->getID()) == 1);
719 sNumImages--;
720 removeImageFromList(image);
721 }
722}
723
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///////////////////////////////////////////////////////////////////////////////
754
755void LLViewerImageList::updateMovieImage(const LLUUID& uuid, BOOL active)
756{
757 // IF the media image hasn't changed, do nothing
758 if (mMovieImageUUID == uuid)
759 {
760 return;
761 }
762 // If we have changed media uuid, restore the old one
763 if (!mMovieImageUUID.isNull())
764 {
765 LLViewerImage* oldImage = getImage( mMovieImageUUID );
766 if (oldImage)
767 {
768 oldImage->reinit(mMovieImageHasMips);
769 oldImage->mIsMediaTexture = FALSE;
770 }
771 mMovieImageUUID.setNull();
772 }
773 // If the movie is playing, set the new media image
774 if (active && !uuid.isNull())
775 {
776 LLViewerImage* viewerImage = getImage( uuid );
777 if( viewerImage )
778 {
779 mMovieImageUUID = uuid;
780 // Can't use mipmaps for movies because they don't update the full image
781 mMovieImageHasMips = viewerImage->getUseMipMaps();
782 viewerImage->reinit(FALSE);
783 viewerImage->mIsMediaTexture = TRUE;
784 }
785 }
786}
787
788void LLViewerImageList::updateImages(const F32 decode_time_max)
789{
790 sNumImagesStat.addValue(sNumImages);
791 sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
792 sGLTexMemStat.addValue(LLImageGL::sGlobalTextureMemory/(1024.f*1024.f));
793 sGLBoundMemStat.addValue(LLImageGL::sBoundTextureMemory/(1024.f*1024.f));
794 sRawMemStat.addValue(LLImageRaw::sGlobalRawMemory/(1024.f*1024.f));
795 sFormattedMemStat.addValue(LLImageFormatted::sGlobalFormattedMemory/(1024.f*1024.f));
796
797 updateImagesDecodePriorities();
798 updateImagesSendRequests();
799
800 if (gGLManager.mIsDisabled)
801 {
802 // We don't want to run this part of the texture system while we don't have
803 // a GL context - we COULD probably do some of it, but that's tricky - djs 10/29/03
804 return;
805 }
806
807 updateImagesDecodeTextures(decode_time_max);
808 updateImagesMediaStreams();
809 updateImagesPollVFS();
810 updateImagesUpdateStats();
811}
812
813
814void LLViewerImageList::updateImagesDecodePriorities()
815{
816 // Update the decode priority for N images each frame
817 {
818 const size_t max_update_count = 256;
819 S32 update_counter = llmin(max_update_count, mUUIDMap.size());
820 uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID);
821 while(update_counter > 0)
822 {
823 if (iter == mUUIDMap.end())
824 {
825 iter = mUUIDMap.begin();
826 }
827 mLastUpdateUUID = iter->first;
828 LLPointer<LLViewerImage> imagep = iter->second;
829 imagep->processTextureStats();
830 F32 old_priority = imagep->getDecodePriority();
831 F32 decode_priority = imagep->calcDecodePriority();
832 // Ignore < 20% difference
833 if ((decode_priority < old_priority * .8f || decode_priority > old_priority * 1.25f))
834 {
835 removeImageFromList(imagep);
836 imagep->setDecodePriority(decode_priority);
837 addImageToList(imagep);
838 }
839 iter++;
840 update_counter--;
841 }
842 }
843}
844
845static U8 get_image_type(LLViewerImage* imagep, LLHost target_host)
846{
847 // Having a target host implies this is a baked image. I don't
848 // believe that boost level has been set at this point. JC
849 U8 type_from_host = (target_host.isOk()
850 ? LLImageBase::TYPE_AVATAR_BAKE
851 : LLImageBase::TYPE_NORMAL);
852 S32 boost_level = imagep->getBoostLevel();
853 U8 type_from_boost = ( (boost_level == LLViewerImage::BOOST_AVATAR_BAKED
854 || boost_level == LLViewerImage::BOOST_AVATAR_BAKED_SELF)
855 ? LLImageBase::TYPE_AVATAR_BAKE
856 : LLImageBase::TYPE_NORMAL);
857 if (type_from_host == LLImageBase::TYPE_NORMAL
858 && type_from_boost == LLImageBase::TYPE_AVATAR_BAKE)
859 {
860 llwarns << "TAT: get_image_type() type_from_host doesn't match type_from_boost"
861 << " host " << target_host
862 << " boost " << imagep->getBoostLevel()
863 << " imageid " << imagep->getID()
864 << llendl;
865 imagep->dump();
866 }
867 return type_from_host;
868}
869
870void LLViewerImageList::updateImagesSendRequests()
871{
872 // Send requests for images based on priority.
873 {
874 S32 request_count = 0;
875 S32 request_packets_sent = 0;
876 S32 update_count = 0;
877
878 callback_data_t *requested_images = NULL;
879
880 // Baked texture images may live on a separate host. JC
881 std::vector< LLPointer<LLViewerImage> > images_on_other_hosts;
882 LLHost agent_host = gAgent.getRegionHost();
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
1052 requested_images = NULL;
1053 request_count = 0;
1054 ++request_packets_sent;
1055 }
1056 }
1057 }
1058
1059 if (request_count != 0)
1060 {
1061 // fill in the unused requested_images w/ NULL
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 {
1070 // llinfos << "TAT: images_on_other_hosts " << images_on_other_hosts.size() << llendl;
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 }
1150 }
1151}
1152
1153
1154
1155void LLViewerImageList::updateImagesDecodeTextures(F32 decode_time_max)
1156{
1157 if (gNoRender) return;
1158
1159 LLTimer image_op_timer;
1160
1161 BOOL done_one = FALSE;
1162 image_op_timer.reset();
1163
1164 S32 create_count = 0;
1165
1166 // added by IW to help track down a bug
1167 stop_glerror();
1168
1169 //
1170 // Create GL textures for all textures that need them (images which have been
1171 // decoded, but haven't been pushed into GL).
1172 //
1173 {
1174 LLFastTimer t(LLFastTimer::FTM_IMAGE_CREATE);
1175
1176 for (image_list_t::iterator iter = mImageList.begin();
1177 iter != mImageList.end(); )
1178 {
1179 LLPointer<LLViewerImage> imagep = *iter++;
1180 if (imagep->getNeedsCreateTexture())
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 {
1236 // Reprioritize this image
1237 if (mCurrentDecodeImagep->mInImageList)
1238 {
1239 removeImageFromList(mCurrentDecodeImagep);
1240 mCurrentDecodeImagep->setDecodePriority();
1241 addImageToList(mCurrentDecodeImagep);
1242 }
1243 mCurrentDecodeImagep = NULL;
1244 }
1245
1246 //
1247 // At this point, we're going to check out the status of anything that's
1248 // on our callback list. Instead of calling the callback lists from a
1249 // billion different places, we're ONLY going to handle them here.
1250 //
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
1270 //
1271 // Decode as many images as we can at this point.
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 {
1277 LLFastTimer t(LLFastTimer::FTM_IMAGE_DECODE);
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 }
1336}
1337
1338void LLViewerImageList::updateImagesMediaStreams()
1339{
1340 if (gNoRender) return;
1341
1342 // update media stream if required
1343 LLMediaEngine* media_engine = LLMediaEngine::getInstance();
1344 if (media_engine)
1345 {
1346 if ( media_engine->update() )
1347 {
1348 LLUUID media_uuid = media_engine->getImageUUID();
1349 updateMovieImage(media_uuid, TRUE);
1350 if (!media_uuid.isNull())
1351 {
1352 LLViewerImage* viewerImage = getImage( media_uuid );
1353 if( viewerImage )
1354 {
1355 LLMediaBase* renderer = media_engine->getMediaRenderer();
1356 if ((renderer->getTextureWidth() != viewerImage->getWidth()) ||
1357 (renderer->getTextureHeight() != viewerImage->getHeight()) ||
1358 (renderer->getTextureDepth() != viewerImage->getComponents()) ||
1359 (viewerImage->getHasGLTexture() == FALSE))
1360 {
1361 llassert(!viewerImage->getUseMipMaps());
1362
1363 // destroy existing GL image
1364 viewerImage->destroyGLTexture();
1365
1366 // set new size
1367 viewerImage->setSize( renderer->getTextureWidth(),
1368 renderer->getTextureHeight(),
1369 renderer->getTextureDepth() );
1370
1371 LLPointer<LLImageRaw> raw = new LLImageRaw(renderer->getTextureWidth(),
1372 renderer->getTextureHeight(),
1373 renderer->getTextureDepth());
1374 raw->clear(0x7f,0x7f,0x7f,0xff);
1375 viewerImage->createGLTexture(0, raw);
1376 }
1377
1378 // Set the explicit format the instance wants
1379 viewerImage->setExplicitFormat(renderer->getTextureFormatInternal(),
1380 renderer->getTextureFormatPrimary(),
1381 renderer->getTextureFormatType(),
1382 renderer->getTextureFormatSwapBytes());
1383
1384 LLImageRaw* rawImage = media_engine->getImageRaw();
1385
1386 if ( rawImage )
1387 {
1388 ((LLImageGL*)viewerImage)->setSubImage(rawImage, 0, 0,
1389 renderer->getMediaWidth(),
1390 renderer->getMediaHeight());
1391 }
1392 }
1393 else
1394 {
1395 llwarns << "MediaEngine update unable to get viewer image for GL texture" << llendl;
1396 }
1397 }
1398 }
1399 else
1400 {
1401 LLUUID media_uuid = media_engine->getImageUUID();
1402 updateMovieImage(media_uuid, FALSE);
1403 }
1404 }
1405}
1406
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()
1425{
1426 if (mUpdateStats)
1427 {
1428 for (image_list_t::iterator iter = mImageList.begin();
1429 iter != mImageList.end(); )
1430 {
1431 LLViewerImage* imagep = *iter++;
1432 imagep->resetTextureStats(mForceResetTextureStats);
1433 }
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;
1458 mForceResetTextureStats = FALSE;
1459 }
1460}
1461
1462void LLViewerImageList::decodeAllImages(F32 max_decode_time)
1463{
1464 LLTimer timer;
1465 if(!gNoRender)
1466 {
1467 for (image_list_t::iterator iter = mImageList.begin();
1468 iter != mImageList.end(); )
1469 {
1470 LLViewerImage* imagep = *iter++;
1471 if (imagep->needsDecode())
1472 {
1473 imagep->decodeImage(0.f); // LLViewerImageList::decodeAllImages
1474 }
1475 if (max_decode_time > 0.0f && timer.getElapsedTimeF32() > max_decode_time)
1476 {
1477 break;
1478 }
1479 }
1480
1481 for (image_list_t::iterator iter = mImageList.begin();
1482 iter != mImageList.end(); )
1483 {
1484 LLViewerImage* imagep = *iter++;
1485 if (imagep->getNeedsCreateTexture())
1486 {
1487 imagep->createTexture();
1488 }
1489 }
1490 }
1491 if (timer.getElapsedTimeF32() > .5f) // seconds
1492 {
1493 llinfos << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. " << llendl;
1494 }
1495}
1496
1497
1498BOOL LLViewerImageList::createUploadFile(const LLString& filename,
1499 const LLString& out_filename,
1500 const U8 codec)
1501{
1502 // First, load the image.
1503 LLPointer<LLImageRaw> raw_image = new LLImageRaw;
1504
1505 switch (codec)
1506 {
1507 case IMG_CODEC_BMP:
1508 {
1509 LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
1510
1511 if (!bmp_image->load(filename))
1512 {
1513 return FALSE;
1514 }
1515
1516 if (!bmp_image->decode(raw_image))
1517 {
1518 return FALSE;
1519 }
1520 }
1521 break;
1522 case IMG_CODEC_TGA:
1523 {
1524 LLPointer<LLImageTGA> tga_image = new LLImageTGA;
1525
1526 if (!tga_image->load(filename))
1527 {
1528 return FALSE;
1529 }
1530
1531 if (!tga_image->decode(raw_image))
1532 {
1533 return FALSE;
1534 }
1535
1536 if( (tga_image->getComponents() != 3) &&
1537 (tga_image->getComponents() != 4) )
1538 {
1539 tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." );
1540 return FALSE;
1541 }
1542 }
1543 break;
1544 case IMG_CODEC_JPEG:
1545 {
1546 LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG;
1547
1548 if (!jpeg_image->load(filename))
1549 {
1550 return FALSE;
1551 }
1552
1553 if (!jpeg_image->decode(raw_image))
1554 {
1555 return FALSE;
1556 }
1557 }
1558 break;
1559 default:
1560 return FALSE;
1561 }
1562
1563 raw_image->biasedScaleToPowerOfTwo(LLViewerImage::MAX_IMAGE_SIZE_DEFAULT);
1564
1565 LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C;
1566
1567 compressedImage->setRate(0.f);
1568 compressedImage->encode(raw_image);
1569 if( !compressedImage->save(out_filename) )
1570 {
1571 llinfos << "Couldn't create output file " << out_filename << llendl;
1572 return FALSE;
1573 }
1574
1575 // test to see if the encode and save worked.
1576 LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
1577 if( !integrity_test->loadAndValidate( out_filename ) )
1578 {
1579 llinfos << "Image: " << out_filename << " is corrupt." << llendl;
1580 return FALSE;
1581 }
1582
1583 return TRUE;
1584}
1585
1586//static
1587S32 LLViewerImageList::getMaxVideoRamSetting(S32 max)
1588{
1589 const U32 vram_settings[] = { 16, 32, 64, 128, 256, 512 };
1590
1591 U32 max_vram;
1592 if (gGLManager.mVRAM != 0)
1593 {
1594 max_vram = (llmax(gGLManager.mVRAM,16)) << 20;
1595 }
1596 else
1597 {
1598 if (max == -2) // max recommended setting
1599 {
1600 max_vram = 128 << 20;
1601 }
1602 else
1603 {
1604 max_vram = 512 << 20;
1605 }
1606 llwarns << "VRAM amount not detected, defaulting to " << max_vram/(double)(1<<20) << " MB" << llendl;
1607 }
1608 U32 system_ram = gSysMemory.getPhysicalMemory();
1609 llinfos << "*** DETECTED " << system_ram/(double)(1<<20) << " MB of system memory." << llendl; // TomY TESTING DNCI
1610 if (max == -2)
1611 {
1612 max_vram = llmin(max_vram, (U32)(system_ram/2)); // max recommended setting
1613 }
1614 else
1615 {
1616 max_vram = llmin(max_vram, (U32)((F32)system_ram/1.5f));
1617 }
1618 S32 idx;
1619 for (idx=0; idx<=5; idx++)
1620 {
1621 if (idx == max)
1622 break;
1623 if ((vram_settings[idx] << 20) > max_vram)
1624 {
1625 idx--;
1626 break;
1627 }
1628 }
1629 return idx;
1630}
1631
1632void LLViewerImageList::updateMaxResidentTexMem(S32 max, U32 fudge)
1633{
1634 // Initialize the image pipeline VRAM settings
1635 S32 cur_setting = gSavedSettings.getS32("GraphicsCardMemorySetting");
1636 S32 max_setting = getMaxVideoRamSetting(max);
1637 if (max >= 0 && max != cur_setting)
1638 {
1639 S32 default_setting = getMaxVideoRamSetting(-2); // recommended default
1640 if (cur_setting >= 0 || max_setting != default_setting)
1641 {
1642 gSavedSettings.setS32("GraphicsCardMemorySetting", max_setting);
1643 return; //listener will reenter this function
1644 }
1645 cur_setting = max_setting; // max_setting <= max
1646 }
1647 else if (cur_setting < 0)
1648 {
1649 S32 default_setting = getMaxVideoRamSetting(-2); // recommended default
1650 cur_setting = default_setting;
1651 }
1652 mVideoMemorySetting = cur_setting;
1653 // TODO: set available resident texture mem based on use by other subsystems
1654 // currently 12MB assumed...
1655
1656 mMaxResidentTexMem = VIDEO_CARD_MEM_SIZES[cur_setting] - 0xC00000 - fudge; // - 12MB
1657 mMaxResidentTexMem -= mMaxResidentTexMem/8;
1658
1659 llinfos << "Graphics Card memory set to " << (VIDEO_CARD_MEM_SIZES[cur_setting]>>20)
1660 << " MB" << llendl;
1661}
1662
1663// We've been that the asset server does not contain the requested image id.
1664// static
1665void LLViewerImageList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data)
1666{
1667 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1668 LLUUID image_id;
1669 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id);
1670
1671 LLViewerImage* image = gImageList.hasImage( image_id );
1672 if( image )
1673 {
1674 image->setIsMissingAsset( TRUE );
1675 }
1676}