aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llimage/llimage.cpp38
-rw-r--r--linden/indra/llimage/llimage.h8
-rw-r--r--linden/indra/llimage/llimagedxt.cpp19
-rw-r--r--linden/indra/llimage/llimagej2c.cpp5
-rw-r--r--linden/indra/llimage/llimagejpeg.cpp9
-rw-r--r--linden/indra/llimage/llimageworker.cpp202
-rw-r--r--linden/indra/llimage/llimageworker.h97
-rw-r--r--linden/indra/llrender/llcubemap.cpp4
-rw-r--r--linden/indra/llrender/llimagegl.cpp273
-rw-r--r--linden/indra/llrender/llimagegl.h82
-rw-r--r--linden/indra/llrender/llrender.cpp20
-rw-r--r--linden/indra/llrender/llrender.h2
-rw-r--r--linden/indra/llrender/llrendertarget.cpp4
-rw-r--r--linden/indra/newview/CMakeLists.txt8
-rw-r--r--linden/indra/newview/app_settings/settings.xml44
-rw-r--r--linden/indra/newview/llappviewer.cpp17
-rw-r--r--linden/indra/newview/llappviewer.h6
-rw-r--r--linden/indra/newview/llassetuploadresponders.cpp8
-rw-r--r--linden/indra/newview/llassetuploadresponders.h1
-rw-r--r--linden/indra/newview/lldrawable.cpp8
-rw-r--r--linden/indra/newview/lldrawable.h4
-rw-r--r--linden/indra/newview/lldrawpool.cpp5
-rw-r--r--linden/indra/newview/lldrawpoolalpha.cpp4
-rw-r--r--linden/indra/newview/lldrawpoolbump.cpp14
-rw-r--r--linden/indra/newview/lldrawpoolterrain.cpp4
-rw-r--r--linden/indra/newview/lldrawpooltree.cpp2
-rw-r--r--linden/indra/newview/lldynamictexture.cpp2
-rw-r--r--linden/indra/newview/llface.cpp193
-rw-r--r--linden/indra/newview/llface.h21
-rw-r--r--linden/indra/newview/llfloaterassetbrowser.cpp2
-rw-r--r--linden/indra/newview/llfloaterreporter.cpp4
-rw-r--r--linden/indra/newview/llpreviewtexture.cpp8
-rw-r--r--linden/indra/newview/llstartup.cpp3
-rw-r--r--linden/indra/newview/lltexlayer.cpp29
-rw-r--r--linden/indra/newview/lltexturecache.cpp1268
-rw-r--r--linden/indra/newview/lltexturecache.h68
-rw-r--r--linden/indra/newview/lltexturectrl.cpp8
-rw-r--r--linden/indra/newview/lltexturefetch.cpp1058
-rw-r--r--linden/indra/newview/lltexturefetch.h37
-rw-r--r--linden/indra/newview/lltextureinfo.cpp290
-rw-r--r--linden/indra/newview/lltextureinfo.h80
-rw-r--r--linden/indra/newview/lltextureinfodetails.cpp40
-rw-r--r--linden/indra/newview/lltextureinfodetails.h58
-rw-r--r--linden/indra/newview/lltexturestats.cpp61
-rw-r--r--linden/indra/newview/lltexturestats.h41
-rw-r--r--linden/indra/newview/lltexturestatsuploader.cpp59
-rw-r--r--linden/indra/newview/lltexturestatsuploader.h48
-rw-r--r--linden/indra/newview/lltextureview.cpp11
-rw-r--r--linden/indra/newview/llviewercamera.cpp20
-rw-r--r--linden/indra/newview/llviewercamera.h14
-rw-r--r--linden/indra/newview/llviewercontrol.cpp9
-rw-r--r--linden/indra/newview/llviewerimage.cpp700
-rw-r--r--linden/indra/newview/llviewerimage.h130
-rw-r--r--linden/indra/newview/llviewerimagelist.cpp143
-rw-r--r--linden/indra/newview/llviewerimagelist.h12
-rw-r--r--linden/indra/newview/llviewermessage.cpp1
-rw-r--r--linden/indra/newview/llviewerobject.cpp6
-rw-r--r--linden/indra/newview/llviewerobject.h2
-rw-r--r--linden/indra/newview/llviewerobjectlist.cpp2
-rw-r--r--linden/indra/newview/llviewerparceloverlay.cpp2
-rw-r--r--linden/indra/newview/llviewerregion.cpp4
-rw-r--r--linden/indra/newview/llviewerwindow.cpp2
-rw-r--r--linden/indra/newview/llvlcomposition.cpp12
-rw-r--r--linden/indra/newview/llvoavatar.cpp79
-rw-r--r--linden/indra/newview/llvoavatar.h2
-rw-r--r--linden/indra/newview/llvoclouds.cpp4
-rw-r--r--linden/indra/newview/llvoclouds.h2
-rw-r--r--linden/indra/newview/llvograss.cpp2
-rw-r--r--linden/indra/newview/llvograss.h2
-rw-r--r--linden/indra/newview/llvoground.cpp2
-rw-r--r--linden/indra/newview/llvoground.h2
-rw-r--r--linden/indra/newview/llvopartgroup.cpp2
-rw-r--r--linden/indra/newview/llvopartgroup.h2
-rw-r--r--linden/indra/newview/llvosky.cpp4
-rw-r--r--linden/indra/newview/llvosky.h2
-rw-r--r--linden/indra/newview/llvosurfacepatch.cpp2
-rw-r--r--linden/indra/newview/llvosurfacepatch.h2
-rw-r--r--linden/indra/newview/llvotextbubble.cpp2
-rw-r--r--linden/indra/newview/llvotextbubble.h2
-rw-r--r--linden/indra/newview/llvotree.cpp2
-rw-r--r--linden/indra/newview/llvotree.h2
-rw-r--r--linden/indra/newview/llvotreenew.h2
-rw-r--r--linden/indra/newview/llvovolume.cpp199
-rw-r--r--linden/indra/newview/llvovolume.h6
-rw-r--r--linden/indra/newview/llvowater.cpp2
-rw-r--r--linden/indra/newview/llvowater.h2
-rw-r--r--linden/indra/newview/llworldmapview.cpp6
-rw-r--r--linden/indra/newview/primbackup.cpp4
88 files changed, 3836 insertions, 1838 deletions
diff --git a/linden/indra/llimage/llimage.cpp b/linden/indra/llimage/llimage.cpp
index 4b0076e..32891e7 100644
--- a/linden/indra/llimage/llimage.cpp
+++ b/linden/indra/llimage/llimage.cpp
@@ -55,13 +55,9 @@ std::string LLImage::sLastErrorMessage;
55LLMutex* LLImage::sMutex = NULL; 55LLMutex* LLImage::sMutex = NULL;
56 56
57//static 57//static
58void LLImage::initClass(LLWorkerThread* workerthread) 58void LLImage::initClass()
59{ 59{
60 sMutex = new LLMutex(NULL); 60 sMutex = new LLMutex(NULL);
61 if (workerthread)
62 {
63 LLImageWorker::initImageWorker(workerthread);
64 }
65 LLImageJ2C::openDSO(); 61 LLImageJ2C::openDSO();
66} 62}
67 63
@@ -69,7 +65,6 @@ void LLImage::initClass(LLWorkerThread* workerthread)
69void LLImage::cleanupClass() 65void LLImage::cleanupClass()
70{ 66{
71 LLImageJ2C::closeDSO(); 67 LLImageJ2C::closeDSO();
72 LLImageWorker::cleanupImageWorker();
73 delete sMutex; 68 delete sMutex;
74 sMutex = NULL; 69 sMutex = NULL;
75} 70}
@@ -1242,25 +1237,28 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
1242 ifs.read ((char*)buffer, length); /* Flawfinder: ignore */ 1237 ifs.read ((char*)buffer, length); /* Flawfinder: ignore */
1243 ifs.close(); 1238 ifs.close();
1244 1239
1245 image->updateData(); 1240 BOOL success;
1246 1241
1247 if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C) 1242 success = image->updateData();
1243 if (success)
1248 { 1244 {
1249 S32 width = image->getWidth(); 1245 if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C)
1250 S32 height = image->getHeight();
1251 S32 discard_level = 0;
1252 while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL)
1253 { 1246 {
1254 width >>= 1; 1247 S32 width = image->getWidth();
1255 height >>= 1; 1248 S32 height = image->getHeight();
1256 discard_level++; 1249 S32 discard_level = 0;
1250 while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL)
1251 {
1252 width >>= 1;
1253 height >>= 1;
1254 discard_level++;
1255 }
1256 ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level);
1257 } 1257 }
1258 ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level); 1258 success = image->decode(this, 100000.0f);
1259 } 1259 }
1260
1261 BOOL success = image->decode(this, 100000.0f);
1262 image = NULL; // deletes image
1263 1260
1261 image = NULL; // deletes image
1264 if (!success) 1262 if (!success)
1265 { 1263 {
1266 deleteData(); 1264 deleteData();
diff --git a/linden/indra/llimage/llimage.h b/linden/indra/llimage/llimage.h
index bd609b6..be2eb08 100644
--- a/linden/indra/llimage/llimage.h
+++ b/linden/indra/llimage/llimage.h
@@ -49,7 +49,8 @@ const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE;
49const S32 MAX_IMAGE_COMPONENTS = 8; 49const S32 MAX_IMAGE_COMPONENTS = 8;
50const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; 50const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS;
51 51
52// Note! These CANNOT be changed without invalidating the viewer VFS files, I think? 52// Note! These CANNOT be changed without modifying simulator code
53// *TODO: change both to 1024 when SIM texture fetching is deprecated
53const S32 FIRST_PACKET_SIZE = 600; 54const S32 FIRST_PACKET_SIZE = 600;
54const S32 MAX_IMG_PACKET_SIZE = 1000; 55const S32 MAX_IMG_PACKET_SIZE = 1000;
55 56
@@ -60,7 +61,6 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;
60class LLImageFormatted; 61class LLImageFormatted;
61class LLImageRaw; 62class LLImageRaw;
62class LLColor4U; 63class LLColor4U;
63class LLWorkerThread;
64 64
65typedef enum e_image_codec 65typedef enum e_image_codec
66{ 66{
@@ -81,7 +81,7 @@ typedef enum e_image_codec
81class LLImage 81class LLImage
82{ 82{
83public: 83public:
84 static void initClass(LLWorkerThread* workerthread); 84 static void initClass();
85 static void cleanupClass(); 85 static void cleanupClass();
86 86
87 static const std::string& getLastError(); 87 static const std::string& getLastError();
@@ -309,7 +309,7 @@ protected:
309protected: 309protected:
310 S8 mCodec; 310 S8 mCodec;
311 S8 mDecoding; 311 S8 mDecoding;
312 S8 mDecoded; 312 S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC
313 S8 mDiscardLevel; 313 S8 mDiscardLevel;
314 314
315public: 315public:
diff --git a/linden/indra/llimage/llimagedxt.cpp b/linden/indra/llimage/llimagedxt.cpp
index 1ce4517..0aa6840 100644
--- a/linden/indra/llimage/llimagedxt.cpp
+++ b/linden/indra/llimage/llimagedxt.cpp
@@ -264,6 +264,8 @@ void LLImageDXT::setFormat()
264// virtual 264// virtual
265BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) 265BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
266{ 266{
267 // *TODO: Test! This has been tweaked since its intial inception,
268 // but we don't use it any more!
267 llassert_always(raw_image); 269 llassert_always(raw_image);
268 270
269 if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5) 271 if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
@@ -274,8 +276,17 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
274 276
275 S32 width = getWidth(), height = getHeight(); 277 S32 width = getWidth(), height = getHeight();
276 S32 ncomponents = getComponents(); 278 S32 ncomponents = getComponents();
279 U8* data = NULL;
280 if (mDiscardLevel >= 0)
281 {
282 data = getData() + getMipOffset(mDiscardLevel);
283 calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
284 }
285 else
286 {
287 data = getData() + getMipOffset(0);
288 }
277 S32 image_size = formatBytes(mFileFormat, width, height); 289 S32 image_size = formatBytes(mFileFormat, width, height);
278 U8* data = getData() + getMipOffset(0);
279 290
280 if ((!getData()) || (data + image_size > getData() + getDataSize())) 291 if ((!getData()) || (data + image_size > getData() + getDataSize()))
281 { 292 {
@@ -300,10 +311,8 @@ BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
300 llerrs << "Request for invalid discard level" << llendl; 311 llerrs << "Request for invalid discard level" << llendl;
301 } 312 }
302 U8* data = getData() + getMipOffset(discard); 313 U8* data = getData() + getMipOffset(discard);
303 // I'm not sure these are the correct initial values for height and width, 314 S32 width = 0;
304 // but previously they were being used uninitialized. JC 315 S32 height = 0;
305 S32 width = raw->getWidth();
306 S32 height = raw->getHeight();
307 calcDiscardWidthHeight(discard, mFileFormat, width, height); 316 calcDiscardWidthHeight(discard, mFileFormat, width, height);
308 raw = new LLImageRaw(data, width, height, getComponents()); 317 raw = new LLImageRaw(data, width, height, getComponents());
309 return TRUE; 318 return TRUE;
diff --git a/linden/indra/llimage/llimagej2c.cpp b/linden/indra/llimage/llimagej2c.cpp
index ed58f85..1aae83e 100644
--- a/linden/indra/llimage/llimagej2c.cpp
+++ b/linden/indra/llimage/llimagej2c.cpp
@@ -277,6 +277,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
277} 277}
278 278
279 279
280// Returns TRUE to mean done, whether successful or not.
280BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) 281BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
281{ 282{
282 LLMemType mt1((LLMemType::EMemType)mMemType); 283 LLMemType mt1((LLMemType::EMemType)mMemType);
@@ -289,7 +290,7 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
289 if (!getData() || (getDataSize() < 16)) 290 if (!getData() || (getDataSize() < 16))
290 { 291 {
291 setLastError("LLImageJ2C uninitialized"); 292 setLastError("LLImageJ2C uninitialized");
292 res = FALSE; 293 res = TRUE; // done
293 } 294 }
294 else 295 else
295 { 296 {
@@ -342,7 +343,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text,
342//static 343//static
343S32 LLImageJ2C::calcHeaderSizeJ2C() 344S32 LLImageJ2C::calcHeaderSizeJ2C()
344{ 345{
345 return 600; //2048; // ??? hack... just needs to be >= actual header size... 346 return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size...
346} 347}
347 348
348//static 349//static
diff --git a/linden/indra/llimage/llimagejpeg.cpp b/linden/indra/llimage/llimagejpeg.cpp
index fa0dd3f..79ea79c 100644
--- a/linden/indra/llimage/llimagejpeg.cpp
+++ b/linden/indra/llimage/llimagejpeg.cpp
@@ -188,6 +188,7 @@ void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo)
188} 188}
189 189
190 190
191// Returns true when done, whether or not decode was successful.
191BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) 192BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
192{ 193{
193 llassert_always(raw_image); 194 llassert_always(raw_image);
@@ -198,7 +199,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
198 if (!getData() || (0 == getDataSize())) 199 if (!getData() || (0 == getDataSize()))
199 { 200 {
200 setLastError("LLImageJPEG trying to decode an image with no data!"); 201 setLastError("LLImageJPEG trying to decode an image with no data!");
201 return FALSE; 202 return TRUE; // done
202 } 203 }
203 204
204 S32 row_stride = 0; 205 S32 row_stride = 0;
@@ -226,7 +227,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
226 if(setjmp(sSetjmpBuffer)) 227 if(setjmp(sSetjmpBuffer))
227 { 228 {
228 jpeg_destroy_decompress(&cinfo); 229 jpeg_destroy_decompress(&cinfo);
229 return FALSE; 230 return TRUE; // done
230 } 231 }
231 try 232 try
232 { 233 {
@@ -320,7 +321,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
320 catch (int) 321 catch (int)
321 { 322 {
322 jpeg_destroy_decompress(&cinfo); 323 jpeg_destroy_decompress(&cinfo);
323 return FALSE; 324 return TRUE; // done
324 } 325 }
325 326
326 // Check to see whether any corrupt-data warnings occurred 327 // Check to see whether any corrupt-data warnings occurred
@@ -328,7 +329,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
328 { 329 {
329 // TODO: extract the warning to find out what went wrong. 330 // TODO: extract the warning to find out what went wrong.
330 setLastError( "Unable to decode JPEG image."); 331 setLastError( "Unable to decode JPEG image.");
331 return FALSE; 332 return TRUE; // done
332 } 333 }
333 334
334 return TRUE; 335 return TRUE;
diff --git a/linden/indra/llimage/llimageworker.cpp b/linden/indra/llimage/llimageworker.cpp
index 532e996..86d4151 100644
--- a/linden/indra/llimage/llimageworker.cpp
+++ b/linden/indra/llimage/llimageworker.cpp
@@ -37,152 +37,138 @@
37 37
38//---------------------------------------------------------------------------- 38//----------------------------------------------------------------------------
39 39
40//static 40// MAIN THREAD
41LLWorkerThread* LLImageWorker::sWorkerThread = NULL; 41LLImageDecodeThread::LLImageDecodeThread(bool threaded)
42S32 LLImageWorker::sCount = 0; 42 : LLQueuedThread("imagedecode", threaded)
43{
44 mCreationMutex = new LLMutex(getAPRPool());
45}
43 46
44//static 47// MAIN THREAD
45void LLImageWorker::initImageWorker(LLWorkerThread* workerthread) 48// virtual
49S32 LLImageDecodeThread::update(U32 max_time_ms)
46{ 50{
47 sWorkerThread = workerthread; 51 LLMutexLock lock(mCreationMutex);
52 for (creation_list_t::iterator iter = mCreationList.begin();
53 iter != mCreationList.end(); ++iter)
54 {
55 creation_info& info = *iter;
56 ImageRequest* req = new ImageRequest(info.handle, info.image,
57 info.priority, info.discard, info.needs_aux,
58 info.responder);
59 addRequest(req);
60 }
61 mCreationList.clear();
62 S32 res = LLQueuedThread::update(max_time_ms);
63 return res;
48} 64}
49 65
50//static 66LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,
51void LLImageWorker::cleanupImageWorker() 67 U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
68{
69 LLMutexLock lock(mCreationMutex);
70 handle_t handle = generateHandle();
71 mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
72 return handle;
73}
74
75// Used by unit test only
76// Returns the size of the mutex guarded list as an indication of sanity
77S32 LLImageDecodeThread::tut_size()
78{
79 LLMutexLock lock(mCreationMutex);
80 S32 res = mCreationList.size();
81 return res;
82}
83
84LLImageDecodeThread::Responder::~Responder()
52{ 85{
53} 86}
54 87
55//---------------------------------------------------------------------------- 88//----------------------------------------------------------------------------
56 89
57LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, 90LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image,
58 S32 discard, 91 U32 priority, S32 discard, BOOL needs_aux,
59 LLPointer<LLResponder> responder) 92 LLImageDecodeThread::Responder* responder)
60 : LLWorkerClass(sWorkerThread, "Image"), 93 : LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
61 mFormattedImage(image), 94 mFormattedImage(image),
62 mDecodedType(-1),
63 mDiscardLevel(discard), 95 mDiscardLevel(discard),
64 mPriority(priority), 96 mNeedsAux(needs_aux),
97 mDecodedRaw(FALSE),
98 mDecodedAux(FALSE),
65 mResponder(responder) 99 mResponder(responder)
66{ 100{
67 ++sCount;
68} 101}
69 102
70LLImageWorker::~LLImageWorker() 103LLImageDecodeThread::ImageRequest::~ImageRequest()
71{ 104{
72 mDecodedImage = NULL; 105 mDecodedImageRaw = NULL;
106 mDecodedImageAux = NULL;
73 mFormattedImage = NULL; 107 mFormattedImage = NULL;
74 --sCount;
75} 108}
76 109
77//---------------------------------------------------------------------------- 110//----------------------------------------------------------------------------
78 111
79//virtual, main thread
80void LLImageWorker::startWork(S32 param)
81{
82 llassert_always(mDecodedImage.isNull());
83 mDecodedType = -1;
84}
85 112
86bool LLImageWorker::doWork(S32 param) 113// Returns true when done, whether or not decode was successful.
114bool LLImageDecodeThread::ImageRequest::processRequest()
87{ 115{
88 bool decoded = false; 116 const F32 decode_time_slice = .1f;
89 if(mDecodedImage.isNull()) 117 bool done = true;
118 if (!mDecodedRaw && mFormattedImage.notNull())
90 { 119 {
91 if (!mFormattedImage->updateData()) 120 // Decode primary channels
92 { 121 if (mDecodedImageRaw.isNull())
93 mDecodedType = -2; // failed
94 return true;
95 }
96 if (mDiscardLevel >= 0)
97 { 122 {
98 mFormattedImage->setDiscardLevel(mDiscardLevel); 123 // parse formatted header
99 } 124 if (!mFormattedImage->updateData())
100 if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) 125 {
101 { 126 return true; // done (failed)
102 decoded = true; // failed 127 }
103 } 128 if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
104 else 129 {
105 { 130 return true; // done (failed)
106 mDecodedImage = new LLImageRaw(); // allow possibly smaller size set during decoding 131 }
132 if (mDiscardLevel >= 0)
133 {
134 mFormattedImage->setDiscardLevel(mDiscardLevel);
135 }
136 mDecodedImageRaw = new LLImageRaw(mFormattedImage->getWidth(),
137 mFormattedImage->getHeight(),
138 mFormattedImage->getComponents());
107 } 139 }
140 done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms
141 mDecodedRaw = done;
108 } 142 }
109 if (!decoded) 143 if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull())
110 { 144 {
111 if (param == 0) 145 // Decode aux channel
112 { 146 if (!mDecodedImageAux)
113 // Decode primary channels
114 decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
115 }
116 else
117 { 147 {
118 // Decode aux channel 148 mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(),
119 decoded = mFormattedImage->decodeChannels(mDecodedImage, .1f, param, param); // 1ms 149 mFormattedImage->getHeight(),
150 1);
120 } 151 }
152 done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms
153 mDecodedAux = done;
121 } 154 }
122 if (decoded)
123 {
124 // Call the callback immediately; endWork doesn't get called until ckeckWork
125 if (mResponder.notNull())
126 {
127 bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
128 mResponder->completed(success);
129 }
130 }
131 return decoded;
132}
133 155
134void LLImageWorker::endWork(S32 param, bool aborted) 156 return done;
135{
136 if (mDecodedType != -2)
137 {
138 mDecodedType = aborted ? -2 : param;
139 }
140} 157}
141 158
142//---------------------------------------------------------------------------- 159void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
143
144
145BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
146{ 160{
147 // For most codecs, only mDiscardLevel data is available. 161 if (mResponder.notNull())
148 // (see LLImageDXT for exception)
149 if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
150 {
151 llerrs << "Request for invalid discard level" << llendl;
152 }
153 checkWork();
154 if (mDecodedType == -2)
155 { 162 {
156 return TRUE; // aborted, done 163 bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
157 } 164 mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux);
158 if (mDecodedType != channel)
159 {
160 if (!haveWork())
161 {
162 addWork(channel, mPriority);
163 }
164 return FALSE;
165 }
166 else
167 {
168 llassert_always(!haveWork());
169 llassert_always(mDecodedType == channel);
170 raw = mDecodedImage; // smart pointer acquires ownership of data
171 mDecodedImage = NULL;
172 return TRUE;
173 } 165 }
166 // Will automatically be deleted
174} 167}
175 168
176BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard) 169// Used by unit test only
170// Checks that a responder exists for this instance so that something can happen when completion is reached
171bool LLImageDecodeThread::ImageRequest::tut_isOK()
177{ 172{
178 if (mFormattedImage->getCodec() == IMG_CODEC_DXT) 173 return mResponder.notNull();
179 {
180 // special case
181 LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
182 return imagedxt->getMipData(raw, discard);
183 }
184 else
185 {
186 return requestDecodedAuxData(raw, 0, discard);
187 }
188} 174}
diff --git a/linden/indra/llimage/llimageworker.h b/linden/indra/llimage/llimageworker.h
index 879fcf5..fcd3039 100644
--- a/linden/indra/llimage/llimageworker.h
+++ b/linden/indra/llimage/llimageworker.h
@@ -34,51 +34,74 @@
34#define LL_LLIMAGEWORKER_H 34#define LL_LLIMAGEWORKER_H
35 35
36#include "llimage.h" 36#include "llimage.h"
37#include "llworkerthread.h" 37#include "llqueuedthread.h"
38 38
39class LLImageWorker : public LLWorkerClass 39class LLImageDecodeThread : public LLQueuedThread
40{ 40{
41public: 41public:
42 static void initImageWorker(LLWorkerThread* workerthread); 42 class Responder : public LLThreadSafeRefCount
43 static void cleanupImageWorker(); 43 {
44 44 protected:
45public: 45 virtual ~Responder();
46 static LLWorkerThread* getWorkerThread() { return sWorkerThread; } 46 public:
47 47 virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
48 // LLWorkerThread 48 };
49public:
50 LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard,
51 LLPointer<LLResponder> responder);
52 ~LLImageWorker();
53
54 // called from WORKER THREAD, returns TRUE if done
55 /*virtual*/ bool doWork(S32 param);
56
57 BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
58 BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
59 void releaseDecodedData();
60 void cancelDecode();
61 49
62private: 50 class ImageRequest : public LLQueuedThread::QueuedRequest
63 // called from MAIN THREAD 51 {
64 /*virtual*/ void startWork(S32 param); // called from addWork() 52 protected:
65 /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() 53 virtual ~ImageRequest(); // use deleteRequest()
54
55 public:
56 ImageRequest(handle_t handle, LLImageFormatted* image,
57 U32 priority, S32 discard, BOOL needs_aux,
58 LLImageDecodeThread::Responder* responder);
66 59
67protected: 60 /*virtual*/ bool processRequest();
68 LLPointer<LLImageFormatted> mFormattedImage; 61 /*virtual*/ void finishRequest(bool completed);
69 LLPointer<LLImageRaw> mDecodedImage;
70 S32 mDecodedType;
71 S32 mDiscardLevel;
72 62
73private: 63 // Used by unit tests to check the consitency of the request instance
74 U32 mPriority; 64 bool tut_isOK();
75 LLPointer<LLResponder> mResponder; 65
66 private:
67 // input
68 LLPointer<LLImageFormatted> mFormattedImage;
69 S32 mDiscardLevel;
70 BOOL mNeedsAux;
71 // output
72 LLPointer<LLImageRaw> mDecodedImageRaw;
73 LLPointer<LLImageRaw> mDecodedImageAux;
74 BOOL mDecodedRaw;
75 BOOL mDecodedAux;
76 LLPointer<LLImageDecodeThread::Responder> mResponder;
77 };
76 78
77protected:
78 static LLWorkerThread* sWorkerThread;
79
80public: 79public:
81 static S32 sCount; 80 LLImageDecodeThread(bool threaded = true);
81 handle_t decodeImage(LLImageFormatted* image,
82 U32 priority, S32 discard, BOOL needs_aux,
83 Responder* responder);
84 S32 update(U32 max_time_ms);
85
86 // Used by unit tests to check the consistency of the thread instance
87 S32 tut_size();
88
89private:
90 struct creation_info
91 {
92 handle_t handle;
93 LLImageFormatted* image;
94 U32 priority;
95 S32 discard;
96 BOOL needs_aux;
97 LLPointer<Responder> responder;
98 creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r)
99 : handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r)
100 {}
101 };
102 typedef std::list<creation_info> creation_list_t;
103 creation_list_t mCreationList;
104 LLMutex* mCreationMutex;
82}; 105};
83 106
84#endif 107#endif
diff --git a/linden/indra/llrender/llcubemap.cpp b/linden/indra/llrender/llcubemap.cpp
index 754d90c..a5c677d 100644
--- a/linden/indra/llrender/llcubemap.cpp
+++ b/linden/indra/llrender/llcubemap.cpp
@@ -94,7 +94,7 @@ void LLCubeMap::initGL()
94 mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE)); 94 mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE));
95 mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP); 95 mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP);
96 mRawImages[i] = new LLImageRaw(64, 64, 4); 96 mRawImages[i] = new LLImageRaw(64, 64, 4);
97 mImages[i]->createGLTexture(0, mRawImages[i], texname); 97 mImages[i]->createGLTexture(0, mRawImages[i], texname, TRUE);
98 98
99 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); 99 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname);
100 mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP); 100 mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -106,7 +106,7 @@ void LLCubeMap::initGL()
106 } 106 }
107 else 107 else
108 { 108 {
109 llwarns << "Using cube map without extension!" << llendl 109 llwarns << "Using cube map without extension!" << llendl;
110 } 110 }
111} 111}
112 112
diff --git a/linden/indra/llrender/llimagegl.cpp b/linden/indra/llrender/llimagegl.cpp
index d1efb11..27b1d55 100644
--- a/linden/indra/llrender/llimagegl.cpp
+++ b/linden/indra/llrender/llimagegl.cpp
@@ -43,8 +43,6 @@
43#include "llmath.h" 43#include "llmath.h"
44#include "llgl.h" 44#include "llgl.h"
45#include "llrender.h" 45#include "llrender.h"
46
47
48//---------------------------------------------------------------------------- 46//----------------------------------------------------------------------------
49 47
50const F32 MIN_TEXTURE_LIFETIME = 10.f; 48const F32 MIN_TEXTURE_LIFETIME = 10.f;
@@ -61,8 +59,33 @@ S32 LLImageGL::sCount = 0;
61 59
62BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; 60BOOL LLImageGL::sGlobalUseAnisotropic = FALSE;
63F32 LLImageGL::sLastFrameTime = 0.f; 61F32 LLImageGL::sLastFrameTime = 0.f;
62BOOL LLImageGL::sAllowReadBackRaw = FALSE ;
64 63
65std::set<LLImageGL*> LLImageGL::sImageList; 64std::set<LLImageGL*> LLImageGL::sImageList;
65
66//****************************************************************************************************
67//The below for texture auditing use only
68//****************************************************************************************************
69//-----------------------
70//debug use
71BOOL gAuditTexture = FALSE ;
72#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048
73std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
74std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
75std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
76S32 LLImageGL::sCurTexSizeBar = -1 ;
77S32 LLImageGL::sCurTexPickSize = -1 ;
78LLPointer<LLImageGL> LLImageGL::sDefaultTexturep = NULL;
79S32 LLImageGL::sMaxCatagories = 1 ;
80
81std::vector<S32> LLImageGL::sTextureMemByCategory;
82std::vector<S32> LLImageGL::sTextureMemByCategoryBound ;
83std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ;
84//------------------------
85//****************************************************************************************************
86//End for texture auditing use only
87//****************************************************************************************************
88
66//************************************************************************************** 89//**************************************************************************************
67//below are functions for debug use 90//below are functions for debug use
68//do not delete them even though they are not currently being used. 91//do not delete them even though they are not currently being used.
@@ -110,6 +133,20 @@ void LLImageGL::checkTexSize() const
110//************************************************************************************** 133//**************************************************************************************
111 134
112//---------------------------------------------------------------------------- 135//----------------------------------------------------------------------------
136//static
137void LLImageGL::initClass(S32 num_catagories)
138{
139 sMaxCatagories = num_catagories ;
140
141 sTextureMemByCategory.resize(sMaxCatagories);
142 sTextureMemByCategoryBound.resize(sMaxCatagories) ;
143 sTextureCurMemByCategoryBound.resize(sMaxCatagories) ;
144}
145
146//static
147void LLImageGL::cleanupClass()
148{
149}
113 150
114//static 151//static
115S32 LLImageGL::dataFormatBits(S32 dataformat) 152S32 LLImageGL::dataFormatBits(S32 dataformat)
@@ -176,12 +213,44 @@ void LLImageGL::updateStats(F32 current_time)
176 sLastFrameTime = current_time; 213 sLastFrameTime = current_time;
177 sBoundTextureMemoryInBytes = sCurBoundTextureMemory; 214 sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
178 sCurBoundTextureMemory = 0; 215 sCurBoundTextureMemory = 0;
216
217 if(gAuditTexture)
218 {
219 for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
220 {
221 sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
222 sTextureCurBoundCounter[i] = 0 ;
223 }
224 for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++)
225 {
226 sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ;
227 sTextureCurMemByCategoryBound[i] = 0 ;
228 }
229 }
179} 230}
180 231
181//static 232//static
182S32 LLImageGL::updateBoundTexMem(const S32 delta) 233S32 LLImageGL::updateBoundTexMemStatic(const S32 delta, const S32 size, S32 category)
234{
235 if(gAuditTexture)
236 {
237 sTextureCurBoundCounter[getTextureCounterIndex(size)]++ ;
238 sTextureCurMemByCategoryBound[category] += delta ;
239 }
240
241 LLImageGL::sCurBoundTextureMemory += delta ;
242 return LLImageGL::sCurBoundTextureMemory;
243}
244
245S32 LLImageGL::updateBoundTexMem()const
183{ 246{
184 LLImageGL::sCurBoundTextureMemory += delta; 247 if(gAuditTexture)
248 {
249 sTextureCurBoundCounter[getTextureCounterIndex(mTextureMemory / mComponents)]++ ;
250 sTextureCurMemByCategoryBound[mCategory] += mTextureMemory ;
251 }
252
253 LLImageGL::sCurBoundTextureMemory += mTextureMemory ;
185 return LLImageGL::sCurBoundTextureMemory; 254 return LLImageGL::sCurBoundTextureMemory;
186} 255}
187 256
@@ -195,6 +264,7 @@ void LLImageGL::destroyGL(BOOL save_state)
195 gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); 264 gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE);
196 } 265 }
197 266
267 sAllowReadBackRaw = true ;
198 for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); 268 for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
199 iter != sImageList.end(); iter++) 269 iter != sImageList.end(); iter++)
200 { 270 {
@@ -204,7 +274,7 @@ void LLImageGL::destroyGL(BOOL save_state)
204 if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) 274 if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
205 { 275 {
206 glimage->mSaveData = new LLImageRaw; 276 glimage->mSaveData = new LLImageRaw;
207 if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) 277 if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
208 { 278 {
209 glimage->mSaveData = NULL ; 279 glimage->mSaveData = NULL ;
210 } 280 }
@@ -214,6 +284,7 @@ void LLImageGL::destroyGL(BOOL save_state)
214 stop_glerror(); 284 stop_glerror();
215 } 285 }
216 } 286 }
287 sAllowReadBackRaw = false ;
217} 288}
218 289
219//static 290//static
@@ -231,7 +302,7 @@ void LLImageGL::restoreGL()
231 { 302 {
232 if (glimage->getComponents() && glimage->mSaveData->getComponents()) 303 if (glimage->getComponents() && glimage->mSaveData->getComponents())
233 { 304 {
234 glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData); 305 glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory());
235 stop_glerror(); 306 stop_glerror();
236 } 307 }
237 glimage->mSaveData = NULL; // deletes data 308 glimage->mSaveData = NULL; // deletes data
@@ -311,7 +382,7 @@ void LLImageGL::init(BOOL usemipmaps)
311 mTextureState = NO_DELETE ; 382 mTextureState = NO_DELETE ;
312 mTextureMemory = 0; 383 mTextureMemory = 0;
313 mLastBindTime = 0.f; 384 mLastBindTime = 0.f;
314 385
315 mTarget = GL_TEXTURE_2D; 386 mTarget = GL_TEXTURE_2D;
316 mBindTarget = LLTexUnit::TT_TEXTURE; 387 mBindTarget = LLTexUnit::TT_TEXTURE;
317 mUseMipMaps = usemipmaps; 388 mUseMipMaps = usemipmaps;
@@ -338,7 +409,9 @@ void LLImageGL::init(BOOL usemipmaps)
338 mHasExplicitFormat = FALSE; 409 mHasExplicitFormat = FALSE;
339 410
340 mGLTextureCreated = FALSE ; 411 mGLTextureCreated = FALSE ;
412
341 mIsMask = FALSE; 413 mIsMask = FALSE;
414 mCategory = -1 ;
342} 415}
343 416
344void LLImageGL::cleanup() 417void LLImageGL::cleanup()
@@ -438,6 +511,10 @@ void LLImageGL::dump()
438} 511}
439 512
440//---------------------------------------------------------------------------- 513//----------------------------------------------------------------------------
514void LLImageGL::forceUpdateBindStats(void) const
515{
516 mLastBindTime = sLastFrameTime;
517}
441 518
442void LLImageGL::updateBindStats(void) const 519void LLImageGL::updateBindStats(void) const
443{ 520{
@@ -451,7 +528,8 @@ void LLImageGL::updateBindStats(void) const
451 { 528 {
452 // we haven't accounted for this texture yet this frame 529 // we haven't accounted for this texture yet this frame
453 sUniqueCount++; 530 sUniqueCount++;
454 updateBoundTexMem(mTextureMemory); 531
532 updateBoundTexMem();
455 mLastBindTime = sLastFrameTime; 533 mLastBindTime = sLastFrameTime;
456 } 534 }
457 } 535 }
@@ -464,7 +542,7 @@ bool LLImageGL::bindError(const S32 stage) const
464} 542}
465 543
466//virtual 544//virtual
467bool LLImageGL::bindDefaultImage(const S32 stage) const 545bool LLImageGL::bindDefaultImage(const S32 stage)
468{ 546{
469 return false; 547 return false;
470} 548}
@@ -503,7 +581,6 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
503void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) 581void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
504{ 582{
505// LLFastTimer t1(LLFastTimer::FTM_TEMP1); 583// LLFastTimer t1(LLFastTimer::FTM_TEMP1);
506 llpushcallstacks ;
507 bool is_compressed = false; 584 bool is_compressed = false;
508 if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) 585 if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
509 { 586 {
@@ -716,12 +793,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
716 } 793 }
717 stop_glerror(); 794 stop_glerror();
718 mGLTextureCreated = true; 795 mGLTextureCreated = true;
719 llpushcallstacks ;
720} 796}
721 797
722BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) 798BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
723{ 799{
724 llpushcallstacks ;
725 if (!width || !height) 800 if (!width || !height)
726 { 801 {
727 return TRUE; 802 return TRUE;
@@ -737,7 +812,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
737 return FALSE; 812 return FALSE;
738 } 813 }
739 814
740 if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) 815 // HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture.
816 if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height)
741 { 817 {
742 setImage(datap, FALSE); 818 setImage(datap, FALSE);
743 } 819 }
@@ -810,20 +886,20 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
810 stop_glerror(); 886 stop_glerror();
811 mGLTextureCreated = true; 887 mGLTextureCreated = true;
812 } 888 }
813 llpushcallstacks ;
814 return TRUE; 889 return TRUE;
815} 890}
816 891
817BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) 892BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
818{ 893{
819 return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height); 894 return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update);
820} 895}
821 896
822// Copy sub image from frame buffer 897// Copy sub image from frame buffer
823BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height) 898BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
824{ 899{
825 if (gGL.getTexUnit(0)->bind(this, true)) 900 if (gGL.getTexUnit(0)->bind(this, false, true))
826 { 901 {
902 //checkTexSize() ;
827 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); 903 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
828 mGLTextureCreated = true; 904 mGLTextureCreated = true;
829 stop_glerror(); 905 stop_glerror();
@@ -883,14 +959,14 @@ BOOL LLImageGL::createGLTexture()
883 return TRUE ; 959 return TRUE ;
884} 960}
885 961
886BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/) 962BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
887{ 963{
888 llpushcallstacks ;
889 if (gGLManager.mIsDisabled) 964 if (gGLManager.mIsDisabled)
890 { 965 {
891 llwarns << "Trying to create a texture while GL is disabled!" << llendl; 966 llwarns << "Trying to create a texture while GL is disabled!" << llendl;
892 return FALSE; 967 return FALSE;
893 } 968 }
969
894 mGLTextureCreated = false ; 970 mGLTextureCreated = false ;
895 llassert(gGLManager.mInited); 971 llassert(gGLManager.mInited);
896 stop_glerror(); 972 stop_glerror();
@@ -903,8 +979,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
903 discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); 979 discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
904 980
905 // Actual image width/height = raw image width/height * 2^discard_level 981 // Actual image width/height = raw image width/height * 2^discard_level
906 S32 w = imageraw->getWidth() << discard_level; 982 S32 raw_w = imageraw->getWidth() ;
907 S32 h = imageraw->getHeight() << discard_level; 983 S32 raw_h = imageraw->getHeight() ;
984 S32 w = raw_w << discard_level;
985 S32 h = raw_h << discard_level;
908 986
909 // setSize may call destroyGLTexture if the size does not match 987 // setSize may call destroyGLTexture if the size does not match
910 setSize(w, h, imageraw->getComponents()); 988 setSize(w, h, imageraw->getComponents());
@@ -940,13 +1018,21 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
940 } 1018 }
941 } 1019 }
942 1020
1021 if(!to_create) //not create a gl texture
1022 {
1023 destroyGLTexture();
1024 mCurrentDiscardLevel = discard_level;
1025 mLastBindTime = sLastFrameTime;
1026 return TRUE ;
1027 }
1028
1029 mCategory = category ;
943 const U8* rawdata = imageraw->getData(); 1030 const U8* rawdata = imageraw->getData();
944 return createGLTexture(discard_level, rawdata, FALSE, usename); 1031 return createGLTexture(discard_level, rawdata, FALSE, usename);
945} 1032}
946 1033
947BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) 1034BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
948{ 1035{
949 llpushcallstacks ;
950 llassert(data_in); 1036 llassert(data_in);
951 1037
952 if (discard_level < 0) 1038 if (discard_level < 0)
@@ -1014,7 +1100,14 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
1014 if (old_name != 0) 1100 if (old_name != 0)
1015 { 1101 {
1016 sGlobalTextureMemoryInBytes -= mTextureMemory; 1102 sGlobalTextureMemoryInBytes -= mTextureMemory;
1103
1104 if(gAuditTexture)
1105 {
1106 decTextureCounter() ;
1107 }
1108
1017 LLImageGL::deleteTextures(1, &old_name); 1109 LLImageGL::deleteTextures(1, &old_name);
1110
1018 stop_glerror(); 1111 stop_glerror();
1019 } 1112 }
1020 1113
@@ -1022,13 +1115,15 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
1022 sGlobalTextureMemoryInBytes += mTextureMemory; 1115 sGlobalTextureMemoryInBytes += mTextureMemory;
1023 setActive() ; 1116 setActive() ;
1024 1117
1118 if(gAuditTexture)
1119 {
1120 incTextureCounter() ;
1121 }
1025 // mark this as bound at this point, so we don't throw it out immediately 1122 // mark this as bound at this point, so we don't throw it out immediately
1026 mLastBindTime = sLastFrameTime; 1123 mLastBindTime = sLastFrameTime;
1027
1028 llpushcallstacks ;
1029 return TRUE; 1124 return TRUE;
1030} 1125}
1031 1126#if 0
1032BOOL LLImageGL::setDiscardLevel(S32 discard_level) 1127BOOL LLImageGL::setDiscardLevel(S32 discard_level)
1033{ 1128{
1034 llassert(discard_level >= 0); 1129 llassert(discard_level >= 0);
@@ -1080,25 +1175,14 @@ BOOL LLImageGL::setDiscardLevel(S32 discard_level)
1080 return FALSE; 1175 return FALSE;
1081 } 1176 }
1082} 1177}
1083 1178#endif
1084BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents)
1085{
1086 assert_glerror();
1087 S32 gl_discard = discard_level - mCurrentDiscardLevel;
1088 LLGLint glwidth = 0;
1089 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
1090 LLGLint glheight = 0;
1091 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_HEIGHT, (GLint*)&glheight);
1092 LLGLint glcomponents = 0 ;
1093 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&glcomponents);
1094 assert_glerror();
1095
1096 return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ;
1097}
1098 1179
1099BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) 1180BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok)
1100{ 1181{
1101 llpushcallstacks ; 1182 // VWR-13505 : Merov : Allow gl texture read back so save texture works again (temporary)
1183 //llassert_always(sAllowReadBackRaw) ;
1184 //llerrs << "should not call this function!" << llendl ;
1185
1102 if (discard_level < 0) 1186 if (discard_level < 0)
1103 { 1187 {
1104 discard_level = mCurrentDiscardLevel; 1188 discard_level = mCurrentDiscardLevel;
@@ -1201,7 +1285,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
1201 return FALSE ; 1285 return FALSE ;
1202 } 1286 }
1203 //----------------------------------------------------------------------------------------------- 1287 //-----------------------------------------------------------------------------------------------
1204 llpushcallstacks ; 1288
1205 return TRUE ; 1289 return TRUE ;
1206} 1290}
1207 1291
@@ -1219,12 +1303,19 @@ void LLImageGL::destroyGLTexture()
1219 stop_glerror(); 1303 stop_glerror();
1220 } 1304 }
1221 } 1305 }
1222 1306
1223 sGlobalTextureMemoryInBytes -= mTextureMemory; 1307 if(mTextureMemory)
1224 mTextureMemory = 0; 1308 {
1225 1309 if(gAuditTexture)
1310 {
1311 decTextureCounter() ;
1312 }
1313 sGlobalTextureMemoryInBytes -= mTextureMemory;
1314 mTextureMemory = 0;
1315 }
1316
1226 LLImageGL::deleteTextures(1, &mTexName); 1317 LLImageGL::deleteTextures(1, &mTexName);
1227 mTextureState = DELETED ; 1318 mTextureState = DELETED ;
1228 mTexName = 0; 1319 mTexName = 0;
1229 mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. 1320 mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
1230 mGLTextureCreated = FALSE ; 1321 mGLTextureCreated = FALSE ;
@@ -1338,6 +1429,11 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const
1338 return res; 1429 return res;
1339} 1430}
1340 1431
1432BOOL LLImageGL::isJustBound() const
1433{
1434 return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f);
1435}
1436
1341BOOL LLImageGL::getBoundRecently() const 1437BOOL LLImageGL::getBoundRecently() const
1342{ 1438{
1343 return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); 1439 return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
@@ -1539,6 +1635,87 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
1539 return res; 1635 return res;
1540} 1636}
1541 1637
1638void LLImageGL::setCategory(S32 category)
1639{
1640 if(!gAuditTexture)
1641 {
1642 return ;
1643 }
1644 if(mCategory != category)
1645 {
1646 if(mCategory > -1)
1647 {
1648 sTextureMemByCategory[mCategory] -= mTextureMemory ;
1649 }
1650 sTextureMemByCategory[category] += mTextureMemory ;
1651
1652 mCategory = category;
1653 }
1654}
1655
1656//for debug use
1657//val is a "power of two" number
1658S32 LLImageGL::getTextureCounterIndex(U32 val)
1659{
1660 //index range is [0, MAX_TEXTURE_LOG_SIZE].
1661 if(val < 2)
1662 {
1663 return 0 ;
1664 }
1665 else if(val >= (1 << MAX_TEXTURE_LOG_SIZE))
1666 {
1667 return MAX_TEXTURE_LOG_SIZE ;
1668 }
1669 else
1670 {
1671 S32 ret = 0 ;
1672 while(val >>= 1)
1673 {
1674 ++ret;
1675 }
1676 return ret ;
1677 }
1678}
1679void LLImageGL::incTextureCounterStatic(U32 val, S32 ncomponents, S32 category)
1680{
1681 sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
1682 sTextureMemByCategory[category] += (S32)val * ncomponents ;
1683}
1684void LLImageGL::decTextureCounterStatic(U32 val, S32 ncomponents, S32 category)
1685{
1686 sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
1687 sTextureMemByCategory[category] += (S32)val * ncomponents ;
1688}
1689void LLImageGL::incTextureCounter()
1690{
1691 sTextureLoadedCounter[getTextureCounterIndex(mTextureMemory / mComponents)]++ ;
1692 sTextureMemByCategory[mCategory] += mTextureMemory ;
1693}
1694void LLImageGL::decTextureCounter()
1695{
1696 sTextureLoadedCounter[getTextureCounterIndex(mTextureMemory / mComponents)]-- ;
1697 sTextureMemByCategory[mCategory] -= mTextureMemory ;
1698}
1699void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size)
1700{
1701 sCurTexSizeBar = index ;
1702
1703 if(set_pick_size)
1704 {
1705 sCurTexPickSize = (1 << index) ;
1706 }
1707 else
1708 {
1709 sCurTexPickSize = -1 ;
1710 }
1711}
1712void LLImageGL::resetCurTexSizebar()
1713{
1714 sCurTexSizeBar = -1 ;
1715 sCurTexPickSize = -1 ;
1716}
1717//----------------------------------------------------------------------------
1718
1542//---------------------------------------------------------------------------- 1719//----------------------------------------------------------------------------
1543 1720
1544 1721
diff --git a/linden/indra/llrender/llimagegl.h b/linden/indra/llrender/llimagegl.h
index 2f08a5a..c8df101 100644
--- a/linden/indra/llrender/llimagegl.h
+++ b/linden/indra/llrender/llimagegl.h
@@ -46,7 +46,6 @@
46#define MEGA_BYTES_TO_BYTES(x) ((x) << 20) 46#define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
47 47
48//============================================================================ 48//============================================================================
49
50class LLImageGL : public LLRefCount 49class LLImageGL : public LLRefCount
51{ 50{
52 friend class LLTexUnit; 51 friend class LLTexUnit;
@@ -57,6 +56,7 @@ public:
57 static S32 dataFormatComponents(S32 dataformat); 56 static S32 dataFormatComponents(S32 dataformat);
58 57
59 void updateBindStats(void) const; 58 void updateBindStats(void) const;
59 void forceUpdateBindStats(void) const;
60 60
61 // needs to be called every frame 61 // needs to be called every frame
62 static void updateStats(F32 current_time); 62 static void updateStats(F32 current_time);
@@ -65,9 +65,10 @@ public:
65 static void destroyGL(BOOL save_state = TRUE); 65 static void destroyGL(BOOL save_state = TRUE);
66 static void restoreGL(); 66 static void restoreGL();
67 67
68 // Sometimes called externally for textures not using LLImageGL (should go away...) 68 // Sometimes called externally for textures not using LLImageGL (should go away...)
69 static S32 updateBoundTexMem(const S32 delta); 69 static S32 updateBoundTexMemStatic(const S32 delta, const S32 size, S32 category) ;
70 70 S32 updateBoundTexMem()const;
71
71 static bool checkSize(S32 width, S32 height); 72 static bool checkSize(S32 width, S32 height);
72 73
73 // Not currently necessary for LLImageGL, but required in some derived classes, 74 // Not currently necessary for LLImageGL, but required in some derived classes,
@@ -89,7 +90,7 @@ protected:
89public: 90public:
90 virtual void dump(); // debugging info to llinfos 91 virtual void dump(); // debugging info to llinfos
91 virtual bool bindError(const S32 stage = 0) const; 92 virtual bool bindError(const S32 stage = 0) const;
92 virtual bool bindDefaultImage(const S32 stage = 0) const; 93 virtual bool bindDefaultImage(const S32 stage = 0) ;
93 virtual void forceImmediateUpdate() ; 94 virtual void forceImmediateUpdate() ;
94 95
95 void setSize(S32 width, S32 height, S32 ncomponents); 96 void setSize(S32 width, S32 height, S32 ncomponents);
@@ -101,20 +102,22 @@ public:
101 static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels); 102 static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
102 103
103 BOOL createGLTexture() ; 104 BOOL createGLTexture() ;
104 BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0); 105 BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
106 S32 category = sMaxCatagories - 1);
105 BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); 107 BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
106 void setImage(const LLImageRaw* imageraw); 108 void setImage(const LLImageRaw* imageraw);
107 void setImage(const U8* data_in, BOOL data_hasmips = FALSE); 109 void setImage(const U8* data_in, BOOL data_hasmips = FALSE);
108 BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); 110 BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
109 BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); 111 BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
110 BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); 112 BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
111 BOOL setDiscardLevel(S32 discard_level); 113
112 // Read back a raw image for this discard level, if it exists 114 // Read back a raw image for this discard level, if it exists
113 BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok); 115 BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok);
114 void destroyGLTexture(); 116 void destroyGLTexture();
115 117
116 void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); 118 void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
117 void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } 119 void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; }
120 void setComponents(S8 ncomponents) { mComponents = ncomponents; }
118 121
119 S32 getDiscardLevel() const { return mCurrentDiscardLevel; } 122 S32 getDiscardLevel() const { return mCurrentDiscardLevel; }
120 S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } 123 S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; }
@@ -127,6 +130,7 @@ public:
127 S32 getBytes(S32 discard_level = -1) const; 130 S32 getBytes(S32 discard_level = -1) const;
128 S32 getMipBytes(S32 discard_level = -1) const; 131 S32 getMipBytes(S32 discard_level = -1) const;
129 BOOL getBoundRecently() const; 132 BOOL getBoundRecently() const;
133 BOOL isJustBound() const;
130 LLGLenum getPrimaryFormat() const { return mFormatPrimary; } 134 LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
131 135
132 BOOL getHasGLTexture() const { return mTexName != 0; } 136 BOOL getHasGLTexture() const { return mTexName != 0; }
@@ -147,8 +151,6 @@ public:
147 BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; } 151 BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; }
148 BOOL getDontDiscard() const { return mDontDiscard; } 152 BOOL getDontDiscard() const { return mDontDiscard; }
149 153
150 BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ;
151
152 void updatePickMask(S32 width, S32 height, const U8* data_in); 154 void updatePickMask(S32 width, S32 height, const U8* data_in);
153 BOOL getMask(const LLVector2 &tc); 155 BOOL getMask(const LLVector2 &tc);
154 156
@@ -175,6 +177,7 @@ public:
175 void forceActive() ; 177 void forceActive() ;
176 void setNoDelete() ; 178 void setNoDelete() ;
177 179
180 void setTextureSize(S32 size) {mTextureMemory = size;}
178protected: 181protected:
179 void init(BOOL usemipmaps); 182 void init(BOOL usemipmaps);
180 virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors 183 virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors
@@ -183,7 +186,7 @@ public:
183 // Various GL/Rendering options 186 // Various GL/Rendering options
184 S32 mTextureMemory; 187 S32 mTextureMemory;
185 mutable F32 mLastBindTime; // last time this was bound, by discard level 188 mutable F32 mLastBindTime; // last time this was bound, by discard level
186 189
187private: 190private:
188 LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL 191 LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
189 U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel 192 U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel
@@ -198,7 +201,7 @@ private:
198 U16 mWidth; 201 U16 mWidth;
199 U16 mHeight; 202 U16 mHeight;
200 S8 mCurrentDiscardLevel; 203 S8 mCurrentDiscardLevel;
201 204
202protected: 205protected:
203 LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) 206 LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
204 LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps) 207 LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps)
@@ -237,7 +240,7 @@ public:
237 static S32 sCount; 240 static S32 sCount;
238 241
239 static F32 sLastFrameTime; 242 static F32 sLastFrameTime;
240 243
241 static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID 244 static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID
242 245
243 // Global memory statistics 246 // Global memory statistics
@@ -253,6 +256,57 @@ public:
253#else 256#else
254 BOOL getMissed() const { return FALSE; }; 257 BOOL getMissed() const { return FALSE; };
255#endif 258#endif
259
260public:
261 static void initClass(S32 num_catagories) ;
262 static void cleanupClass() ;
263private:
264 static S32 sMaxCatagories ;
265
266 //the flag to allow to call readBackRaw(...).
267 //can be removed if we do not use that function at all.
268 static BOOL sAllowReadBackRaw ;
269//
270//****************************************************************************************************
271//The below for texture auditing use only
272//****************************************************************************************************
273private:
274 S32 mCategory ;
275public:
276 void setCategory(S32 category) ;
277 S32 getCategory()const {return mCategory ;}
278
279 //for debug use: show texture size distribution
280 //----------------------------------------
281 static LLPointer<LLImageGL> sDefaultTexturep; //default texture to replace normal textures
282 static std::vector<S32> sTextureLoadedCounter ;
283 static std::vector<S32> sTextureBoundCounter ;
284 static std::vector<S32> sTextureCurBoundCounter ;
285 static S32 sCurTexSizeBar ;
286 static S32 sCurTexPickSize ;
287
288 static S32 getTextureCounterIndex(U32 val) ;
289 static void incTextureCounterStatic(U32 val, S32 ncomponents, S32 category) ;
290 static void decTextureCounterStatic(U32 val, S32 ncomponents, S32 category) ;
291 static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ;
292 static void resetCurTexSizebar();
293
294 void incTextureCounter() ;
295 void decTextureCounter() ;
296 //----------------------------------------
297
298 //for debug use: show texture category distribution
299 //----------------------------------------
300
301 static std::vector<S32> sTextureMemByCategory;
302 static std::vector<S32> sTextureMemByCategoryBound ;
303 static std::vector<S32> sTextureCurMemByCategoryBound ;
304 //----------------------------------------
305//****************************************************************************************************
306//End of definitions for texture auditing use only
307//****************************************************************************************************
308
256}; 309};
257 310
311extern BOOL gAuditTexture;
258#endif // LL_LLIMAGEGL_H 312#endif // LL_LLIMAGEGL_H
diff --git a/linden/indra/llrender/llrender.cpp b/linden/indra/llrender/llrender.cpp
index ba95a19..93ff822 100644
--- a/linden/indra/llrender/llrender.cpp
+++ b/linden/indra/llrender/llrender.cpp
@@ -177,7 +177,7 @@ void LLTexUnit::disable(void)
177 } 177 }
178} 178}
179 179
180bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) 180bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
181{ 181{
182 stop_glerror(); 182 stop_glerror();
183 if (mIndex < 0) return false; 183 if (mIndex < 0) return false;
@@ -192,12 +192,25 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
192 192
193 if (!texture->getTexName()) //if texture does not exist 193 if (!texture->getTexName()) //if texture does not exist
194 { 194 {
195 //if deleted, will re-generate it immediately 195 if (texture->isDeleted())
196 texture->forceImmediateUpdate() ; 196 {
197 // This will re-generate the texture immediately.
198 texture->forceImmediateUpdate() ;
199 }
197 200
201 texture->forceUpdateBindStats() ;
198 return texture->bindDefaultImage(mIndex); 202 return texture->bindDefaultImage(mIndex);
199 } 203 }
200 204
205 if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0)
206 {
207 if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize)
208 {
209 texture->updateBindStats();
210 return bind(LLImageGL::sDefaultTexturep.get());
211 }
212 }
213
201 if ((mCurrTexture != texture->getTexName()) || forceBind) 214 if ((mCurrTexture != texture->getTexName()) || forceBind)
202 { 215 {
203 activate(); 216 activate();
@@ -214,6 +227,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
214 setTextureFilteringOption(texture->mFilterOption); 227 setTextureFilteringOption(texture->mFilterOption);
215 } 228 }
216 } 229 }
230
217 return true; 231 return true;
218} 232}
219 233
diff --git a/linden/indra/llrender/llrender.h b/linden/indra/llrender/llrender.h
index 437c715..ce84e74 100644
--- a/linden/indra/llrender/llrender.h
+++ b/linden/indra/llrender/llrender.h
@@ -148,7 +148,7 @@ public:
148 148
149 // Binds the LLImageGL to this texture unit 149 // Binds the LLImageGL to this texture unit
150 // (automatically enables the unit for the LLImageGL's texture type) 150 // (automatically enables the unit for the LLImageGL's texture type)
151 bool bind(LLImageGL* texture, bool forceBind = false); 151 bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
152 152
153 // Binds a cubemap to this texture unit 153 // Binds a cubemap to this texture unit
154 // (automatically enables the texture unit for cubemaps) 154 // (automatically enables the texture unit for cubemaps)
diff --git a/linden/indra/llrender/llrendertarget.cpp b/linden/indra/llrender/llrendertarget.cpp
index b7f3177..4cf8451 100644
--- a/linden/indra/llrender/llrendertarget.cpp
+++ b/linden/indra/llrender/llrendertarget.cpp
@@ -139,7 +139,7 @@ void LLRenderTarget::addColorAttachment(U32 color_fmt)
139 139
140 U32 offset = mTex.size(); 140 U32 offset = mTex.size();
141 if (offset >= 4 || 141 if (offset >= 4 ||
142 offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)) 142 (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)))
143 { 143 {
144 llerrs << "Too many color attachments!" << llendl; 144 llerrs << "Too many color attachments!" << llendl;
145 } 145 }
@@ -608,7 +608,7 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
608 608
609 U32 offset = mTex.size(); 609 U32 offset = mTex.size();
610 if (offset >= 4 || 610 if (offset >= 4 ||
611 offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)) 611 (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers)))
612 { 612 {
613 llerrs << "Too many color attachments!" << llendl; 613 llerrs << "Too many color attachments!" << llendl;
614 } 614 }
diff --git a/linden/indra/newview/CMakeLists.txt b/linden/indra/newview/CMakeLists.txt
index e451465..d5b50cf 100644
--- a/linden/indra/newview/CMakeLists.txt
+++ b/linden/indra/newview/CMakeLists.txt
@@ -340,6 +340,10 @@ set(viewer_SOURCE_FILES
340 lltexturecache.cpp 340 lltexturecache.cpp
341 lltexturectrl.cpp 341 lltexturectrl.cpp
342 lltexturefetch.cpp 342 lltexturefetch.cpp
343 lltextureinfo.cpp
344 lltextureinfodetails.cpp
345 lltexturestats.cpp
346 lltexturestatsuploader.cpp
343 lltextureview.cpp 347 lltextureview.cpp
344 lltoolbar.cpp 348 lltoolbar.cpp
345 lltoolbrush.cpp 349 lltoolbrush.cpp
@@ -760,6 +764,10 @@ set(viewer_HEADER_FILES
760 lltexturecache.h 764 lltexturecache.h
761 lltexturectrl.h 765 lltexturectrl.h
762 lltexturefetch.h 766 lltexturefetch.h
767 lltextureinfo.h
768 lltextureinfodetails.h
769 lltexturestats.h
770 lltexturestatsuploader.h
763 lltextureview.h 771 lltextureview.h
764 lltool.h 772 lltool.h
765 lltoolbar.h 773 lltoolbar.h
diff --git a/linden/indra/newview/app_settings/settings.xml b/linden/indra/newview/app_settings/settings.xml
index f8594ad..9fea0d8 100644
--- a/linden/indra/newview/app_settings/settings.xml
+++ b/linden/indra/newview/app_settings/settings.xml
@@ -523,6 +523,17 @@
523 <key>Value</key> 523 <key>Value</key>
524 <integer>1</integer> 524 <integer>1</integer>
525 </map> 525 </map>
526 <key>AuditTexture</key>
527 <map>
528 <key>Comment</key>
529 <string>Enable texture auditting.</string>
530 <key>Persist</key>
531 <integer>1</integer>
532 <key>Type</key>
533 <string>Boolean</string>
534 <key>Value</key>
535 <integer>0</integer>
536 </map>
526 <key>AutoAcceptNewInventory</key> 537 <key>AutoAcceptNewInventory</key>
527 <map> 538 <map>
528 <key>Comment</key> 539 <key>Comment</key>
@@ -5811,6 +5822,28 @@
5811 <key>Value</key> 5822 <key>Value</key>
5812 <string>http://imprudenceviewer.org/splash/</string> 5823 <string>http://imprudenceviewer.org/splash/</string>
5813 </map> 5824 </map>
5825 <key>LogTextureDownloadsToViewerLog</key>
5826 <map>
5827 <key>Comment</key>
5828 <string>Send texture download details to the viewer log</string>
5829 <key>Persist</key>
5830 <integer>1</integer>
5831 <key>Type</key>
5832 <string>Boolean</string>
5833 <key>Value</key>
5834 <integer>0</integer>
5835 </map>
5836 <key>LogTextureDownloadsToSimulator</key>
5837 <map>
5838 <key>Comment</key>
5839 <string>Send a digest of texture info to the sim</string>
5840 <key>Persist</key>
5841 <integer>1</integer>
5842 <key>Type</key>
5843 <string>Boolean</string>
5844 <key>Value</key>
5845 <integer>0</integer>
5846 </map>
5814 <key>LosslessJ2CUpload</key> 5847 <key>LosslessJ2CUpload</key>
5815 <map> 5848 <map>
5816 <key>Comment</key> 5849 <key>Comment</key>
@@ -9776,6 +9809,17 @@
9776 <key>Value</key> 9809 <key>Value</key>
9777 <real>20.0</real> 9810 <real>20.0</real>
9778 </map> 9811 </map>
9812 <key>TextureLoggingThreshold</key>
9813 <map>
9814 <key>Comment</key>
9815 <string>Specifies the byte threshold at which texture download data should be sent to the sim.</string>
9816 <key>Persist</key>
9817 <integer>1</integer>
9818 <key>Type</key>
9819 <string>U32</string>
9820 <key>Value</key>
9821 <integer>1</integer>
9822 </map>
9779 <key>TextureMemory</key> 9823 <key>TextureMemory</key>
9780 <map> 9824 <map>
9781 <key>Comment</key> 9825 <key>Comment</key>
diff --git a/linden/indra/newview/llappviewer.cpp b/linden/indra/newview/llappviewer.cpp
index cdecaf4..a630beb 100644
--- a/linden/indra/newview/llappviewer.cpp
+++ b/linden/indra/newview/llappviewer.cpp
@@ -57,9 +57,12 @@
57#include "llares.h" 57#include "llares.h"
58#include "llcurl.h" 58#include "llcurl.h"
59#include "llfloatersnapshot.h" 59#include "llfloatersnapshot.h"
60#include "lltexturestats.h"
60#include "llviewerwindow.h" 61#include "llviewerwindow.h"
61#include "llviewerdisplay.h" 62#include "llviewerdisplay.h"
62#include "llviewermedia.h" 63#include "llviewermedia.h"
64
65
63#include "llviewermessage.h" 66#include "llviewermessage.h"
64#include "llviewerobjectlist.h" 67#include "llviewerobjectlist.h"
65#include "llworldmap.h" 68#include "llworldmap.h"
@@ -435,7 +438,7 @@ static void settings_modify()
435 LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] 438 LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
436 gDebugGL = gSavedSettings.getBOOL("RenderDebugGL"); 439 gDebugGL = gSavedSettings.getBOOL("RenderDebugGL");
437 gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline"); 440 gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
438 441 gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
439#if LL_VECTORIZE 442#if LL_VECTORIZE
440 if (gSysCPU.hasAltivec()) 443 if (gSysCPU.hasAltivec())
441 { 444 {
@@ -527,7 +530,7 @@ const std::string LLAppViewer::sPerAccountSettingsName = "PerAccount";
527const std::string LLAppViewer::sCrashSettingsName = "CrashSettings"; 530const std::string LLAppViewer::sCrashSettingsName = "CrashSettings";
528 531
529LLTextureCache* LLAppViewer::sTextureCache = NULL; 532LLTextureCache* LLAppViewer::sTextureCache = NULL;
530LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL; 533LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
531LLTextureFetch* LLAppViewer::sTextureFetch = NULL; 534LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
532 535
533LLAppViewer::LLAppViewer() : 536LLAppViewer::LLAppViewer() :
@@ -1512,14 +1515,14 @@ bool LLAppViewer::initThreads()
1512 LLWatchdog::getInstance()->init(watchdog_killer_callback); 1515 LLWatchdog::getInstance()->init(watchdog_killer_callback);
1513 } 1516 }
1514 1517
1515 LLVFSThread::initClass(enable_threads && true); 1518 LLVFSThread::initClass(enable_threads && false);
1516 LLLFSThread::initClass(enable_threads && true); 1519 LLLFSThread::initClass(enable_threads && false);
1517 1520
1518 // Image decoding 1521 // Image decoding
1519 LLAppViewer::sImageDecodeThread = new LLWorkerThread("ImageDecode", enable_threads && true); 1522 LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
1520 LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true); 1523 LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
1521 LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), enable_threads && false); 1524 LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
1522 LLImage::initClass(LLAppViewer::getImageDecodeThread()); 1525 LLImage::initClass();
1523 1526
1524 // *FIX: no error handling here! 1527 // *FIX: no error handling here!
1525 return true; 1528 return true;
diff --git a/linden/indra/newview/llappviewer.h b/linden/indra/newview/llappviewer.h
index ada5557..9d72457 100644
--- a/linden/indra/newview/llappviewer.h
+++ b/linden/indra/newview/llappviewer.h
@@ -34,7 +34,7 @@
34#define LL_LLAPPVIEWER_H 34#define LL_LLAPPVIEWER_H
35 35
36class LLTextureCache; 36class LLTextureCache;
37class LLWorkerThread; 37class LLImageDecodeThread;
38class LLTextureFetch; 38class LLTextureFetch;
39class LLWatchdogTimeout; 39class LLWatchdogTimeout;
40class LLCommandLineParser; 40class LLCommandLineParser;
@@ -91,7 +91,7 @@ public:
91 91
92 // Thread accessors 92 // Thread accessors
93 static LLTextureCache* getTextureCache() { return sTextureCache; } 93 static LLTextureCache* getTextureCache() { return sTextureCache; }
94 static LLWorkerThread* getImageDecodeThread() { return sImageDecodeThread; } 94 static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
95 static LLTextureFetch* getTextureFetch() { return sTextureFetch; } 95 static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
96 96
97 const std::string& getSerialNumber() { return mSerialNumber; } 97 const std::string& getSerialNumber() { return mSerialNumber; }
@@ -213,7 +213,7 @@ private:
213 213
214 // Thread objects. 214 // Thread objects.
215 static LLTextureCache* sTextureCache; 215 static LLTextureCache* sTextureCache;
216 static LLWorkerThread* sImageDecodeThread; 216 static LLImageDecodeThread* sImageDecodeThread;
217 static LLTextureFetch* sTextureFetch; 217 static LLTextureFetch* sTextureFetch;
218 218
219 S32 mNumSessions; 219 S32 mNumSessions;
diff --git a/linden/indra/newview/llassetuploadresponders.cpp b/linden/indra/newview/llassetuploadresponders.cpp
index dfd7403..700edb5 100644
--- a/linden/indra/newview/llassetuploadresponders.cpp
+++ b/linden/indra/newview/llassetuploadresponders.cpp
@@ -378,6 +378,14 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
378 } 378 }
379} 379}
380 380
381void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason)
382{
383 llinfos << "status: " << statusNum << " reason: " << reason << llendl;
384
385 // Invoke the original callback with an error result
386 LLTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
387 mBakedUploadData = NULL; // deleted in onTextureUploadComplete()
388}
381 389
382LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data, 390LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
383 const LLUUID& vfile_id, 391 const LLUUID& vfile_id,
diff --git a/linden/indra/newview/llassetuploadresponders.h b/linden/indra/newview/llassetuploadresponders.h
index 9ab571a..c08f299 100644
--- a/linden/indra/newview/llassetuploadresponders.h
+++ b/linden/indra/newview/llassetuploadresponders.h
@@ -83,6 +83,7 @@ public:
83 ~LLSendTexLayerResponder(); 83 ~LLSendTexLayerResponder();
84 84
85 virtual void uploadComplete(const LLSD& content); 85 virtual void uploadComplete(const LLSD& content);
86 virtual void error(U32 statusNum, const std::string& reason);
86 87
87 LLBakedUploadData * mBakedUploadData; 88 LLBakedUploadData * mBakedUploadData;
88}; 89};
diff --git a/linden/indra/newview/lldrawable.cpp b/linden/indra/newview/lldrawable.cpp
index 44a5de9..14aa38a 100644
--- a/linden/indra/newview/lldrawable.cpp
+++ b/linden/indra/newview/lldrawable.cpp
@@ -102,7 +102,7 @@ void LLDrawable::init()
102 mVObjp = NULL; 102 mVObjp = NULL;
103 // mFaces 103 // mFaces
104 mSpatialGroupp = NULL; 104 mSpatialGroupp = NULL;
105 mVisible = 0; 105 mVisible = sCurVisible - 2;//invisible for the current frame and the last frame.
106 mRadius = 0.f; 106 mRadius = 0.f;
107 107
108 mGeneration = -1; 108 mGeneration = -1;
@@ -949,7 +949,11 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
949 return retval; 949 return retval;
950} 950}
951 951
952 952BOOL LLDrawable::isRecentlyVisible() const
953{
954 //currently visible or visible in the previous frame.
955 return isVisible() || (mVisible == sCurVisible - 1) ;
956}
953BOOL LLDrawable::isVisible() const 957BOOL LLDrawable::isVisible() const
954{ 958{
955 if (mVisible == sCurVisible) 959 if (mVisible == sCurVisible)
diff --git a/linden/indra/newview/lldrawable.h b/linden/indra/newview/lldrawable.h
index 21cc0c5..71b75dc 100644
--- a/linden/indra/newview/lldrawable.h
+++ b/linden/indra/newview/lldrawable.h
@@ -50,7 +50,6 @@
50#include "llviewerobject.h" 50#include "llviewerobject.h"
51#include "llrect.h" 51#include "llrect.h"
52#include "llappviewer.h" // for gFrameTimeSeconds 52#include "llappviewer.h" // for gFrameTimeSeconds
53#include "llimagej2c.h"
54 53
55class LLCamera; 54class LLCamera;
56class LLDrawPool; 55class LLDrawPool;
@@ -81,7 +80,8 @@ public:
81 80
82 BOOL isLight() const; 81 BOOL isLight() const;
83 82
84 BOOL isVisible() const; 83 BOOL isVisible() const;
84 BOOL isRecentlyVisible() const;
85 virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE); 85 virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE);
86 86
87 87
diff --git a/linden/indra/newview/lldrawpool.cpp b/linden/indra/newview/lldrawpool.cpp
index 9f05ce3..e1bf1ed 100644
--- a/linden/indra/newview/lldrawpool.cpp
+++ b/linden/indra/newview/lldrawpool.cpp
@@ -279,7 +279,7 @@ S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage)
279 iter != face_list.end(); iter++) 279 iter != face_list.end(); iter++)
280 { 280 {
281 LLFace *facep = *iter; 281 LLFace *facep = *iter;
282 gGL.getTexUnit(stage)->bind(facep->getTexture()); 282 gGL.getTexUnit(stage)->bind(facep->getTexture(), TRUE);
283 gGL.getTexUnit(0)->activate(); 283 gGL.getTexUnit(0)->activate();
284 res += facep->renderIndexed(); 284 res += facep->renderIndexed();
285 } 285 }
@@ -481,14 +481,13 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
481 { 481 {
482 if (params.mTexture.notNull()) 482 if (params.mTexture.notNull())
483 { 483 {
484 gGL.getTexUnit(0)->bind(params.mTexture.get()); 484 gGL.getTexUnit(0)->bind(params.mTexture.get(), TRUE);
485 if (params.mTextureMatrix) 485 if (params.mTextureMatrix)
486 { 486 {
487 glMatrixMode(GL_TEXTURE); 487 glMatrixMode(GL_TEXTURE);
488 glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix); 488 glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
489 gPipeline.mTextureMatrixOps++; 489 gPipeline.mTextureMatrixOps++;
490 } 490 }
491 params.mTexture->addTextureStats(params.mVSize);
492 } 491 }
493 else 492 else
494 { 493 {
diff --git a/linden/indra/newview/lldrawpoolalpha.cpp b/linden/indra/newview/lldrawpoolalpha.cpp
index 7e470bd..4b552ac 100644
--- a/linden/indra/newview/lldrawpoolalpha.cpp
+++ b/linden/indra/newview/lldrawpoolalpha.cpp
@@ -219,7 +219,7 @@ void LLDrawPoolAlpha::render(S32 pass)
219 gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); 219 gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
220 glColor4f(1,0,0,1); 220 glColor4f(1,0,0,1);
221 LLViewerImage::sSmokeImagep->addTextureStats(1024.f*1024.f); 221 LLViewerImage::sSmokeImagep->addTextureStats(1024.f*1024.f);
222 gGL.getTexUnit(0)->bind(LLViewerImage::sSmokeImagep.get()); 222 gGL.getTexUnit(0)->bind(LLViewerImage::sSmokeImagep.get(), TRUE);
223 renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX | 223 renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
224 LLVertexBuffer::MAP_TEXCOORD0); 224 LLVertexBuffer::MAP_TEXCOORD0);
225 } 225 }
@@ -295,7 +295,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
295 { 295 {
296 gGL.getTexUnit(0)->activate(); 296 gGL.getTexUnit(0)->activate();
297 gGL.getTexUnit(0)->bind(params.mTexture.get()); 297 gGL.getTexUnit(0)->bind(params.mTexture.get());
298 params.mTexture->addTextureStats(params.mVSize); 298
299 if (params.mTextureMatrix) 299 if (params.mTextureMatrix)
300 { 300 {
301 glMatrixMode(GL_TEXTURE); 301 glMatrixMode(GL_TEXTURE);
diff --git a/linden/indra/newview/lldrawpoolbump.cpp b/linden/indra/newview/lldrawpoolbump.cpp
index 8f5858f..ff464f7 100644
--- a/linden/indra/newview/lldrawpoolbump.cpp
+++ b/linden/indra/newview/lldrawpoolbump.cpp
@@ -309,8 +309,8 @@ void LLDrawPoolBump::endRenderPass(S32 pass)
309void LLDrawPoolBump::beginShiny(bool invisible) 309void LLDrawPoolBump::beginShiny(bool invisible)
310{ 310{
311 LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); 311 LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
312 if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| 312 if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))||
313 invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) 313 (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
314 { 314 {
315 return; 315 return;
316 } 316 }
@@ -384,8 +384,8 @@ void LLDrawPoolBump::beginShiny(bool invisible)
384void LLDrawPoolBump::renderShiny(bool invisible) 384void LLDrawPoolBump::renderShiny(bool invisible)
385{ 385{
386 LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); 386 LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
387 if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| 387 if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))||
388 invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) 388 (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
389 { 389 {
390 return; 390 return;
391 } 391 }
@@ -411,8 +411,8 @@ void LLDrawPoolBump::renderShiny(bool invisible)
411void LLDrawPoolBump::endShiny(bool invisible) 411void LLDrawPoolBump::endShiny(bool invisible)
412{ 412{
413 LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); 413 LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY);
414 if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| 414 if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))||
415 invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) 415 (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
416 { 416 {
417 return; 417 return;
418 } 418 }
@@ -1221,7 +1221,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
1221 if (params.mTexture.notNull()) 1221 if (params.mTexture.notNull())
1222 { 1222 {
1223 gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get()); 1223 gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get());
1224 params.mTexture->addTextureStats(params.mVSize); 1224 //params.mTexture->addTextureStats(params.mVSize);
1225 } 1225 }
1226 else 1226 else
1227 { 1227 {
diff --git a/linden/indra/newview/lldrawpoolterrain.cpp b/linden/indra/newview/lldrawpoolterrain.cpp
index 2c644b0..cac5162 100644
--- a/linden/indra/newview/lldrawpoolterrain.cpp
+++ b/linden/indra/newview/lldrawpoolterrain.cpp
@@ -83,7 +83,7 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerImage *texturep) :
83 gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get()); 83 gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get());
84 m2DAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP); 84 m2DAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
85 85
86 mTexturep->setBoostLevel(LLViewerImage::BOOST_TERRAIN); 86 mTexturep->setBoostLevel(LLViewerImageBoostLevel::BOOST_TERRAIN);
87 87
88 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 88 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
89} 89}
@@ -170,7 +170,7 @@ void LLDrawPoolTerrain::render(S32 pass)
170 LLVLComposition *compp = regionp->getComposition(); 170 LLVLComposition *compp = regionp->getComposition();
171 for (S32 i = 0; i < 4; i++) 171 for (S32 i = 0; i < 4; i++)
172 { 172 {
173 compp->mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); 173 compp->mDetailTextures[i]->setBoostLevel(LLViewerImageBoostLevel::BOOST_TERRAIN);
174 compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area 174 compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area
175 } 175 }
176 176
diff --git a/linden/indra/newview/lldrawpooltree.cpp b/linden/indra/newview/lldrawpooltree.cpp
index 2f2b072..46cd2d5 100644
--- a/linden/indra/newview/lldrawpooltree.cpp
+++ b/linden/indra/newview/lldrawpooltree.cpp
@@ -247,7 +247,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
247 LLGLState normalize(GL_NORMALIZE, TRUE); 247 LLGLState normalize(GL_NORMALIZE, TRUE);
248 248
249 // Bind the texture for this tree. 249 // Bind the texture for this tree.
250 gGL.getTexUnit(sDiffTex)->bind(mTexturep.get()); 250 gGL.getTexUnit(sDiffTex)->bind(mTexturep.get(), TRUE);
251 251
252 U32 indices_drawn = 0; 252 U32 indices_drawn = 0;
253 253
diff --git a/linden/indra/newview/lldynamictexture.cpp b/linden/indra/newview/lldynamictexture.cpp
index 62fcf60..61f5a89 100644
--- a/linden/indra/newview/lldynamictexture.cpp
+++ b/linden/indra/newview/lldynamictexture.cpp
@@ -111,7 +111,7 @@ void LLDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum prima
111 mTexture->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes); 111 mTexture->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes);
112 } 112 }
113// llinfos << "ALLOCATING " << (mWidth*mHeight*mComponents)/1024 << "K" << llendl; 113// llinfos << "ALLOCATING " << (mWidth*mHeight*mComponents)/1024 << "K" << llendl;
114 mTexture->createGLTexture(0, raw_image); 114 mTexture->createGLTexture(0, raw_image, 0, TRUE, LLViewerImageBoostLevel::DYNAMIC_TEX);
115 mTexture->setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP); 115 mTexture->setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP);
116 mTexture->setGLTextureCreated(false); 116 mTexture->setGLTextureCreated(false);
117} 117}
diff --git a/linden/indra/newview/llface.cpp b/linden/indra/newview/llface.cpp
index 69edcca..dab1dac 100644
--- a/linden/indra/newview/llface.cpp
+++ b/linden/indra/newview/llface.cpp
@@ -52,6 +52,7 @@
52#include "llvovolume.h" 52#include "llvovolume.h"
53#include "pipeline.h" 53#include "pipeline.h"
54#include "llviewerregion.h" 54#include "llviewerregion.h"
55#include "llviewerwindow.h"
55 56
56#define LL_MAX_INDICES_COUNT 1000000 57#define LL_MAX_INDICES_COUNT 1000000
57 58
@@ -174,11 +175,19 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
174 mLastGeomIndex = mGeomIndex; 175 mLastGeomIndex = mGeomIndex;
175 mLastIndicesCount = mIndicesCount; 176 mLastIndicesCount = mIndicesCount;
176 mLastIndicesIndex = mIndicesIndex; 177 mLastIndicesIndex = mIndicesIndex;
178
179 mImportanceToCamera = 0.f ;
180 mBoundingSphereRadius = 0.0f ;
177} 181}
178 182
179 183
180void LLFace::destroy() 184void LLFace::destroy()
181{ 185{
186 if(mTexture.notNull())
187 {
188 mTexture->removeFace(this) ;
189 }
190
182 if (mDrawPoolp) 191 if (mDrawPoolp)
183 { 192 {
184 mDrawPoolp->removeFace(this); 193 mDrawPoolp->removeFace(this);
@@ -199,7 +208,7 @@ void LLFace::destroy()
199 } 208 }
200 } 209 }
201 } 210 }
202 211
203 setDrawInfo(NULL); 212 setDrawInfo(NULL);
204 213
205 mDrawablep = NULL; 214 mDrawablep = NULL;
@@ -247,9 +256,29 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerImage *texturep)
247 } 256 }
248 mDrawPoolp = new_pool; 257 mDrawPoolp = new_pool;
249 } 258 }
250 mTexture = texturep; 259
260 setTexture(texturep) ;
251} 261}
252 262
263void LLFace::setTexture(LLViewerImage* tex)
264{
265 if(mTexture == tex)
266 {
267 return ;
268 }
269
270 if(mTexture.notNull())
271 {
272 mTexture->removeFace(this) ;
273 }
274
275 mTexture = tex ;
276
277 if(mTexture.notNull())
278 {
279 mTexture->addFace(this) ;
280 }
281}
253 282
254void LLFace::setTEOffset(const S32 te_offset) 283void LLFace::setTEOffset(const S32 te_offset)
255{ 284{
@@ -698,7 +727,9 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
698 } 727 }
699 728
700 mCenterLocal = (newMin+newMax)*0.5f; 729 mCenterLocal = (newMin+newMax)*0.5f;
701 730 LLVector3 tmp = (newMin - newMax) ;
731 mBoundingSphereRadius = tmp.length() * 0.5f ;
732
702 updateCenterAgent(); 733 updateCenterAgent();
703 } 734 }
704 735
@@ -865,6 +896,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
865 { 896 {
866 mVertexBuffer->getBinormalStrider(binormals, mGeomIndex); 897 mVertexBuffer->getBinormalStrider(binormals, mGeomIndex);
867 } 898 }
899
868 if (rebuild_tcoord) 900 if (rebuild_tcoord)
869 { 901 {
870 mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); 902 mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex);
@@ -959,7 +991,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
959 0.75f 991 0.75f
960 }; 992 };
961 993
962 if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || LLPipeline::sRenderBump && tep->getShiny())) 994 if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || (LLPipeline::sRenderBump && tep->getShiny())))
963 { 995 {
964 color.mV[3] = U8 (alpha[tep->getShiny()] * 255); 996 color.mV[3] = U8 (alpha[tep->getShiny()] * 255);
965 } 997 }
@@ -1147,6 +1179,159 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
1147 return TRUE; 1179 return TRUE;
1148} 1180}
1149 1181
1182const F32 LEAST_IMPORTANCE = 0.05f ;
1183const F32 LEAST_IMPORTANCE_FOR_LARGE_IMAGE = 0.3f ;
1184
1185F32 LLFace::getTextureVirtualSize()
1186{
1187 F32 radius;
1188 F32 cos_angle_to_view_dir;
1189 mPixelArea = calcPixelArea(cos_angle_to_view_dir, radius);
1190
1191 if (mPixelArea <= 0)
1192 {
1193 return 0.f;
1194 }
1195
1196 //get area of circle in texture space
1197 LLVector2 tdim = mTexExtents[1] - mTexExtents[0];
1198 F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f;
1199 if (texel_area <= 0)
1200 {
1201 // Probably animated, use default
1202 texel_area = 1.f;
1203 }
1204
1205 F32 face_area;
1206 if (mVObjp->isSculpted() && texel_area > 1.f)
1207 {
1208 //sculpts can break assumptions about texel area
1209 face_area = mPixelArea;
1210 }
1211 else
1212 {
1213 //apply texel area to face area to get accurate ratio
1214 //face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
1215 face_area = mPixelArea / llclamp(texel_area, 0.015625f, 1024.f);
1216 }
1217
1218 if(face_area > LLViewerImage::sMaxSmallImageSize)
1219 {
1220 if(mImportanceToCamera < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
1221 {
1222 face_area = LLViewerImage::sMaxSmallImageSize ;
1223 }
1224 else if(face_area > LLViewerImage::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
1225 {
1226 if(mImportanceToCamera < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
1227 {
1228 face_area = LLViewerImage::sMinLargeImageSize ;
1229 }
1230 else if(mTexture.notNull() && mTexture->isLargeImage())
1231 {
1232 face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
1233 }
1234 }
1235 }
1236
1237 return face_area;
1238}
1239
1240F32 LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
1241{
1242 //get area of circle around face
1243 LLVector3 center = getPositionAgent();
1244 LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f;
1245
1246 LLVector3 lookAt = center - LLViewerCamera::getInstance()->getOrigin();
1247 F32 dist = lookAt.normVec() ;
1248
1249 //get area of circle around node
1250 F32 app_angle = atanf(size.length()/dist);
1251 radius = app_angle*LLDrawable::sCurPixelAngle;
1252 F32 face_area = radius*radius * 3.14159f;
1253
1254 if(dist < mBoundingSphereRadius) //camera is very close
1255 {
1256 cos_angle_to_view_dir = 1.0f ;
1257 mImportanceToCamera = 1.0f ;
1258 }
1259 else
1260 {
1261 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;
1262 mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ;
1263 }
1264
1265 return face_area ;
1266}
1267
1268//the projection of the face partially overlaps with the screen
1269F32 LLFace::adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius )
1270{
1271 F32 screen_radius = (F32)llmax(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()) ;
1272 F32 center_angle = acosf(cos_angle_to_view_dir) ;
1273 F32 d = center_angle * LLDrawable::sCurPixelAngle ;
1274
1275 if(d + radius > screen_radius + 5.f)
1276 {
1277 //----------------------------------------------
1278 //calculate the intersection area of two circles
1279 //F32 radius_square = radius * radius ;
1280 //F32 d_square = d * d ;
1281 //F32 screen_radius_square = screen_radius * screen_radius ;
1282 //face_area =
1283 // radius_square * acosf((d_square + radius_square - screen_radius_square)/(2 * d * radius)) +
1284 // screen_radius_square * acosf((d_square + screen_radius_square - radius_square)/(2 * d * screen_radius)) -
1285 // 0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ;
1286 //----------------------------------------------
1287
1288 //the above calculation is too expensive
1289 //the below is a good estimation: bounding box of the bounding sphere:
1290 F32 alpha = 0.5f * (radius + screen_radius - d) / radius ;
1291 alpha = llclamp(alpha, 0.f, 1.f) ;
1292 return alpha * alpha ;
1293 }
1294 return 1.0f ;
1295}
1296
1297const S8 FACE_IMPORTANCE_LEVEL = 4 ;
1298const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL][2] = //{distance, importance_weight}
1299 {{16.1f, 1.0f}, {32.1f, 0.5f}, {48.1f, 0.2f}, {96.1f, 0.05f} } ;
1300const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[FACE_IMPORTANCE_LEVEL][2] = //{cos(angle), importance_weight}
1301 {{0.985f /*cos(10 degrees)*/, 1.0f}, {0.94f /*cos(20 degrees)*/, 0.8f}, {0.866f /*cos(30 degrees)*/, 0.64f}, {0.0f, 0.36f}} ;
1302
1303//static
1304F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
1305{
1306 F32 importance = 0.f ;
1307
1308 if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() &&
1309 dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0])
1310 {
1311 F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
1312 F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
1313
1314 if(camera_moving_speed > 10.0f || camera_angular_speed > 1.0f)
1315 {
1316 //if camera moves or rotates too fast, ignore the importance factor
1317 return 0.f ;
1318 }
1319
1320 //F32 camera_relative_speed = camera_moving_speed * (lookAt * LLViewerCamera::getInstance()->getVelocityDir()) ;
1321
1322 S32 i = 0 ;
1323 for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i);
1324 i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
1325 F32 dist_factor = FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][1] ;
1326
1327 for(i = 0; i < FACE_IMPORTANCE_LEVEL && cos_angle_to_view_dir < FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][0] ; ++i) ;
1328 i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
1329 importance = dist_factor * FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][1] ;
1330 }
1331
1332 return importance ;
1333}
1334
1150BOOL LLFace::verify(const U32* indices_array) const 1335BOOL LLFace::verify(const U32* indices_array) const
1151{ 1336{
1152 BOOL ok = TRUE; 1337 BOOL ok = TRUE;
diff --git a/linden/indra/newview/llface.h b/linden/indra/newview/llface.h
index 4a551ff..5e422b4 100644
--- a/linden/indra/newview/llface.h
+++ b/linden/indra/newview/llface.h
@@ -88,7 +88,7 @@ public:
88 U16 getGeomIndex() const { return mGeomIndex; } // index into draw pool 88 U16 getGeomIndex() const { return mGeomIndex; } // index into draw pool
89 U16 getGeomStart() const { return mGeomIndex; } // index into draw pool 89 U16 getGeomStart() const { return mGeomIndex; } // index into draw pool
90 LLViewerImage* getTexture() const { return mTexture; } 90 LLViewerImage* getTexture() const { return mTexture; }
91 void setTexture(LLViewerImage* tex) { mTexture = tex; } 91 void setTexture(LLViewerImage* tex) ;
92 LLXformMatrix* getXform() const { return mXform; } 92 LLXformMatrix* getXform() const { return mXform; }
93 BOOL hasGeometry() const { return mGeomCount > 0; } 93 BOOL hasGeometry() const { return mGeomCount > 0; }
94 LLVector3 getPositionAgent() const; 94 LLVector3 getPositionAgent() const;
@@ -186,7 +186,14 @@ public:
186 void setIndicesIndex(S32 idx) { mIndicesIndex = idx; } 186 void setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
187 void setDrawInfo(LLDrawInfo* draw_info); 187 void setDrawInfo(LLDrawInfo* draw_info);
188 188
189protected: 189 F32 getTextureVirtualSize() ;
190 F32 getImportanceToCamera()const {return mImportanceToCamera ;}
191
192private:
193 F32 adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius );
194 F32 calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) ;
195public:
196 static F32 calcImportanceToCamera(F32 to_view_dir, F32 dist);
190 197
191public: 198public:
192 199
@@ -202,7 +209,7 @@ public:
202 LLMatrix4* mTextureMatrix; 209 LLMatrix4* mTextureMatrix;
203 LLDrawInfo* mDrawInfo; 210 LLDrawInfo* mDrawInfo;
204 211
205protected: 212private:
206 friend class LLGeometryManager; 213 friend class LLGeometryManager;
207 friend class LLVolumeGeometryManager; 214 friend class LLVolumeGeometryManager;
208 215
@@ -231,7 +238,13 @@ protected:
231 S32 mReferenceIndex; 238 S32 mReferenceIndex;
232 F32 mVSize; 239 F32 mVSize;
233 F32 mPixelArea; 240 F32 mPixelArea;
234 241
242 //importance factor, in the range [0, 1.0].
243 //1.0: the most important.
244 //based on the distance from the face to the view point and the angle from the face center to the view direction.
245 F32 mImportanceToCamera ;
246 F32 mBoundingSphereRadius ;
247
235protected: 248protected:
236 static BOOL sSafeRenderSelect; 249 static BOOL sSafeRenderSelect;
237 250
diff --git a/linden/indra/newview/llfloaterassetbrowser.cpp b/linden/indra/newview/llfloaterassetbrowser.cpp
index cb2412d..af81c4a 100644
--- a/linden/indra/newview/llfloaterassetbrowser.cpp
+++ b/linden/indra/newview/llfloaterassetbrowser.cpp
@@ -130,7 +130,7 @@ void LLFloaterAssetBrowser::createThumbnails()
130 for(S32 i = 0; i < items.count(); i++) 130 for(S32 i = 0; i < items.count(); i++)
131 { 131 {
132 mTextureAssets[i].mTexturep = gImageList.getImage(mTextureAssets[i].mAssetUUID, MIPMAP_YES, IMMEDIATE_NO); 132 mTextureAssets[i].mTexturep = gImageList.getImage(mTextureAssets[i].mAssetUUID, MIPMAP_YES, IMMEDIATE_NO);
133 mTextureAssets[i].mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); 133 mTextureAssets[i].mTexturep->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW);
134 //mTextureAssets[i].mTexturep->processTextureStats(); 134 //mTextureAssets[i].mTexturep->processTextureStats();
135 } 135 }
136 136
diff --git a/linden/indra/newview/llfloaterreporter.cpp b/linden/indra/newview/llfloaterreporter.cpp
index 31d658b..7a5f2ba 100644
--- a/linden/indra/newview/llfloaterreporter.cpp
+++ b/linden/indra/newview/llfloaterreporter.cpp
@@ -952,8 +952,8 @@ void LLFloaterReporter::takeScreenshot()
952 mResourceDatap->mAssetInfo.mType); 952 mResourceDatap->mAssetInfo.mType);
953 953
954 // store in the image list so it doesn't try to fetch from the server 954 // store in the image list so it doesn't try to fetch from the server
955 LLPointer<LLViewerImage> image_in_list = new LLViewerImage(mResourceDatap->mAssetInfo.mUuid, TRUE); 955 LLPointer<LLViewerImage> image_in_list = new LLViewerImage(mResourceDatap->mAssetInfo.mUuid);
956 image_in_list->createGLTexture(0, raw); 956 image_in_list->createGLTexture(0, raw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
957 gImageList.addImage(image_in_list); 957 gImageList.addImage(image_in_list);
958 958
959 // the texture picker then uses that texture 959 // the texture picker then uses that texture
diff --git a/linden/indra/newview/llpreviewtexture.cpp b/linden/indra/newview/llpreviewtexture.cpp
index 13e7cca..dcbb669 100644
--- a/linden/indra/newview/llpreviewtexture.cpp
+++ b/linden/indra/newview/llpreviewtexture.cpp
@@ -224,6 +224,11 @@ void LLPreviewTexture::draw()
224 // Pump the texture priority 224 // Pump the texture priority
225 F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() ); 225 F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() );
226 mImage->addTextureStats( pixel_area ); 226 mImage->addTextureStats( pixel_area );
227 if(pixel_area > 0.f)
228 {
229 //boost the previewed image priority to the highest to make it to get loaded first.
230 mImage->setAdditionalDecodePriority(1.0f) ;
231 }
227 232
228 // Don't bother decoding more than we can display, unless 233 // Don't bother decoding more than we can display, unless
229 // we're loading the full image. 234 // we're loading the full image.
@@ -482,7 +487,8 @@ void LLPreviewTexture::updateDimensions()
482void LLPreviewTexture::loadAsset() 487void LLPreviewTexture::loadAsset()
483{ 488{
484 mImage = gImageList.getImage(mImageID, MIPMAP_TRUE, FALSE); 489 mImage = gImageList.getImage(mImageID, MIPMAP_TRUE, FALSE);
485 mImage->setBoostLevel(LLViewerImage::BOOST_PREVIEW); 490 mImage->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW);
491 mImage->forceToSaveRawImage(0) ;
486 mAssetStatus = PREVIEW_ASSET_LOADING; 492 mAssetStatus = PREVIEW_ASSET_LOADING;
487} 493}
488 494
diff --git a/linden/indra/newview/llstartup.cpp b/linden/indra/newview/llstartup.cpp
index 143aa34..7a7e023 100644
--- a/linden/indra/newview/llstartup.cpp
+++ b/linden/indra/newview/llstartup.cpp
@@ -59,6 +59,7 @@
59#include "llfocusmgr.h" 59#include "llfocusmgr.h"
60#include "llhttpsender.h" 60#include "llhttpsender.h"
61#include "imageids.h" 61#include "imageids.h"
62#include "llimageworker.h"
62#include "lllandmark.h" 63#include "lllandmark.h"
63#include "llloginflags.h" 64#include "llloginflags.h"
64#include "llmd5.h" 65#include "llmd5.h"
@@ -3468,7 +3469,7 @@ void init_start_screen(S32 location_id)
3468 } 3469 }
3469 3470
3470 raw->expandToPowerOfTwo(); 3471 raw->expandToPowerOfTwo();
3471 gStartImageGL->createGLTexture(0, raw); 3472 gStartImageGL->createGLTexture(0, raw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
3472} 3473}
3473 3474
3474 3475
diff --git a/linden/indra/newview/lltexlayer.cpp b/linden/indra/newview/lltexlayer.cpp
index 424c525..968c496 100644
--- a/linden/indra/newview/lltexlayer.cpp
+++ b/linden/indra/newview/lltexlayer.cpp
@@ -115,7 +115,6 @@ LLTexLayerSetBuffer::~LLTexLayerSetBuffer()
115 if( mBumpTex.notNull()) 115 if( mBumpTex.notNull())
116 { 116 {
117 mBumpTex = NULL ; 117 mBumpTex = NULL ;
118 LLImageGL::sGlobalTextureMemoryInBytes -= mWidth * mHeight * 4;
119 LLTexLayerSetBuffer::sGLBumpByteCount -= mWidth * mHeight * 4; 118 LLTexLayerSetBuffer::sGLBumpByteCount -= mWidth * mHeight * 4;
120 } 119 }
121} 120}
@@ -132,7 +131,7 @@ void LLTexLayerSetBuffer::destroyGLTexture()
132 if( mBumpTex.notNull() ) 131 if( mBumpTex.notNull() )
133 { 132 {
134 mBumpTex = NULL ; 133 mBumpTex = NULL ;
135 LLImageGL::sGlobalTextureMemoryInBytes -= mWidth * mHeight * 4; 134 //LLImageGL::sGlobalTextureMemoryInBytes -= mWidth * mHeight * 4;
136 LLTexLayerSetBuffer::sGLBumpByteCount -= mWidth * mHeight * 4; 135 LLTexLayerSetBuffer::sGLBumpByteCount -= mWidth * mHeight * 4;
137 } 136 }
138 137
@@ -165,6 +164,14 @@ void LLTexLayerSetBuffer::createBumpTexture()
165 164
166 LLImageGL::sGlobalTextureMemoryInBytes += mWidth * mHeight * 4; 165 LLImageGL::sGlobalTextureMemoryInBytes += mWidth * mHeight * 4;
167 LLTexLayerSetBuffer::sGLBumpByteCount += mWidth * mHeight * 4; 166 LLTexLayerSetBuffer::sGLBumpByteCount += mWidth * mHeight * 4;
167
168 if(gAuditTexture)
169 {
170 mBumpTex->setCategory(LLViewerImageBoostLevel::TEXLAYER_BUMP) ;
171 mBumpTex->setTextureSize(mWidth * mHeight * 4) ;
172 mBumpTex->setComponents(4) ;
173 mBumpTex->incTextureCounter() ;
174 }
168 } 175 }
169} 176}
170 177
@@ -619,7 +626,7 @@ void LLTexLayerSetBuffer::bindBumpTexture( U32 stage )
619 if( mLastBindTime != LLImageGL::sLastFrameTime ) 626 if( mLastBindTime != LLImageGL::sLastFrameTime )
620 { 627 {
621 mLastBindTime = LLImageGL::sLastFrameTime; 628 mLastBindTime = LLImageGL::sLastFrameTime;
622 LLImageGL::updateBoundTexMem(mWidth * mHeight * 4); 629 mBumpTex->updateBoundTexMem();
623 } 630 }
624 } 631 }
625 else 632 else
@@ -833,7 +840,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
833 if( image_gl ) 840 if( image_gl )
834 { 841 {
835 LLGLSUIDefault gls_ui; 842 LLGLSUIDefault gls_ui;
836 gGL.getTexUnit(0)->bind(image_gl); 843 gGL.getTexUnit(0)->bind(image_gl, TRUE);
837 gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); 844 gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
838 gl_rect_2d_simple_tex( width, height ); 845 gl_rect_2d_simple_tex( width, height );
839 } 846 }
@@ -1418,7 +1425,7 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height )
1418 1425
1419 LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode(); 1426 LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode();
1420 1427
1421 gGL.getTexUnit(0)->bind(image_gl); 1428 gGL.getTexUnit(0)->bind(image_gl, TRUE);
1422 gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); 1429 gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
1423 1430
1424 gl_rect_2d_simple_tex( width, height ); 1431 gl_rect_2d_simple_tex( width, height );
@@ -1440,7 +1447,7 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height )
1440 LLImageGL* image_gl = gTexStaticImageList.getImageGL( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); 1447 LLImageGL* image_gl = gTexStaticImageList.getImageGL( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
1441 if( image_gl ) 1448 if( image_gl )
1442 { 1449 {
1443 gGL.getTexUnit(0)->bind(image_gl); 1450 gGL.getTexUnit(0)->bind(image_gl, TRUE);
1444 gl_rect_2d_simple_tex( width, height ); 1451 gl_rect_2d_simple_tex( width, height );
1445 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 1452 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
1446 } 1453 }
@@ -1617,7 +1624,7 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4
1617 1624
1618 LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode(); 1625 LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode();
1619 1626
1620 gGL.getTexUnit(0)->bind(image_gl); 1627 gGL.getTexUnit(0)->bind(image_gl, TRUE);
1621 gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); 1628 gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
1622 1629
1623 gl_rect_2d_simple_tex( width, height ); 1630 gl_rect_2d_simple_tex( width, height );
@@ -1643,7 +1650,7 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4
1643 ( (image_gl->getComponents() == 1) && getInfo()->mStaticImageIsMask ) ) 1650 ( (image_gl->getComponents() == 1) && getInfo()->mStaticImageIsMask ) )
1644 { 1651 {
1645 LLGLSNoAlphaTest gls_no_alpha_test; 1652 LLGLSNoAlphaTest gls_no_alpha_test;
1646 gGL.getTexUnit(0)->bind(image_gl); 1653 gGL.getTexUnit(0)->bind(image_gl, TRUE);
1647 gl_rect_2d_simple_tex( width, height ); 1654 gl_rect_2d_simple_tex( width, height );
1648 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 1655 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
1649 } 1656 }
@@ -2088,14 +2095,14 @@ BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height )
2088 // Create the GL texture, and then hang onto it for future use. 2095 // Create the GL texture, and then hang onto it for future use.
2089 if( mNeedsCreateTexture ) 2096 if( mNeedsCreateTexture )
2090 { 2097 {
2091 mCachedProcessedImageGL->createGLTexture(0, mStaticImageRaw); 2098 mCachedProcessedImageGL->createGLTexture(0, mStaticImageRaw, 0, TRUE, LLViewerImageBoostLevel::TEXLAYER_CACHE);
2092 mNeedsCreateTexture = FALSE; 2099 mNeedsCreateTexture = FALSE;
2093 gGL.getTexUnit(0)->bind(mCachedProcessedImageGL); 2100 gGL.getTexUnit(0)->bind(mCachedProcessedImageGL);
2094 mCachedProcessedImageGL->setAddressMode(LLTexUnit::TAM_CLAMP); 2101 mCachedProcessedImageGL->setAddressMode(LLTexUnit::TAM_CLAMP);
2095 } 2102 }
2096 2103
2097 LLGLSNoAlphaTest gls_no_alpha_test; 2104 LLGLSNoAlphaTest gls_no_alpha_test;
2098 gGL.getTexUnit(0)->bind(mCachedProcessedImageGL); 2105 gGL.getTexUnit(0)->bind(mCachedProcessedImageGL, TRUE);
2099 gl_rect_2d_simple_tex( width, height ); 2106 gl_rect_2d_simple_tex( width, height );
2100 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 2107 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
2101 stop_glerror(); 2108 stop_glerror();
@@ -2543,7 +2550,7 @@ LLImageGL* LLTexStaticImageList::getImageGL(const std::string& file_name, BOOL i
2543 // that once an image is a mask it's always a mask. 2550 // that once an image is a mask it's always a mask.
2544 image_gl->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); 2551 image_gl->setExplicitFormat( GL_ALPHA8, GL_ALPHA );
2545 } 2552 }
2546 image_gl->createGLTexture(0, image_raw); 2553 image_gl->createGLTexture(0, image_raw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
2547 2554
2548 gGL.getTexUnit(0)->bind(image_gl); 2555 gGL.getTexUnit(0)->bind(image_gl);
2549 image_gl->setAddressMode(LLTexUnit::TAM_CLAMP); 2556 image_gl->setAddressMode(LLTexUnit::TAM_CLAMP);
diff --git a/linden/indra/newview/lltexturecache.cpp b/linden/indra/newview/lltexturecache.cpp
index 9c3bed2..e0bef61 100644
--- a/linden/indra/newview/lltexturecache.cpp
+++ b/linden/indra/newview/lltexturecache.cpp
@@ -43,11 +43,18 @@
43// Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout 43// Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout
44#include "llappviewer.h" 44#include "llappviewer.h"
45 45
46#define USE_LFS_READ 0 46// Cache organization:
47#define USE_LFS_WRITE 0 47// cache/texture.entries
48 48// Unordered array of Entry structs
49// Note: first 4 bytes store file size, rest is j2c data 49// cache/texture.cache
50const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024; 50// First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order
51// Entry size same as header packet, so we're not 0-padding unless whole image is contained in header.
52// cache/textures/[0-F]/UUID.texture
53// Actual texture body files
54
55const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;
56const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
57const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
51 58
52class LLTextureCacheWorker : public LLWorkerClass 59class LLTextureCacheWorker : public LLWorkerClass
53{ 60{
@@ -309,93 +316,74 @@ void LLTextureCacheWorker::startWork(S32 param)
309{ 316{
310} 317}
311 318
319// This is where a texture is read from the cache system (header and body)
320// Current assumption are:
321// - the whole data are in a raw form, will be stored at mReadData
322// - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
323// - the code supports offset reading but this is actually never exercised in the viewer
312bool LLTextureCacheRemoteWorker::doRead() 324bool LLTextureCacheRemoteWorker::doRead()
313{ 325{
326 bool done = false;
327 S32 idx = -1;
328
314 S32 local_size = 0; 329 S32 local_size = 0;
315 std::string local_filename; 330 std::string local_filename;
316 331
332 // First state / stage : find out if the file is local
317 if (mState == INIT) 333 if (mState == INIT)
318 { 334 {
319 std::string filename = mCache->getLocalFileName(mID); 335 std::string filename = mCache->getLocalFileName(mID);
320 local_filename = filename + ".j2c"; 336 // Is it a JPEG2000 file?
321 local_size = LLAPRFile::size(local_filename);
322 if (local_size == 0)
323 { 337 {
324 local_filename = filename + ".tga"; 338 local_filename = filename + ".j2c";
325 local_size = LLAPRFile::size(local_filename); 339 local_size = LLAPRFile::size(local_filename);
326 if (local_size > 0) 340 if (local_size > 0)
327 { 341 {
328 mImageFormat = IMG_CODEC_TGA; 342 mImageFormat = IMG_CODEC_J2C;
329 mDataSize = local_size; // Only a complete .tga file is valid
330 } 343 }
331 } 344 }
332 if (local_size > 0) 345 // If not, is it a jpeg file?
333 { 346 if (local_size == 0)
334 mState = LOCAL;
335 }
336 else
337 {
338 mState = CACHE;
339 }
340 }
341
342 if (mState == LOCAL)
343 {
344#if USE_LFS_READ
345 if (mFileHandle == LLLFSThread::nullHandle())
346 { 347 {
347 mImageLocal = TRUE; 348 local_filename = filename + ".jpg";
348 mImageSize = local_size; 349 local_size = LLAPRFile::size(local_filename);
349 if (!mDataSize || mDataSize + mOffset > local_size) 350 if (local_size > 0)
350 {
351 mDataSize = local_size - mOffset;
352 }
353 if (mDataSize <= 0)
354 { 351 {
355 // no more data to read 352 mImageFormat = IMG_CODEC_JPEG;
356 mDataSize = 0; 353 mDataSize = local_size; // Only a complete .jpg file is valid
357 return true;
358 } 354 }
359 mReadData = new U8[mDataSize];
360 mBytesRead = -1;
361 mBytesToRead = mDataSize;
362 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
363 mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
364 new ReadResponder(mCache, mRequestHandle));
365 return false;
366 } 355 }
367 else 356 // Hmm... What about a targa file? (used for UI texture mostly)
357 if (local_size == 0)
368 { 358 {
369 if (mBytesRead >= 0) 359 local_filename = filename + ".tga";
370 { 360 local_size = LLAPRFile::size(local_filename);
371 if (mBytesRead != mBytesToRead) 361 if (local_size > 0)
372 {
373// llwarns << "Error reading file from local cache: " << local_filename
374// << " Bytes: " << mDataSize << " Offset: " << mOffset
375// << " / " << mDataSize << llendl;
376 mDataSize = 0; // failed
377 delete[] mReadData;
378 mReadData = NULL;
379 }
380 return true;
381 }
382 else
383 { 362 {
384 return false; 363 mImageFormat = IMG_CODEC_TGA;
364 mDataSize = local_size; // Only a complete .tga file is valid
385 } 365 }
386 } 366 }
387#else 367 // Determine the next stage: if we found a file, then LOCAL else CACHE
368 mState = (local_size > 0 ? LOCAL : CACHE);
369 }
370
371 // Second state / stage : if the file is local, load it and leave
372 if (!done && (mState == LOCAL))
373 {
374 llassert(local_size != 0); // we're assuming there is a non empty local file here...
388 if (!mDataSize || mDataSize > local_size) 375 if (!mDataSize || mDataSize > local_size)
389 { 376 {
390 mDataSize = local_size; 377 mDataSize = local_size;
391 } 378 }
379 // Allocate read buffer
392 mReadData = new U8[mDataSize]; 380 mReadData = new U8[mDataSize];
393 S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize); 381 S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize);
394 if (bytes_read != mDataSize) 382 if (bytes_read != mDataSize)
395 { 383 {
396// llwarns << "Error reading file from local cache: " << local_filename 384 llwarns << "Error reading file from local cache: " << local_filename
397// << " Bytes: " << mDataSize << " Offset: " << mOffset 385 << " Bytes: " << mDataSize << " Offset: " << mOffset
398// << " / " << mDataSize << llendl; 386 << " / " << mDataSize << llendl;
399 mDataSize = 0; 387 mDataSize = 0;
400 delete[] mReadData; 388 delete[] mReadData;
401 mReadData = NULL; 389 mReadData = NULL;
@@ -405,403 +393,273 @@ bool LLTextureCacheRemoteWorker::doRead()
405 mImageSize = local_size; 393 mImageSize = local_size;
406 mImageLocal = TRUE; 394 mImageLocal = TRUE;
407 } 395 }
408 return true; 396 // We're done...
409#endif 397 done = true;
410 } 398 }
411 399
412 S32 idx = -1; 400 // Second state / stage : identify the cache or not...
413 401 if (!done && (mState == CACHE))
414 if (mState == CACHE)
415 { 402 {
416 llassert_always(mImageSize == 0); 403 idx = mCache->getHeaderCacheEntry(mID, mImageSize);
417 idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize); 404 if (idx < 0)
418 if (idx >= 0 && mImageSize > mOffset)
419 { 405 {
420 llassert_always(mImageSize > 0); 406 // The texture is *not* cached. We're done here...
421 if (!mDataSize || mDataSize > mImageSize) 407 mDataSize = 0; // no data
422 { 408 done = true;
423 mDataSize = mImageSize;
424 }
425 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
426 } 409 }
427 else 410 else
428 { 411 {
429 mDataSize = 0; // no data 412 // If the read offset is bigger than the header cache, we read directly from the body
430 return true; 413 // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
414 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
431 } 415 }
432 } 416 }
433 417
434 if (mState == HEADER) 418 // Third state / stage : read data from the header cache (texture.entries) file
419 if (!done && (mState == HEADER))
435 { 420 {
436#if USE_LFS_READ 421 llassert_always(idx >= 0); // we need an entry here or reading the header makes no sense
437 if (mFileHandle == LLLFSThread::nullHandle())
438 {
439 llassert_always(idx >= 0);
440 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
441 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
442 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
443 llassert_always(mReadData == NULL);
444 mReadData = new U8[size];
445 mBytesRead = -1;
446 mBytesToRead = size;
447 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
448 mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
449 mReadData, offset, mBytesToRead,
450 new ReadResponder(mCache, mRequestHandle));
451 return false;
452 }
453 else
454 {
455 if (mBytesRead >= 0)
456 {
457 if (mBytesRead != mBytesToRead)
458 {
459// llwarns << "LLTextureCacheWorker: " << mID
460// << " incorrect number of bytes read from header: " << mBytesRead
461// << " != " << mBytesToRead << llendl;
462 mDataSize = -1; // failed
463 return true;
464 }
465 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
466 {
467 return true; // done
468 }
469 else
470 {
471 mFileHandle = LLLFSThread::nullHandle();
472 mState = BODY;
473 }
474 }
475 else
476 {
477 return false;
478 }
479 }
480#else
481 llassert_always(idx >= 0);
482 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); 422 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
483 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; 423 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
424 // Compute the size we need to read (in bytes)
484 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 425 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
426 size = llmin(size, mDataSize);
427 // Allocate the read buffer
485 mReadData = new U8[size]; 428 mReadData = new U8[size];
486 S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, 429 S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName,
487 mReadData, offset, size); 430 mReadData, offset, size);
488 if (bytes_read != size) 431 if (bytes_read != size)
489 { 432 {
490// llwarns << "LLTextureCacheWorker: " << mID 433 llwarns << "LLTextureCacheWorker: " << mID
491// << " incorrect number of bytes read from header: " << bytes_read 434 << " incorrect number of bytes read from header: " << bytes_read
492// << " / " << size << llendl; 435 << " / " << size << llendl;
436 delete[] mReadData;
437 mReadData = NULL;
493 mDataSize = -1; // failed 438 mDataSize = -1; // failed
494 return true; 439 done = true;
495 } 440 }
496 if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) 441 // If we already read all we expected, we're actually done
442 if (mDataSize <= bytes_read)
497 { 443 {
498 return true; // done 444 done = true;
499 } 445 }
500 else 446 else
501 { 447 {
502 mState = BODY; 448 mState = BODY;
503 } 449 }
504#endif
505 } 450 }
506 451
507 if (mState == BODY) 452 // Fourth state / stage : read the rest of the data from the UUID based cached file
453 if (!done && (mState == BODY))
508 { 454 {
509#if USE_LFS_READ
510 if (mFileHandle == LLLFSThread::nullHandle())
511 {
512 std::string filename = mCache->getTextureFileName(mID);
513 S32 filesize = LLAPRFile::size(filename);
514 if (filesize > mOffset)
515 {
516 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
517 mDataSize = llmin(datasize, mDataSize);
518 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
519 data_offset = llmax(data_offset, 0);
520 S32 file_size = mDataSize - data_offset;
521 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
522 file_offset = llmax(file_offset, 0);
523
524 llassert_always(mDataSize > 0);
525 U8* data = new U8[mDataSize];
526 if (data_offset > 0)
527 {
528 llassert_always(mReadData);
529 llassert_always(data_offset <= mDataSize);
530 memcpy(data, mReadData, data_offset);
531 delete[] mReadData;
532 mReadData = NULL;
533 }
534 llassert_always(mReadData == NULL);
535 mReadData = data;
536
537 mBytesRead = -1;
538 mBytesToRead = file_size;
539 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
540 llassert_always(data_offset + mBytesToRead <= mDataSize);
541 mFileHandle = LLLFSThread::sLocal->read(filename,
542 mReadData + data_offset, file_offset, mBytesToRead,
543 new ReadResponder(mCache, mRequestHandle));
544 return false;
545 }
546 else
547 {
548 mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
549 return true; // done
550 }
551 }
552 else
553 {
554 if (mBytesRead >= 0)
555 {
556 if (mBytesRead != mBytesToRead)
557 {
558// llwarns << "LLTextureCacheWorker: " << mID
559// << " incorrect number of bytes read from body: " << mBytesRead
560// << " != " << mBytesToRead << llendl;
561 mDataSize = -1; // failed
562 }
563 return true;
564 }
565 else
566 {
567 return false;
568 }
569 }
570#else
571 std::string filename = mCache->getTextureFileName(mID); 455 std::string filename = mCache->getTextureFileName(mID);
572 S32 filesize = LLAPRFile::size(filename); 456 S32 filesize = LLAPRFile::size(filename);
573 S32 bytes_read = 0; 457
574 if (filesize > mOffset) 458 if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)
575 { 459 {
576 S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize; 460 S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset;
577 mDataSize = llmin(datasize, mDataSize); 461 mDataSize = llmin(max_datasize, mDataSize);
578 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 462
579 data_offset = llmax(data_offset, 0); 463 S32 data_offset, file_size, file_offset;
580 S32 file_size = mDataSize - data_offset;
581 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
582 file_offset = llmax(file_offset, 0);
583 464
465 // Reserve the whole data buffer first
584 U8* data = new U8[mDataSize]; 466 U8* data = new U8[mDataSize];
585 if (data_offset > 0) 467
468 // Set the data file pointers taking the read offset into account. 2 cases:
469 if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
586 { 470 {
471 // Offset within the header record. That means we read something from the header cache.
472 // Note: most common case is (mOffset = 0), so this is the "normal" code path.
473 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; // i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
474 file_offset = 0;
475 file_size = mDataSize - data_offset;
476 // Copy the raw data we've been holding from the header cache into the new sized buffer
587 llassert_always(mReadData); 477 llassert_always(mReadData);
588 memcpy(data, mReadData, data_offset); 478 memcpy(data, mReadData, data_offset);
589 delete[] mReadData; 479 delete[] mReadData;
480 mReadData = NULL;
481 }
482 else
483 {
484 // Offset bigger than the header record. That means we haven't read anything yet.
485 data_offset = 0;
486 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
487 file_size = mDataSize;
488 // No data from header cache to copy in that case, we skipped it all
590 } 489 }
490
491 // Now use that buffer as the object read buffer
492 llassert_always(mReadData == NULL);
591 mReadData = data; 493 mReadData = data;
592 bytes_read = LLAPRFile::readEx(filename, 494
495 // Read the data at last
496 S32 bytes_read = LLAPRFile::readEx(filename,
593 mReadData + data_offset, 497 mReadData + data_offset,
594 file_offset, file_size); 498 file_offset, file_size);
595 if (bytes_read != file_size) 499 if (bytes_read != file_size)
596 { 500 {
597// llwarns << "LLTextureCacheWorker: " << mID 501 llwarns << "LLTextureCacheWorker: " << mID
598// << " incorrect number of bytes read from body: " << bytes_read 502 << " incorrect number of bytes read from body: " << bytes_read
599// << " / " << file_size << llendl; 503 << " / " << file_size << llendl;
504 delete[] mReadData;
505 mReadData = NULL;
600 mDataSize = -1; // failed 506 mDataSize = -1; // failed
601 return true; 507 done = true;
602 } 508 }
603 } 509 }
604 else 510 else
605 { 511 {
606 mDataSize = TEXTURE_CACHE_ENTRY_SIZE; 512 // No body, we're done.
607 } 513 mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0);
608 514 lldebugs << "No body file for: " << filename << llendl;
609 return true; 515 }
610#endif 516 // Nothing else to do at that point...
517 done = true;
611 } 518 }
612 519
613 return false; 520 // Clean up and exit
521 return done;
614} 522}
615 523
524// This is where *everything* about a texture is written down in the cache system (entry map, header and body)
525// Current assumption are:
526// - the whole data are in a raw form, starting at mWriteData
527// - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
528// - the code *does not* support offset writing so there are no difference between buffer addresses and start of data
616bool LLTextureCacheRemoteWorker::doWrite() 529bool LLTextureCacheRemoteWorker::doWrite()
617{ 530{
531 bool done = false;
618 S32 idx = -1; 532 S32 idx = -1;
619 533
620 // No LOCAL state for write() 534 // First state / stage : check that what we're trying to cache is in an OK shape
621
622 if (mState == INIT) 535 if (mState == INIT)
623 { 536 {
537 llassert_always(mOffset == 0); // We currently do not support write offsets
538 llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
539 mState = CACHE;
540 }
541
542 // No LOCAL state for write(): because it doesn't make much sense to cache a local file...
543
544 // Second state / stage : set an entry in the headers entry (texture.entries) file
545 if (!done && (mState == CACHE))
546 {
547 bool alreadyCached = false;
624 S32 cur_imagesize = 0; 548 S32 cur_imagesize = 0;
625 S32 offset = mOffset; 549 // Checks if this image is already in the entry list
626 idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize); 550 idx = mCache->getHeaderCacheEntry(mID, cur_imagesize);
627 if (idx >= 0 && cur_imagesize > 0) 551 if (idx >= 0 && (cur_imagesize >= 0))
628 { 552 {
629 offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header 553 alreadyCached = true; // already there and non empty
630 } 554 }
631 idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry 555 idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry
632 if (idx >= 0) 556 if (idx < 0)
633 { 557 {
634 if(cur_imagesize > 0 && mImageSize != cur_imagesize) 558 llwarns << "LLTextureCacheWorker: " << mID
635 { 559 << " Unable to create header entry for writing!" << llendl;
636// llwarns << "Header cache entry size: " << cur_imagesize << " != mImageSize: " << mImageSize << llendl; 560 mDataSize = -1; // failed
637 offset = 0; // re-write header 561 done = true;
638 }
639 mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
640 } 562 }
641 else 563 else
642 { 564 {
643 mDataSize = -1; // failed 565 if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
644 return true; 566 {
567 alreadyCached = false; // re-write the header if the size changed in all cases
568 }
569 if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
570 {
571 // Small texture already cached case: we're done with writing
572 done = true;
573 }
574 else
575 {
576 // If the texture has already been cached, we don't resave the header and go directly to the body part
577 mState = alreadyCached ? BODY : HEADER;
578 }
645 } 579 }
646 } 580 }
647 581
648 if (mState == HEADER) 582 // Third stage / state : write the header record in the header file (texture.cache)
583 if (!done && (mState == HEADER))
649 { 584 {
650#if USE_LFS_WRITE 585 llassert_always(idx >= 0); // we need an entry here or storing the header makes no sense
651 if (mFileHandle == LLLFSThread::nullHandle()) 586 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file
587 S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header
588 S32 bytes_written;
589
590 if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
652 { 591 {
653 llassert_always(idx >= 0); 592 // We need to write a full record in the header cache so, if the amount of data is smaller
654 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE); 593 // than a record, we need to transfer the data to a buffer padded with 0 and write that
655 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset; 594 U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE];
656 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 595 memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros
657 mBytesRead = -1; 596 memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer
658 mBytesToRead = size; 597 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size);
659 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); 598 delete [] padBuffer;
660 mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
661 mWriteData, offset, mBytesToRead,
662 new WriteResponder(mCache, mRequestHandle));
663 return false;
664 } 599 }
665 else 600 else
666 { 601 {
667 if (mBytesRead >= 0) 602 // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
668 { 603 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size);
669 if (mBytesRead != mBytesToRead)
670 {
671// llwarns << "LLTextureCacheWorker: " << mID
672// << " incorrect number of bytes written to header: " << mBytesRead
673// << " != " << mBytesToRead << llendl;
674 mDataSize = -1; // failed
675 return true;
676 }
677 if (mDataSize <= mBytesToRead)
678 {
679 return true; // done
680 }
681 else
682 {
683 mFileHandle = LLLFSThread::nullHandle();
684 mState = BODY;
685 }
686 }
687 else
688 {
689 return false;
690 }
691 } 604 }
692#else
693 llassert_always(idx >= 0);
694 llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
695 S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
696 S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
697 S32 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size);
698 605
699 if (bytes_written <= 0) 606 if (bytes_written <= 0)
700 { 607 {
701// llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl; 608 llwarns << "LLTextureCacheWorker: " << mID
609 << " Unable to write header entry!" << llendl;
702 mDataSize = -1; // failed 610 mDataSize = -1; // failed
703 return true; 611 done = true;
704 } 612 }
705 613
706 if (mDataSize <= size) 614 // If we wrote everything (may be more with padding) in the header cache,
615 // we're done so we don't have a body to store
616 if (mDataSize <= bytes_written)
707 { 617 {
708 return true; // done 618 done = true;
709 } 619 }
710 else 620 else
711 { 621 {
712 mState = BODY; 622 mState = BODY;
713 } 623 }
714#endif
715 } 624 }
716 625
717 if (mState == BODY) 626 // Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name
627 if (!done && (mState == BODY))
718 { 628 {
719#if USE_LFS_WRITE 629 llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
720 if (mFileHandle == LLLFSThread::nullHandle()) 630 S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
631 if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size))
721 { 632 {
722 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; 633 // build the cache file name from the UUID
723 data_offset = llmax(data_offset, 0); 634 std::string filename = mCache->getTextureFileName(mID);
724 S32 file_size = mDataSize - data_offset; 635// llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;
725 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE; 636 S32 bytes_written = LLAPRFile::writeEx( filename,
726 file_offset = llmax(file_offset, 0); 637 mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
727 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size)) 638 0, file_size);
728 {
729 std::string filename = mCache->getTextureFileName(mID);
730 mBytesRead = -1;
731 mBytesToRead = file_size;
732 setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
733 mFileHandle = LLLFSThread::sLocal->write(filename,
734 mWriteData + data_offset, file_offset, mBytesToRead,
735 new WriteResponder(mCache, mRequestHandle));
736 return false;
737 }
738 else
739 {
740 mDataSize = 0; // no data written
741 return true; // done
742 }
743 }
744 else
745 {
746 if (mBytesRead >= 0)
747 {
748 if (mBytesRead != mBytesToRead)
749 {
750// llwarns << "LLTextureCacheWorker: " << mID
751// << " incorrect number of bytes written to body: " << mBytesRead
752// << " != " << mBytesToRead << llendl;
753 mDataSize = -1; // failed
754 }
755 return true;
756 }
757 else
758 {
759 return false;
760 }
761 }
762#else
763 S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
764 data_offset = llmax(data_offset, 0);
765 S32 file_size = mDataSize - data_offset;
766 S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
767 file_offset = llmax(file_offset, 0);
768 S32 bytes_written = 0;
769 if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
770 {
771 std::string filename = mCache->getTextureFileName(mID);
772
773 bytes_written = LLAPRFile::writeEx(filename,
774 mWriteData + data_offset,
775 file_offset, file_size);
776 if (bytes_written <= 0) 639 if (bytes_written <= 0)
777 { 640 {
641 llwarns << "LLTextureCacheWorker: " << mID
642 << " incorrect number of bytes written to body: " << bytes_written
643 << " / " << file_size << llendl;
778 mDataSize = -1; // failed 644 mDataSize = -1; // failed
645 done = true;
779 } 646 }
780 } 647 }
781 else 648 else
782 { 649 {
783 mDataSize = 0; // no data written 650 mDataSize = 0; // no data written
784 } 651 }
785 652 // Nothing else to do at that point...
786 return true; 653 done = true;
787#endif
788 } 654 }
789 655
790 return false; 656 // Clean up and exit
657 return done;
791} 658}
792 659
793//virtual 660//virtual
794bool LLTextureCacheWorker::doWork(S32 param) 661bool LLTextureCacheWorker::doWork(S32 param)
795{ 662{
796// *TODO reenable disabled apr_pool usage disabled due to maint-render-9 merge breakage -brad
797 //allocate a new local apr_pool
798// LLAPRPool pool ;
799
800 //save the current mFileAPRPool to avoid breaking anything.
801// apr_pool_t* old_pool = mCache->getFileAPRPool() ;
802 //make mFileAPRPool to point to the local one
803// mCache->setFileAPRPool(pool.getAPRPool()) ;
804
805 bool res = false; 663 bool res = false;
806 if (param == 0) // read 664 if (param == 0) // read
807 { 665 {
@@ -815,10 +673,6 @@ bool LLTextureCacheWorker::doWork(S32 param)
815 { 673 {
816 llassert_always(0); 674 llassert_always(0);
817 } 675 }
818
819 //set mFileAPRPool back, the local one will be released automatically.
820// mCache->setFileAPRPool(old_pool) ;
821
822 return res; 676 return res;
823} 677}
824 678
@@ -884,6 +738,7 @@ LLTextureCache::LLTextureCache(bool threaded)
884 mWorkersMutex(NULL), 738 mWorkersMutex(NULL),
885 mHeaderMutex(NULL), 739 mHeaderMutex(NULL),
886 mListMutex(NULL), 740 mListMutex(NULL),
741 mHeaderAPRFile(NULL),
887 mReadOnly(FALSE), 742 mReadOnly(FALSE),
888 mTexturesSizeTotal(0), 743 mTexturesSizeTotal(0),
889 mDoPurge(FALSE) 744 mDoPurge(FALSE)
@@ -892,9 +747,6 @@ LLTextureCache::LLTextureCache(bool threaded)
892 747
893LLTextureCache::~LLTextureCache() 748LLTextureCache::~LLTextureCache()
894{ 749{
895 purgeTextureFilesTimeSliced(TRUE); // force-flush all pending file deletes
896
897 // apr_pool_destroy(mFileAPRPool);
898} 750}
899 751
900////////////////////////////////////////////////////////////////////////////// 752//////////////////////////////////////////////////////////////////////////////
@@ -926,6 +778,9 @@ S32 LLTextureCache::update(U32 max_time_ms)
926 } 778 }
927 } 779 }
928 780
781 unlockWorkers();
782
783 // call 'completed' with workers list unlocked (may call readComplete() or writeComplete()
929 for (responder_list_t::iterator iter1 = completed_list.begin(); 784 for (responder_list_t::iterator iter1 = completed_list.begin();
930 iter1 != completed_list.end(); ++iter1) 785 iter1 != completed_list.end(); ++iter1)
931 { 786 {
@@ -934,8 +789,6 @@ S32 LLTextureCache::update(U32 max_time_ms)
934 responder->completed(success); 789 responder->completed(success);
935 } 790 }
936 791
937 unlockWorkers();
938
939 return res; 792 return res;
940} 793}
941 794
@@ -954,32 +807,48 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id)
954{ 807{
955 std::string idstr = id.asString(); 808 std::string idstr = id.asString();
956 std::string delem = gDirUtilp->getDirDelimiter(); 809 std::string delem = gDirUtilp->getDirDelimiter();
957 std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr; 810 std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture";
958 return filename; 811 return filename;
959} 812}
960 813
961bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize) 814bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize)
962{ 815{
963 bool res = false; 816 bool res = false;
964 bool purge = false; 817 bool purge = false;
965 // Append UUID to end of texture entries
966 { 818 {
967 LLMutexLock lock(&mHeaderMutex); 819 LLMutexLock lock(&mHeaderMutex);
968 size_map_t::iterator iter = mTexturesSizeMap.find(id); 820 size_map_t::iterator iter1 = mTexturesSizeMap.find(id);
969 if (iter == mTexturesSizeMap.end() || iter->second < bodysize) 821 if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize)
970 { 822 {
971 llassert_always(bodysize > 0); 823 llassert_always(bodysize > 0);
972 Entry* entry = new Entry(id, bodysize, time(NULL));
973 824
974 LLAPRFile::writeEx(mTexturesDirEntriesFileName, 825 S32 oldbodysize = 0;
975 (U8*)entry, -1, 1*sizeof(Entry)); 826 if (iter1 != mTexturesSizeMap.end())
976 delete entry;
977 if (iter != mTexturesSizeMap.end())
978 { 827 {
979 mTexturesSizeTotal -= iter->second; 828 oldbodysize = iter1->second;
980 } 829 }
830
831 Entry entry;
832 S32 idx = openAndReadEntry(id, entry, false);
833 if (idx < 0)
834 {
835 // TODO: change to llwarns
836 llerrs << "Failed to open entry: " << id << llendl;
837 removeFromCache(id);
838 return false;
839 }
840 else if (oldbodysize != entry.mBodySize)
841 {
842 // TODO: change to llwarns
843 llerrs << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
844 << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
845 }
846 entry.mBodySize = bodysize;
847 writeEntryAndClose(idx, entry);
848
849 mTexturesSizeTotal -= oldbodysize;
981 mTexturesSizeTotal += bodysize; 850 mTexturesSizeTotal += bodysize;
982 mTexturesSizeMap[id] = bodysize; 851
983 if (mTexturesSizeTotal > sCacheMaxTexturesSize) 852 if (mTexturesSizeTotal > sCacheMaxTexturesSize)
984 { 853 {
985 purge = true; 854 purge = true;
@@ -998,7 +867,7 @@ bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
998 867
999//static 868//static
1000const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB 869const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
1001F32 LLTextureCache::sHeaderCacheVersion = 1.0f; 870F32 LLTextureCache::sHeaderCacheVersion = 1.2f;
1002U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE; 871U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
1003S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit 872S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
1004const char* entries_filename = "texture.entries"; 873const char* entries_filename = "texture.entries";
@@ -1011,7 +880,6 @@ void LLTextureCache::setDirNames(ELLPath location)
1011 mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename); 880 mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
1012 mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename); 881 mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
1013 mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname); 882 mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
1014 mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
1015} 883}
1016 884
1017void LLTextureCache::purgeCache(ELLPath location) 885void LLTextureCache::purgeCache(ELLPath location)
@@ -1019,7 +887,7 @@ void LLTextureCache::purgeCache(ELLPath location)
1019 if (!mReadOnly) 887 if (!mReadOnly)
1020 { 888 {
1021 setDirNames(location); 889 setDirNames(location);
1022 890 llassert_always(mHeaderAPRFile == NULL);
1023 LLAPRFile::remove(mHeaderEntriesFileName); 891 LLAPRFile::remove(mHeaderEntriesFileName);
1024 LLAPRFile::remove(mHeaderDataFileName); 892 LLAPRFile::remove(mHeaderDataFileName);
1025 } 893 }
@@ -1062,80 +930,315 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
1062 return max_size; // unused cache space 930 return max_size; // unused cache space
1063} 931}
1064 932
1065struct lru_data 933//----------------------------------------------------------------------------
934// mHeaderMutex must be locked for the following functions!
935
936LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
937{
938 llassert_always(mHeaderAPRFile == NULL);
939 apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
940 mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, LLAPRFile::local);
941 mHeaderAPRFile->seek(APR_SET, offset);
942 return mHeaderAPRFile;
943}
944
945void LLTextureCache::closeHeaderEntriesFile()
946{
947 llassert_always(mHeaderAPRFile != NULL);
948 delete mHeaderAPRFile;
949 mHeaderAPRFile = NULL;
950}
951
952void LLTextureCache::readEntriesHeader()
953{
954 // mHeaderEntriesInfo initializes to default values so safe not to read it
955 llassert_always(mHeaderAPRFile == NULL);
956 if (LLAPRFile::isExist(mHeaderEntriesFileName))
957 {
958 LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
959 }
960}
961
962void LLTextureCache::writeEntriesHeader()
1066{ 963{
1067 lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; } 964 llassert_always(mHeaderAPRFile == NULL);
1068 U32 time; 965 if (!mReadOnly)
1069 S32 index; 966 {
1070 LLUUID uuid; 967 LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1071 struct Compare 968 }
1072 { 969}
1073 // lhs < rhs 970
1074 typedef const lru_data* lru_data_ptr; 971static S32 mHeaderEntriesMaxWriteIdx = 0;
1075 bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const 972
973S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create)
974{
975 S32 idx = -1;
976
977 id_map_t::iterator iter1 = mHeaderIDMap.find(id);
978 if (iter1 != mHeaderIDMap.end())
979 {
980 idx = iter1->second;
981 }
982
983 if (idx < 0)
984 {
985 if (create && !mReadOnly)
1076 { 986 {
1077 if(a->time == b->time) 987 if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
1078 return (a->index < b->index); 988 {
989 // Add an entry to the end of the list
990 idx = mHeaderEntriesInfo.mEntries++;
991
992 }
993 else if (!mFreeList.empty())
994 {
995 idx = *(mFreeList.begin());
996 mFreeList.erase(mFreeList.begin());
997 }
1079 else 998 else
1080 return (a->time >= b->time); 999 {
1000 // Look for a still valid entry in the LRU
1001 for (std::set<LLUUID>::iterator iter2 = mLRU.begin(); iter2 != mLRU.end();)
1002 {
1003 std::set<LLUUID>::iterator curiter2 = iter2++;
1004 LLUUID oldid = *curiter2;
1005 // Erase entry from LRU regardless
1006 mLRU.erase(curiter2);
1007 // Look up entry and use it if it is valid
1008 id_map_t::iterator iter3 = mHeaderIDMap.find(oldid);
1009 if (iter3 != mHeaderIDMap.end() && iter3->second >= 0)
1010 {
1011 idx = iter3->second;
1012 mHeaderIDMap.erase(oldid);
1013 mTexturesSizeMap.erase(oldid);
1014 break;
1015 }
1016 }
1017 // if (idx < 0) at this point, we will rebuild the LRU
1018 // and retry if called from setHeaderCacheEntry(),
1019 // otherwise this shouldn't happen and will trigger an error
1020 }
1021 if (idx >= 0)
1022 {
1023 // Set the header index
1024 mHeaderIDMap[id] = idx;
1025 llassert_always(mTexturesSizeMap.erase(id) == 0);
1026 // Initialize the entry (will get written later)
1027 entry.init(id, time(NULL));
1028 // Update Header
1029 writeEntriesHeader();
1030 // Write Entry
1031 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1032 LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
1033 S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
1034 llassert_always(bytes_written == sizeof(Entry));
1035 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
1036 closeHeaderEntriesFile();
1037 }
1081 } 1038 }
1082 }; 1039 }
1083}; 1040 else
1041 {
1042 // Remove this entry from the LRU if it exists
1043 mLRU.erase(id);
1044 // Read the entry
1045 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1046 LLAPRFile* aprfile = openHeaderEntriesFile(true, offset);
1047 S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry));
1048 llassert_always(bytes_read == sizeof(Entry));
1049 llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
1050 closeHeaderEntriesFile();
1051 }
1052 return idx;
1053}
1054
1055void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry)
1056{
1057 if (idx >= 0)
1058 {
1059 if (!mReadOnly)
1060 {
1061 entry.mTime = time(NULL);
1062 llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
1063 if (entry.mBodySize > 0)
1064 {
1065 mTexturesSizeMap[entry.mID] = entry.mBodySize;
1066 }
1067// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl;
1068 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1069 LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
1070 S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
1071 llassert_always(bytes_written == sizeof(Entry));
1072 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
1073 closeHeaderEntriesFile();
1074 }
1075 }
1076}
1077
1078U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
1079{
1080 U32 num_entries = mHeaderEntriesInfo.mEntries;
1081
1082 mHeaderIDMap.clear();
1083 mTexturesSizeMap.clear();
1084 mFreeList.clear();
1085 mTexturesSizeTotal = 0;
1086
1087 LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
1088 for (U32 idx=0; idx<num_entries; idx++)
1089 {
1090 Entry entry;
1091 S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
1092 if (bytes_read < sizeof(Entry))
1093 {
1094 llwarns << "Corrupted header entries, failed at " << idx << " / " << num_entries << llendl;
1095 closeHeaderEntriesFile();
1096 purgeAllTextures(false);
1097 return 0;
1098 }
1099 entries.push_back(entry);
1100// llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl;
1101 if (entry.mImageSize < 0)
1102 {
1103 mFreeList.insert(idx);
1104 }
1105 else
1106 {
1107 mHeaderIDMap[entry.mID] = idx;
1108 if (entry.mBodySize > 0)
1109 {
1110 mTexturesSizeMap[entry.mID] = entry.mBodySize;
1111 mTexturesSizeTotal += entry.mBodySize;
1112 }
1113 llassert_always(entry.mImageSize == 0 || entry.mImageSize > entry.mBodySize);
1114 }
1115 }
1116 closeHeaderEntriesFile();
1117 return num_entries;
1118}
1119
1120void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries)
1121{
1122 S32 num_entries = entries.size();
1123 llassert_always(num_entries == mHeaderEntriesInfo.mEntries);
1124
1125 if (!mReadOnly)
1126 {
1127 LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
1128 for (S32 idx=0; idx<num_entries; idx++)
1129 {
1130 S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry));
1131 llassert_always(bytes_written == sizeof(Entry));
1132 }
1133 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, num_entries-1);
1134 closeHeaderEntriesFile();
1135 }
1136}
1137
1138//----------------------------------------------------------------------------
1084 1139
1085// Called from either the main thread or the worker thread 1140// Called from either the main thread or the worker thread
1086void LLTextureCache::readHeaderCache() 1141void LLTextureCache::readHeaderCache()
1087{ 1142{
1088 LLMutexLock lock(&mHeaderMutex); 1143 LLMutexLock lock(&mHeaderMutex);
1089 mHeaderEntriesInfo.mVersion = 0.f; 1144
1090 mHeaderEntriesInfo.mEntries = 0; 1145 mLRU.clear(); // always clear the LRU
1091 if (LLAPRFile::isExist(mHeaderEntriesFileName)) 1146
1092 { 1147 readEntriesHeader();
1093 LLAPRFile::readEx(mHeaderEntriesFileName, 1148
1094 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1095 }
1096 if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion) 1149 if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
1097 { 1150 {
1098 if (!mReadOnly) 1151 if (!mReadOnly)
1099 { 1152 {
1100 // Info with 0 entries 1153 purgeAllTextures(false);
1101 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
1102
1103 LLAPRFile::writeEx(mHeaderEntriesFileName,
1104 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1105 } 1154 }
1106 } 1155 }
1107 else 1156 else
1108 { 1157 {
1109 S32 num_entries = mHeaderEntriesInfo.mEntries; 1158 std::vector<Entry> entries;
1159 U32 num_entries = openAndReadEntries(entries);
1110 if (num_entries) 1160 if (num_entries)
1111 { 1161 {
1112 Entry* entries = new Entry[num_entries]; 1162 U32 empty_entries = 0;
1163 typedef std::pair<U32, LLUUID> lru_data_t;
1164 std::set<lru_data_t> lru;
1165 std::vector<LLUUID> purge_list;
1166 for (U32 i=0; i<num_entries; i++)
1113 { 1167 {
1114 LLAPRFile::readEx(mHeaderEntriesFileName, 1168 Entry& entry = entries[i];
1115 (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry)); 1169 const LLUUID& id = entry.mID;
1170 if (entry.mImageSize < 0)
1171 {
1172 // This will be in the Free List, don't put it in the LRY
1173 ++empty_entries;
1174 }
1175 else
1176 {
1177 lru.insert(std::make_pair(entry.mTime, id));
1178 if (entry.mBodySize > 0)
1179 {
1180 if (entry.mBodySize > entry.mImageSize)
1181 {
1182 // Shouldn't happen, failsafe only
1183 llwarns << "Bad entry: " << i << ": " << id << ": BodySize: " << entry.mBodySize << llendl;
1184 purge_list.push_back(id);
1185 }
1186 }
1187 }
1116 } 1188 }
1117 typedef std::set<lru_data*, lru_data::Compare> lru_set_t; 1189 if (num_entries > sCacheMaxEntries)
1118 lru_set_t lru;
1119 for (S32 i=0; i<num_entries; i++)
1120 { 1190 {
1121 if (entries[i].mSize >= 0) // -1 indicates erased entry, skip 1191 // Special case: cache size was reduced, need to remove entries
1192 // Note: After we prune entries, we will call this again and create the LRU
1193 U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
1194 if (entries_to_purge > 0)
1122 { 1195 {
1123 const LLUUID& id = entries[i].mID; 1196 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1124 lru.insert(new lru_data(entries[i].mTime, i, id)); 1197 {
1125 mHeaderIDMap[id] = i; 1198 purge_list.push_back(iter->second);
1199 if (--entries_to_purge <= 0)
1200 break;
1201 }
1126 } 1202 }
1127 } 1203 }
1128 mLRU.clear(); 1204 else
1129 S32 lru_entries = sCacheMaxEntries / 10;
1130 for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1131 { 1205 {
1132 lru_data* data = *iter; 1206 S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE);
1133 mLRU[data->index] = data->uuid; 1207 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1134 if (--lru_entries <= 0) 1208 {
1135 break; 1209 mLRU.insert(iter->second);
1210// llinfos << "LRU: " << iter->first << " : " << iter->second << llendl;
1211 if (--lru_entries <= 0)
1212 break;
1213 }
1214 }
1215
1216 if (purge_list.size() > 0)
1217 {
1218 for (std::vector<LLUUID>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter)
1219 {
1220 removeFromCache(*iter);
1221 }
1222 // If we removed any entries, we need to rebuild the entries list,
1223 // write the header, and call this again
1224 std::vector<Entry> new_entries;
1225 for (U32 i=0; i<num_entries; i++)
1226 {
1227 const Entry& entry = entries[i];
1228 if (entry.mImageSize >=0)
1229 {
1230 new_entries.push_back(entry);
1231 }
1232 }
1233 llassert_always(new_entries.size() <= sCacheMaxEntries);
1234 mHeaderEntriesInfo.mEntries = new_entries.size();
1235 writeEntriesAndClose(new_entries);
1236 readHeaderCache(); // repeat with new entries file
1237 }
1238 else
1239 {
1240 writeEntriesAndClose(entries);
1136 } 1241 }
1137 for_each(lru.begin(), lru.end(), DeletePointer());
1138 delete[] entries;
1139 } 1242 }
1140 } 1243 }
1141} 1244}
@@ -1158,13 +1261,21 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
1158 LLFile::rmdir(dirname); 1261 LLFile::rmdir(dirname);
1159 } 1262 }
1160 } 1263 }
1161 LLAPRFile::remove(mTexturesDirEntriesFileName);
1162 if (purge_directories) 1264 if (purge_directories)
1163 { 1265 {
1164 LLFile::rmdir(mTexturesDirName); 1266 LLFile::rmdir(mTexturesDirName);
1165 } 1267 }
1166 } 1268 }
1269 mHeaderIDMap.clear();
1167 mTexturesSizeMap.clear(); 1270 mTexturesSizeMap.clear();
1271 mTexturesSizeTotal = 0;
1272 mFreeList.clear();
1273 mTexturesSizeTotal = 0;
1274
1275 // Info with 0 entries
1276 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
1277 mHeaderEntriesInfo.mEntries = 0;
1278 writeEntriesHeader();
1168} 1279}
1169 1280
1170void LLTextureCache::purgeTextures(bool validate) 1281void LLTextureCache::purgeTextures(bool validate)
@@ -1178,50 +1289,37 @@ void LLTextureCache::purgeTextures(bool validate)
1178 LLAppViewer::instance()->pauseMainloopTimeout(); 1289 LLAppViewer::instance()->pauseMainloopTimeout();
1179 1290
1180 LLMutexLock lock(&mHeaderMutex); 1291 LLMutexLock lock(&mHeaderMutex);
1181 1292
1182 S32 filesize = LLAPRFile::size(mTexturesDirEntriesFileName); 1293 llinfos << "TEXTURE CACHE: Purging." << llendl;
1183 S32 num_entries = filesize / sizeof(Entry); 1294
1184 if (num_entries * (S32)sizeof(Entry) != filesize) 1295 // Read the entries list
1185 { 1296 std::vector<Entry> entries;
1186 LL_WARNS("TextureCache") << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL; 1297 U32 num_entries = openAndReadEntries(entries);
1187 purgeAllTextures(false); 1298 if (!num_entries)
1188 return;
1189 }
1190 if (num_entries == 0)
1191 { 1299 {
1192 return; // nothing to do 1300 writeEntriesAndClose(entries);
1301 return; // nothing to purge
1193 } 1302 }
1194 1303
1195 Entry* entries = new Entry[num_entries]; 1304 // Use mTexturesSizeMap to collect UUIDs of textures with bodies
1196 S32 bytes_read = LLAPRFile::readEx(mTexturesDirEntriesFileName, 1305 typedef std::set<std::pair<U32,S32> > time_idx_set_t;
1197 (U8*)entries, 0, num_entries*sizeof(Entry)); 1306 std::set<std::pair<U32,S32> > time_idx_set;
1198 if (bytes_read != filesize) 1307 for (size_map_t::iterator iter1 = mTexturesSizeMap.begin();
1308 iter1 != mTexturesSizeMap.end(); ++iter1)
1199 { 1309 {
1200 LL_WARNS("TextureCache") << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL; 1310 if (iter1->second > 0)
1201 purgeAllTextures(false);
1202 return;
1203 }
1204
1205 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading " << num_entries << " Entries from " << mTexturesDirEntriesFileName << LL_ENDL;
1206
1207 std::map<LLUUID, S32> entry_idx_map;
1208 S64 total_size = 0;
1209 for (S32 idx=0; idx<num_entries; idx++)
1210 {
1211 const LLUUID& id = entries[idx].mID;
1212 LL_DEBUGS("TextureCache") << "Entry: " << id << " Size: " << entries[idx].mSize << " Time: " << entries[idx].mTime << LL_ENDL;
1213 std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
1214 if (iter != entry_idx_map.end())
1215 { 1311 {
1216 // Newer entry replacing older entry 1312 id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first);
1217 S32 pidx = iter->second; 1313 if (iter2 != mHeaderIDMap.end())
1218 total_size -= entries[pidx].mSize; 1314 {
1219 entries[pidx].mSize = 0; // flag: skip older entry 1315 S32 idx = iter2->second;
1316 time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
1317// llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl;
1318 }
1220 } 1319 }
1221 entry_idx_map[id] = idx;
1222 total_size += entries[idx].mSize;
1223 } 1320 }
1224 1321
1322 // Validate 1/256th of the files on startup
1225 U32 validate_idx = 0; 1323 U32 validate_idx = 0;
1226 if (validate) 1324 if (validate)
1227 { 1325 {
@@ -1230,19 +1328,17 @@ void LLTextureCache::purgeTextures(bool validate)
1230 gSavedSettings.setU32("CacheValidateCounter", next_idx); 1328 gSavedSettings.setU32("CacheValidateCounter", next_idx);
1231 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL; 1329 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
1232 } 1330 }
1233 1331
1234 S64 min_cache_size = sCacheMaxTexturesSize / 100 * 95; 1332 S64 cache_size = mTexturesSizeTotal;
1333 S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f-TEXTURE_CACHE_PURGE_AMOUNT)*100)) / 100;
1235 S32 purge_count = 0; 1334 S32 purge_count = 0;
1236 S32 next_idx = 0; 1335 for (time_idx_set_t::iterator iter = time_idx_set.begin();
1237 for (S32 idx=0; idx<num_entries; idx++) 1336 iter != time_idx_set.end(); ++iter)
1238 { 1337 {
1239 if (entries[idx].mSize == 0) 1338 S32 idx = iter->second;
1240 {
1241 continue;
1242 }
1243 bool purge_entry = false; 1339 bool purge_entry = false;
1244 std::string filename = getTextureFileName(entries[idx].mID); 1340 std::string filename = getTextureFileName(entries[idx].mID);
1245 if (total_size >= min_cache_size) 1341 if (cache_size >= purged_cache_size)
1246 { 1342 {
1247 purge_entry = true; 1343 purge_entry = true;
1248 } 1344 }
@@ -1252,112 +1348,47 @@ void LLTextureCache::purgeTextures(bool validate)
1252 S32 uuididx = entries[idx].mID.mData[0]; 1348 S32 uuididx = entries[idx].mID.mData[0];
1253 if (uuididx == validate_idx) 1349 if (uuididx == validate_idx)
1254 { 1350 {
1255 LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mSize << LL_ENDL; 1351 LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL;
1256 S32 bodysize = LLAPRFile::size(filename); 1352 S32 bodysize = LLAPRFile::size(filename);
1257 if (bodysize != entries[idx].mSize) 1353 if (bodysize != entries[idx].mBodySize)
1258 { 1354 {
1259 LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize 1355 LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize
1260 << filename << LL_ENDL; 1356 << filename << LL_ENDL;
1261 purge_entry = true; 1357 purge_entry = true;
1262 } 1358 }
1263 } 1359 }
1264 } 1360 }
1265 if (purge_entry) 1361 else
1266 { 1362 {
1267 purge_count++; 1363 break;
1268 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
1269 mFilesToDelete.push_back(filename);
1270 total_size -= entries[idx].mSize;
1271 entries[idx].mSize = 0;
1272 } 1364 }
1273 else 1365
1366 if (purge_entry)
1274 { 1367 {
1275 if (next_idx != idx) 1368 purge_count++;
1276 { 1369 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
1277 entries[next_idx] = entries[idx]; 1370 LLAPRFile::remove(filename);
1278 } 1371 cache_size -= entries[idx].mBodySize;
1279 ++next_idx; 1372 mTexturesSizeTotal -= entries[idx].mBodySize;
1373 entries[idx].mBodySize = 0;
1374 mTexturesSizeMap.erase(entries[idx].mID);
1280 } 1375 }
1281 } 1376 }
1282 num_entries = next_idx;
1283 1377
1284 mTimeLastFileDelete.reset(); 1378 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
1285 1379
1286 LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " 1380 writeEntriesAndClose(entries);
1287 << num_entries << " (" << num_entries*sizeof(Entry)/1024 << "KB)"
1288 << LL_ENDL;
1289
1290 LLAPRFile::remove(mTexturesDirEntriesFileName);
1291 LLAPRFile::writeEx(mTexturesDirEntriesFileName,
1292 (U8*)&entries[0], 0, num_entries*sizeof(Entry));
1293
1294 mTexturesSizeTotal = 0;
1295 mTexturesSizeMap.clear();
1296 for (S32 idx=0; idx<num_entries; idx++)
1297 {
1298 mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
1299 mTexturesSizeTotal += entries[idx].mSize;
1300 }
1301 llassert(mTexturesSizeTotal == total_size);
1302 1381
1303 delete[] entries;
1304
1305 // *FIX:Mani - watchdog back on. 1382 // *FIX:Mani - watchdog back on.
1306 LLAppViewer::instance()->resumeMainloopTimeout(); 1383 LLAppViewer::instance()->resumeMainloopTimeout();
1307 1384
1308 LL_INFOS("TextureCache") << "TEXTURE CACHE:" 1385 LL_INFOS("TextureCache") << "TEXTURE CACHE:"
1309 << " PURGED: " << purge_count 1386 << " PURGED: " << purge_count
1310 << " ENTRIES: " << num_entries 1387 << " ENTRIES: " << num_entries
1311 << " CACHE SIZE: " << total_size/1024/1024 << " MB" 1388 << " CACHE SIZE: " << mTexturesSizeTotal / 1024*1024 << " MB"
1312 << llendl; 1389 << llendl;
1313} 1390}
1314 1391
1315
1316void LLTextureCache::purgeTextureFilesTimeSliced(BOOL force_all)
1317{
1318 LLMutexLock lock(&mHeaderMutex);
1319
1320 F32 delay_between_passes = 1.0f; // seconds
1321 F32 max_time_per_pass = 0.1f; // seconds
1322
1323 if (!force_all && mTimeLastFileDelete.getElapsedTimeF32() <= delay_between_passes)
1324 {
1325 return;
1326 }
1327
1328 LLTimer timer;
1329 S32 howmany = 0;
1330
1331 if (mFilesToDelete.size() > 0)
1332 {
1333 llinfos << "TEXTURE CACHE: " << mFilesToDelete.size() << " files scheduled for deletion" << llendl;
1334 }
1335
1336 for (LLTextureCache::filename_list_t::iterator iter = mFilesToDelete.begin(); iter!=mFilesToDelete.end(); )
1337 {
1338 LLTextureCache::filename_list_t::iterator iter2 = iter++;
1339 LLAPRFile::remove(*iter2);
1340 mFilesToDelete.erase(iter2);
1341 howmany++;
1342
1343 if (!force_all && timer.getElapsedTimeF32() > max_time_per_pass)
1344 {
1345 break;
1346 }
1347 }
1348
1349 if (!mFilesToDelete.empty())
1350 {
1351 llinfos << "TEXTURE CACHE: "<< howmany << " files deleted ("
1352 << mFilesToDelete.size() << " files left for next pass)"
1353 << llendl;
1354 }
1355
1356 mTimeLastFileDelete.reset();
1357}
1358
1359
1360
1361////////////////////////////////////////////////////////////////////////////// 1392//////////////////////////////////////////////////////////////////////////////
1362 1393
1363// call lockWorkers() first! 1394// call lockWorkers() first!
@@ -1384,75 +1415,39 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
1384} 1415}
1385 1416
1386////////////////////////////////////////////////////////////////////////////// 1417//////////////////////////////////////////////////////////////////////////////
1387
1388// Called from work thread 1418// Called from work thread
1389S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
1390{
1391 bool retry = false;
1392 S32 idx = -1;
1393 1419
1420// Reads imagesize from the header, updates timestamp
1421S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize)
1422{
1423 LLMutexLock lock(&mHeaderMutex);
1424 Entry entry;
1425 S32 idx = openAndReadEntry(id, entry, false);
1426 if (idx >= 0)
1394 { 1427 {
1395 LLMutexLock lock(&mHeaderMutex); 1428 imagesize = entry.mImageSize;
1396 id_map_t::iterator iter = mHeaderIDMap.find(id); 1429 writeEntryAndClose(idx, entry); // updates time
1397 if (iter != mHeaderIDMap.end()) 1430 }
1398 { 1431 return idx;
1399 idx = iter->second; 1432}
1400 }
1401 else if (touch && !mReadOnly)
1402 {
1403 if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
1404 {
1405 // Add an entry
1406 idx = mHeaderEntriesInfo.mEntries++;
1407 mHeaderIDMap[id] = idx;
1408 // Update Info
1409 LLAPRFile::writeEx(mHeaderEntriesFileName,
1410 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
1411 }
1412 else if (!mLRU.empty())
1413 {
1414 idx = mLRU.begin()->first; // will be erased below
1415 const LLUUID& oldid = mLRU.begin()->second;
1416 mHeaderIDMap.erase(oldid);
1417 mTexturesSizeMap.erase(oldid);
1418 mHeaderIDMap[id] = idx;
1419 }
1420 else
1421 {
1422 idx = -1;
1423 retry = true;
1424 }
1425 }
1426 if (idx >= 0)
1427 {
1428 if (touch && !mReadOnly)
1429 {
1430 // Update the lru entry
1431 mLRU.erase(idx);
1432 llassert_always(imagesize && *imagesize > 0);
1433 Entry* entry = new Entry(id, *imagesize, time(NULL));
1434 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1435 LLAPRFile::writeEx(mHeaderEntriesFileName,
1436 (U8*)entry, offset, sizeof(Entry));
1437 delete entry;
1438 }
1439 else if (imagesize)
1440 {
1441 // Get the image size
1442 Entry entry;
1443 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1444 1433
1445 LLAPRFile::readEx(mHeaderEntriesFileName, 1434// Writes imagesize to the header, updates timestamp
1446 (U8*)&entry, offset, sizeof(Entry)); 1435S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize)
1447 *imagesize = entry.mSize; 1436{
1448 } 1437 LLMutexLock lock(&mHeaderMutex);
1449 } 1438 llassert_always(imagesize >= 0);
1439 Entry entry;
1440 S32 idx = openAndReadEntry(id, entry, true);
1441 if (idx >= 0)
1442 {
1443 entry.mImageSize = imagesize;
1444 writeEntryAndClose(idx, entry);
1450 } 1445 }
1451 if (retry) 1446 else // retry
1452 { 1447 {
1453 readHeaderCache(); // updates the lru 1448 readHeaderCache(); // We couldn't write an entry, so refresh the LRU
1454 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); 1449 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
1455 idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion 1450 idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion
1456 } 1451 }
1457 return idx; 1452 return idx;
1458} 1453}
@@ -1468,8 +1463,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const std::string& filena
1468 // so let the thread handle it 1463 // so let the thread handle it
1469 LLMutexLock lock(&mWorkersMutex); 1464 LLMutexLock lock(&mWorkersMutex);
1470 LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id, 1465 LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id,
1471 NULL, size, offset, 0, 1466 NULL, size, offset, 0,
1472 responder); 1467 responder);
1473 handle_t handle = worker->read(); 1468 handle_t handle = worker->read();
1474 mReaders[handle] = worker; 1469 mReaders[handle] = worker;
1475 return handle; 1470 return handle;
@@ -1482,8 +1477,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 pri
1482 // so let the thread handle it 1477 // so let the thread handle it
1483 LLMutexLock lock(&mWorkersMutex); 1478 LLMutexLock lock(&mWorkersMutex);
1484 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, 1479 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
1485 NULL, size, offset, 0, 1480 NULL, size, offset,
1486 responder); 1481 0, responder);
1487 handle_t handle = worker->read(); 1482 handle_t handle = worker->read();
1488 mReaders[handle] = worker; 1483 mReaders[handle] = worker;
1489 return handle; 1484 return handle;
@@ -1494,7 +1489,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort)
1494{ 1489{
1495 lockWorkers(); 1490 lockWorkers();
1496 handle_map_t::iterator iter = mReaders.find(handle); 1491 handle_map_t::iterator iter = mReaders.find(handle);
1497 llassert_always(iter != mReaders.end()); 1492 llassert_always(iter != mReaders.end() || abort);
1498 LLTextureCacheWorker* worker = iter->second; 1493 LLTextureCacheWorker* worker = iter->second;
1499 bool res = worker->complete(); 1494 bool res = worker->complete();
1500 if (res || abort) 1495 if (res || abort)
@@ -1528,14 +1523,10 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio
1528 purgeTextures(false); 1523 purgeTextures(false);
1529 mDoPurge = FALSE; 1524 mDoPurge = FALSE;
1530 } 1525 }
1531
1532 purgeTextureFilesTimeSliced(); // purge textures from cache in a non-hiccup-way
1533
1534
1535 LLMutexLock lock(&mWorkersMutex); 1526 LLMutexLock lock(&mWorkersMutex);
1536 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, 1527 LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
1537 data, datasize, 0, 1528 data, datasize, 0,
1538 imagesize, responder); 1529 imagesize, responder);
1539 handle_t handle = worker->write(); 1530 handle_t handle = worker->write();
1540 mWriters[handle] = worker; 1531 mWriters[handle] = worker;
1541 return handle; 1532 return handle;
@@ -1581,24 +1572,17 @@ void LLTextureCache::addCompleted(Responder* responder, bool success)
1581 1572
1582bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id) 1573bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
1583{ 1574{
1584 if (mReadOnly) 1575 if (!mReadOnly)
1585 {
1586 return false;
1587 }
1588 LLMutexLock lock(&mHeaderMutex);
1589 id_map_t::iterator iter = mHeaderIDMap.find(id);
1590 if (iter != mHeaderIDMap.end())
1591 { 1576 {
1592 S32 idx = iter->second; 1577 LLMutexLock lock(&mHeaderMutex);
1578 Entry entry;
1579 S32 idx = openAndReadEntry(id, entry, false);
1593 if (idx >= 0) 1580 if (idx >= 0)
1594 { 1581 {
1595 Entry* entry = new Entry(id, -1, time(NULL)); 1582 entry.mImageSize = -1;
1596 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); 1583 entry.mBodySize = 0;
1597 1584 writeEntryAndClose(idx, entry);
1598 LLAPRFile::writeEx(mHeaderEntriesFileName, 1585 mFreeList.insert(idx);
1599 (U8*)entry, offset, sizeof(Entry));
1600 delete entry;
1601 mLRU[idx] = id;
1602 mHeaderIDMap.erase(id); 1586 mHeaderIDMap.erase(id);
1603 mTexturesSizeMap.erase(id); 1587 mTexturesSizeMap.erase(id);
1604 return true; 1588 return true;
diff --git a/linden/indra/newview/lltexturecache.h b/linden/indra/newview/lltexturecache.h
index 1e3ed5b..e4f6934 100644
--- a/linden/indra/newview/lltexturecache.h
+++ b/linden/indra/newview/lltexturecache.h
@@ -48,6 +48,27 @@ class LLTextureCache : public LLWorkerThread
48 friend class LLTextureCacheRemoteWorker; 48 friend class LLTextureCacheRemoteWorker;
49 friend class LLTextureCacheLocalFileWorker; 49 friend class LLTextureCacheLocalFileWorker;
50 50
51private:
52 // Entries
53 struct EntriesInfo
54 {
55 EntriesInfo() : mVersion(0.f), mEntries(0) {}
56 F32 mVersion;
57 U32 mEntries;
58 };
59 struct Entry
60 {
61 Entry() {}
62 Entry(const LLUUID& id, S32 imagesize, S32 bodysize, U32 time) :
63 mID(id), mImageSize(imagesize), mBodySize(bodysize), mTime(time) {}
64 void init(const LLUUID& id, U32 time) { mID = id, mImageSize = 0; mBodySize = 0; mTime = time; }
65 LLUUID mID; // 16 bytes
66 S32 mImageSize; // total size of image if known
67 S32 mBodySize; // size of body file in body cache
68 U32 mTime; // seconds since 1/1/1970
69 };
70
71
51public: 72public:
52 73
53 class Responder : public LLResponder 74 class Responder : public LLResponder
@@ -106,10 +127,14 @@ public:
106 // debug 127 // debug
107 S32 getNumReads() { return mReaders.size(); } 128 S32 getNumReads() { return mReaders.size(); }
108 S32 getNumWrites() { return mWriters.size(); } 129 S32 getNumWrites() { return mWriters.size(); }
130 S64 getUsage() { return mTexturesSizeTotal; }
131 S64 getMaxUsage() { return sCacheMaxTexturesSize; }
132 U32 getEntries() { return mHeaderEntriesInfo.mEntries; }
133 U32 getMaxEntries() { return sCacheMaxEntries; };
109 134
110protected: 135protected:
111 // Accessed by LLTextureCacheWorker 136 // Accessed by LLTextureCacheWorker
112 bool appendToTextureEntryList(const LLUUID& id, S32 size); 137 bool updateTextureEntryList(const LLUUID& id, S32 size);
113 std::string getLocalFileName(const LLUUID& id); 138 std::string getLocalFileName(const LLUUID& id);
114 std::string getTextureFileName(const LLUUID& id); 139 std::string getTextureFileName(const LLUUID& id);
115 void addCompleted(Responder* responder, bool success); 140 void addCompleted(Responder* responder, bool success);
@@ -122,8 +147,16 @@ private:
122 void readHeaderCache(); 147 void readHeaderCache();
123 void purgeAllTextures(bool purge_directories); 148 void purgeAllTextures(bool purge_directories);
124 void purgeTextures(bool validate); 149 void purgeTextures(bool validate);
125 void purgeTextureFilesTimeSliced(BOOL force_all = FALSE); 150 LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset);
126 S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL); 151 void closeHeaderEntriesFile();
152 void readEntriesHeader();
153 void writeEntriesHeader();
154 S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create);
155 void writeEntryAndClose(S32 idx, Entry& entry);
156 U32 openAndReadEntries(std::vector<Entry>& entries);
157 void writeEntriesAndClose(const std::vector<Entry>& entries);
158 S32 getHeaderCacheEntry(const LLUUID& id, S32& imagesize);
159 S32 setHeaderCacheEntry(const LLUUID& id, S32 imagesize);
127 bool removeHeaderCacheEntry(const LLUUID& id); 160 bool removeHeaderCacheEntry(const LLUUID& id);
128 void lockHeaders() { mHeaderMutex.lock(); } 161 void lockHeaders() { mHeaderMutex.lock(); }
129 void unlockHeaders() { mHeaderMutex.unlock(); } 162 void unlockHeaders() { mHeaderMutex.unlock(); }
@@ -133,6 +166,7 @@ private:
133 LLMutex mWorkersMutex; 166 LLMutex mWorkersMutex;
134 LLMutex mHeaderMutex; 167 LLMutex mHeaderMutex;
135 LLMutex mListMutex; 168 LLMutex mListMutex;
169 LLAPRFile* mHeaderAPRFile;
136 170
137 typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t; 171 typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
138 handle_map_t mReaders; 172 handle_map_t mReaders;
@@ -143,49 +177,31 @@ private:
143 177
144 typedef std::vector<std::pair<LLPointer<Responder>, bool> > responder_list_t; 178 typedef std::vector<std::pair<LLPointer<Responder>, bool> > responder_list_t;
145 responder_list_t mCompletedList; 179 responder_list_t mCompletedList;
146
147 typedef std::list<std::string> filename_list_t;
148 filename_list_t mFilesToDelete;
149 LLTimer mTimeLastFileDelete;
150 180
151 BOOL mReadOnly; 181 BOOL mReadOnly;
152 182
153 // Entries
154 struct EntriesInfo
155 {
156 F32 mVersion;
157 U32 mEntries;
158 };
159 struct Entry
160 {
161 Entry() {}
162 Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {}
163 LLUUID mID; // 128 bits
164 S32 mSize; // total size of image if known (NOT size cached)
165 U32 mTime; // seconds since 1/1/1970
166 };
167
168 // HEADERS (Include first mip) 183 // HEADERS (Include first mip)
169 std::string mHeaderEntriesFileName; 184 std::string mHeaderEntriesFileName;
170 std::string mHeaderDataFileName; 185 std::string mHeaderDataFileName;
171 EntriesInfo mHeaderEntriesInfo; 186 EntriesInfo mHeaderEntriesInfo;
172 typedef std::map<S32,LLUUID> index_map_t; 187 std::set<S32> mFreeList; // deleted entries
173 index_map_t mLRU; // index, id; stored as a map for fast removal 188 std::set<LLUUID> mLRU;
174 typedef std::map<LLUUID,S32> id_map_t; 189 typedef std::map<LLUUID,S32> id_map_t;
175 id_map_t mHeaderIDMap; 190 id_map_t mHeaderIDMap;
176 191
177 // BODIES (TEXTURES minus headers) 192 // BODIES (TEXTURES minus headers)
178 std::string mTexturesDirName; 193 std::string mTexturesDirName;
179 std::string mTexturesDirEntriesFileName;
180 typedef std::map<LLUUID,S32> size_map_t; 194 typedef std::map<LLUUID,S32> size_map_t;
181 size_map_t mTexturesSizeMap; 195 size_map_t mTexturesSizeMap;
182 S64 mTexturesSizeTotal; 196 S64 mTexturesSizeTotal;
183 LLAtomic32<BOOL> mDoPurge; 197 LLAtomic32<BOOL> mDoPurge;
184 198
185 // Statics 199 // Statics
186 static F32 sHeaderCacheVersion; 200 static F32 sHeaderCacheVersion;
187 static U32 sCacheMaxEntries; 201 static U32 sCacheMaxEntries;
188 static S64 sCacheMaxTexturesSize; 202 static S64 sCacheMaxTexturesSize;
189}; 203};
190 204
205extern const S32 TEXTURE_CACHE_ENTRY_SIZE;
206
191#endif // LL_LLTEXTURECACHE_H 207#endif // LL_LLTEXTURECACHE_H
diff --git a/linden/indra/newview/lltexturectrl.cpp b/linden/indra/newview/lltexturectrl.cpp
index 5500973..f4476fb 100644
--- a/linden/indra/newview/lltexturectrl.cpp
+++ b/linden/indra/newview/lltexturectrl.cpp
@@ -556,12 +556,12 @@ void LLFloaterTexturePicker::draw()
556 if(mImageAssetID.notNull()) 556 if(mImageAssetID.notNull())
557 { 557 {
558 mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); 558 mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO);
559 mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); 559 mTexturep->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW);
560 } 560 }
561 else if (!mFallbackImageName.empty()) 561 else if (!mFallbackImageName.empty())
562 { 562 {
563 mTexturep = gImageList.getImageFromFile(mFallbackImageName); 563 mTexturep = gImageList.getImageFromFile(mFallbackImageName);
564 mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); 564 mTexturep->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW);
565 } 565 }
566 566
567 if (mTentativeLabel) 567 if (mTentativeLabel)
@@ -1314,13 +1314,13 @@ void LLTextureCtrl::draw()
1314 else if (!mImageAssetID.isNull()) 1314 else if (!mImageAssetID.isNull())
1315 { 1315 {
1316 mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); 1316 mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO);
1317 mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); 1317 mTexturep->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW);
1318 } 1318 }
1319 else if (!mFallbackImageName.empty()) 1319 else if (!mFallbackImageName.empty())
1320 { 1320 {
1321 // Show fallback image. 1321 // Show fallback image.
1322 mTexturep = gImageList.getImageFromFile(mFallbackImageName); 1322 mTexturep = gImageList.getImageFromFile(mFallbackImageName);
1323 mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); 1323 mTexturep->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW);
1324 } 1324 }
1325 1325
1326 // Border 1326 // Border
diff --git a/linden/indra/newview/lltexturefetch.cpp b/linden/indra/newview/lltexturefetch.cpp
index e9dd792..935b8cc 100644
--- a/linden/indra/newview/lltexturefetch.cpp
+++ b/linden/indra/newview/lltexturefetch.cpp
@@ -32,108 +32,35 @@
32 32
33#include "llviewerprecompiledheaders.h" 33#include "llviewerprecompiledheaders.h"
34 34
35#include <iostream>
36
35#include "llstl.h" 37#include "llstl.h"
36 38
37#include "lltexturefetch.h" 39#include "lltexturefetch.h"
38 40
39#include "llcurl.h" 41#include "llcurl.h"
42#include "lldir.h"
40#include "llhttpclient.h" 43#include "llhttpclient.h"
44#include "llhttpstatuscodes.h"
41#include "llimage.h" 45#include "llimage.h"
42#include "llimageworker.h" 46#include "llimageworker.h"
43#include "llworkerthread.h" 47#include "llworkerthread.h"
44 48
45#include "llagent.h" 49#include "llagent.h"
46#include "lltexturecache.h" 50#include "lltexturecache.h"
51#include "llviewercontrol.h"
47#include "llviewerimagelist.h" 52#include "llviewerimagelist.h"
48#include "llviewerimage.h" 53#include "llviewerimage.h"
49#include "llviewerregion.h" 54#include "llviewerregion.h"
55#include "llworld.h"
50 56
51////////////////////////////////////////////////////////////////////////////// 57//////////////////////////////////////////////////////////////////////////////
52//static
53class LLTextureFetchWorker : public LLWorkerClass 58class LLTextureFetchWorker : public LLWorkerClass
54{ 59{
55friend class LLTextureFetch; 60 friend class LLTextureFetch;
56 61 friend class HTTPGetResponder;
57private:
58#if 0
59 class URLResponder : public LLHTTPClient::Responder
60 {
61 public:
62 URLResponder(LLTextureFetch* fetcher, const LLUUID& id)
63 : mFetcher(fetcher), mID(id)
64 {
65 }
66 ~URLResponder()
67 {
68 }
69 virtual void error(U32 status, const std::string& reason)
70 {
71 mFetcher->lockQueue();
72 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
73 if (worker)
74 {
75// llwarns << "LLTextureFetchWorker::URLResponder::error " << status << ": " << reason << llendl;
76 worker->callbackURLReceived(LLSD(), false);
77 }
78 mFetcher->unlockQueue();
79 }
80 virtual void result(const LLSD& content)
81 {
82 mFetcher->lockQueue();
83 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
84 if (worker)
85 {
86 worker->callbackURLReceived(content, true);
87 }
88 mFetcher->unlockQueue();
89 }
90 private:
91 LLTextureFetch* mFetcher;
92 LLUUID mID;
93 };
94
95 class HTTPGetResponder : public LLHTTPClient::Responder
96 {
97 public:
98 HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id)
99 : mFetcher(fetcher), mID(id)
100 {
101 }
102 ~HTTPGetResponder()
103 {
104 }
105 virtual void completed(U32 status, const std::stringstream& content)
106 {
107 mFetcher->lockQueue();
108 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
109 if (worker)
110 {
111 const std::string& cstr = content.str();
112 if (200 <= status && status < 300)
113 {
114 if (203 == status) // partial information (i.e. last block)
115 {
116 worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), true);
117 }
118 else
119 {
120 worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), false);
121 }
122 }
123 else
124 {
125// llinfos << "LLTextureFetchWorker::HTTPGetResponder::error " << status << ": " << cstr << llendl;
126 worker->callbackHttpGet(NULL, -1, true);
127 }
128 }
129 mFetcher->unlockQueue();
130 }
131 private:
132 LLTextureFetch* mFetcher;
133 LLUUID mID;
134 };
135#endif
136 62
63private:
137 class CacheReadResponder : public LLTextureCache::ReadResponder 64 class CacheReadResponder : public LLTextureCache::ReadResponder
138 { 65 {
139 public: 66 public:
@@ -179,20 +106,20 @@ private:
179 LLUUID mID; 106 LLUUID mID;
180 }; 107 };
181 108
182 class DecodeResponder : public LLResponder 109 class DecodeResponder : public LLImageDecodeThread::Responder
183 { 110 {
184 public: 111 public:
185 DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker) 112 DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker)
186 : mFetcher(fetcher), mID(id), mWorker(worker) 113 : mFetcher(fetcher), mID(id), mWorker(worker)
187 { 114 {
188 } 115 }
189 virtual void completed(bool success) 116 virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
190 { 117 {
191 mFetcher->lockQueue(); 118 mFetcher->lockQueue();
192 LLTextureFetchWorker* worker = mFetcher->getWorker(mID); 119 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
193 if (worker) 120 if (worker)
194 { 121 {
195 worker->callbackDecoded(success); 122 worker->callbackDecoded(success, raw, aux);
196 } 123 }
197 mFetcher->unlockQueue(); 124 mFetcher->unlockQueue();
198 } 125 }
@@ -225,39 +152,47 @@ public:
225 /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD) 152 /*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
226 153
227 ~LLTextureFetchWorker(); 154 ~LLTextureFetchWorker();
228 void relese() { --mActiveCount; } 155 void release() { --mActiveCount; }
156
157 void callbackHttpGet(const LLChannelDescriptors& channels,
158 const LLIOPipe::buffer_ptr_t& buffer,
159 bool last_block, bool success);
160 void callbackCacheRead(bool success, LLImageFormatted* image,
161 S32 imagesize, BOOL islocal);
162 void callbackCacheWrite(bool success);
163 void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
164
165 void setGetStatus(U32 status, const std::string& reason)
166 {
167 mGetStatus = status;
168 mGetReason = reason;
169 }
229 170
230protected: 171protected:
231 LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host, 172 LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
232 F32 priority, S32 discard, S32 size); 173 F32 priority, S32 discard, S32 size);
174 LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
175 F32 priority, S32 discard, S32 size);
233 176
234private: 177private:
235 /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD) 178 /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
236 /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD) 179 /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
237 180
238 virtual std::string getName() { return LLStringUtil::null; }
239 void resetFormattedData(); 181 void resetFormattedData();
240 182
241 void setImagePriority(F32 priority); 183 void setImagePriority(F32 priority);
242 void setDesiredDiscard(S32 discard, S32 size); 184 void setDesiredDiscard(S32 discard, S32 size);
243 bool insertPacket(S32 index, U8* data, S32 size); 185 bool insertPacket(S32 index, U8* data, S32 size);
244 void clearPackets(); 186 void clearPackets();
187 void setupPacketData();
245 U32 calcWorkPriority(); 188 U32 calcWorkPriority();
246 void removeFromCache(); 189 void removeFromCache();
247 bool processSimulatorPackets(); 190 bool processSimulatorPackets();
248 bool decodeImage();
249 bool writeToCacheComplete(); 191 bool writeToCacheComplete();
250 192
251 void lockWorkData() { mWorkMutex.lock(); } 193 void lockWorkMutex() { mWorkMutex.lock(); }
252 void unlockWorkData() { mWorkMutex.unlock(); } 194 void unlockWorkMutex() { mWorkMutex.unlock(); }
253 195
254 void callbackURLReceived(const LLSD& data, bool success);
255 void callbackHttpGet(U8* data, S32 data_size, bool last_block);
256 void callbackCacheRead(bool success, LLImageFormatted* image,
257 S32 imagesize, BOOL islocal);
258 void callbackCacheWrite(bool success);
259 void callbackDecoded(bool success);
260
261private: 196private:
262 enum e_state // mState 197 enum e_state // mState
263 { 198 {
@@ -268,8 +203,8 @@ private:
268 CACHE_POST, 203 CACHE_POST,
269 LOAD_FROM_NETWORK, 204 LOAD_FROM_NETWORK,
270 LOAD_FROM_SIMULATOR, 205 LOAD_FROM_SIMULATOR,
271 LOAD_FROM_HTTP_GET_URL, 206 SEND_HTTP_REQ,
272 LOAD_FROM_HTTP_GET_DATA, 207 WAIT_HTTP_REQ,
273 DECODE_IMAGE, 208 DECODE_IMAGE,
274 DECODE_IMAGE_UPDATE, 209 DECODE_IMAGE_UPDATE,
275 WRITE_TO_CACHE, 210 WRITE_TO_CACHE,
@@ -280,19 +215,17 @@ private:
280 { 215 {
281 UNSENT = 0, 216 UNSENT = 0,
282 QUEUED = 1, 217 QUEUED = 1,
283 SENT_SIM = 2, 218 SENT_SIM = 2
284 SENT_URL = 3,
285 SENT_HTTP = 4
286 }; 219 };
287 static const char* sStateDescs[]; 220 static const char* sStateDescs[];
288 e_state mState; 221 e_state mState;
289 LLTextureFetch* mFetcher; 222 LLTextureFetch* mFetcher;
290 LLImageWorker* mImageWorker;
291 LLPointer<LLImageFormatted> mFormattedImage; 223 LLPointer<LLImageFormatted> mFormattedImage;
292 LLPointer<LLImageRaw> mRawImage; 224 LLPointer<LLImageRaw> mRawImage;
293 LLPointer<LLImageRaw> mAuxImage; 225 LLPointer<LLImageRaw> mAuxImage;
294 LLUUID mID; 226 LLUUID mID;
295 LLHost mHost; 227 LLHost mHost;
228 std::string mUrl;
296 U8 mType; 229 U8 mType;
297 F32 mImagePriority; 230 F32 mImagePriority;
298 U32 mWorkPriority; 231 U32 mWorkPriority;
@@ -314,15 +247,18 @@ private:
314 S32 mCachedSize; 247 S32 mCachedSize;
315 BOOL mLoaded; 248 BOOL mLoaded;
316 e_request_state mSentRequest; 249 e_request_state mSentRequest;
250 handle_t mDecodeHandle;
317 BOOL mDecoded; 251 BOOL mDecoded;
318 BOOL mWritten; 252 BOOL mWritten;
319 BOOL mNeedsAux; 253 BOOL mNeedsAux;
320 BOOL mHaveAllData; 254 BOOL mHaveAllData;
321 BOOL mInLocalCache; 255 BOOL mInLocalCache;
256 S32 mHTTPFailCount;
322 S32 mRetryAttempt; 257 S32 mRetryAttempt;
323 std::string mURL;
324 S32 mActiveCount; 258 S32 mActiveCount;
325 259 U32 mGetStatus;
260 std::string mGetReason;
261
326 // Work Data 262 // Work Data
327 LLMutex mWorkMutex; 263 LLMutex mWorkMutex;
328 struct PacketData 264 struct PacketData
@@ -340,25 +276,79 @@ private:
340 U8 mImageCodec; 276 U8 mImageCodec;
341}; 277};
342 278
343class LLTextureFetchLocalFileWorker : public LLTextureFetchWorker 279//////////////////////////////////////////////////////////////////////////////
344{
345friend class LLTextureFetch;
346
347protected:
348 LLTextureFetchLocalFileWorker(LLTextureFetch* fetcher, const std::string& filename, const LLUUID& id, const LLHost& host,
349 F32 priority, S32 discard, S32 size)
350 : LLTextureFetchWorker(fetcher, id, host, priority, discard, size),
351 mFileName(filename)
352 {}
353 280
354private: 281class HTTPGetResponder : public LLCurl::Responder
355 /*virtual*/ std::string getName() { return mFileName; } 282{
283 LOG_CLASS(HTTPGetResponder);
284public:
285 HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset)
286 : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset)
287 {
288 }
289 ~HTTPGetResponder()
290 {
291 }
356 292
293 virtual void completedRaw(U32 status, const std::string& reason,
294 const LLChannelDescriptors& channels,
295 const LLIOPipe::buffer_ptr_t& buffer)
296 {
297 if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
298 {
299 mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime);
300 U64 timeNow = LLTimer::getTotalTime();
301 mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
302 mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
303 mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
304 mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
305 }
357 306
307 lldebugs << "HTTP COMPLETE: " << mID << llendl;
308 mFetcher->lockQueue();
309 LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
310 if (worker)
311 {
312 bool success = false;
313 bool partial = false;
314 if (200 <= status && status < 300)
315 {
316 success = true;
317 if (HTTP_PARTIAL_CONTENT == status) // partial information (i.e. last block)
318 {
319 partial = true;
320 }
321 }
322 else
323 {
324 worker->setGetStatus(status, reason);
325// llwarns << status << ": " << reason << llendl;
326 }
327 if (!success)
328 {
329 worker->setGetStatus(status, reason);
330// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
331 }
332 mFetcher->removeFromHTTPQueue(mID);
333 worker->callbackHttpGet(channels, buffer, partial, success);
334 }
335 else
336 {
337 mFetcher->removeFromHTTPQueue(mID);
338 llwarns << "Worker not found: " << mID << llendl;
339 }
340 mFetcher->unlockQueue();
341 }
342
358private: 343private:
359 std::string mFileName; 344 LLTextureFetch* mFetcher;
345 LLUUID mID;
346 U64 mStartTime;
347 S32 mRequestedSize;
348 U32 mOffset;
360}; 349};
361 350
351//////////////////////////////////////////////////////////////////////////////
362 352
363//static 353//static
364const char* LLTextureFetchWorker::sStateDescs[] = { 354const char* LLTextureFetchWorker::sStateDescs[] = {
@@ -368,8 +358,8 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
368 "CACHE_POST", 358 "CACHE_POST",
369 "LOAD_FROM_NETWORK", 359 "LOAD_FROM_NETWORK",
370 "LOAD_FROM_SIMULATOR", 360 "LOAD_FROM_SIMULATOR",
371 "LOAD_FROM_HTTP_URL", 361 "SEND_HTTP_REQ",
372 "LOAD_FROM_HTTP_DATA", 362 "WAIT_HTTP_REQ",
373 "DECODE_IMAGE", 363 "DECODE_IMAGE",
374 "DECODE_IMAGE_UPDATE", 364 "DECODE_IMAGE_UPDATE",
375 "WRITE_TO_CACHE", 365 "WRITE_TO_CACHE",
@@ -380,6 +370,7 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
380// called from MAIN THREAD 370// called from MAIN THREAD
381 371
382LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, 372LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
373 const std::string& url, // Optional URL
383 const LLUUID& id, // Image UUID 374 const LLUUID& id, // Image UUID
384 const LLHost& host, // Simulator host 375 const LLHost& host, // Simulator host
385 F32 priority, // Priority 376 F32 priority, // Priority
@@ -388,9 +379,9 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
388 : LLWorkerClass(fetcher, "TextureFetch"), 379 : LLWorkerClass(fetcher, "TextureFetch"),
389 mState(INIT), 380 mState(INIT),
390 mFetcher(fetcher), 381 mFetcher(fetcher),
391 mImageWorker(NULL),
392 mID(id), 382 mID(id),
393 mHost(host), 383 mHost(host),
384 mUrl(url),
394 mImagePriority(priority), 385 mImagePriority(priority),
395 mWorkPriority(0), 386 mWorkPriority(0),
396 mRequestedPriority(0.f), 387 mRequestedPriority(0.f),
@@ -409,13 +400,16 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
409 mCachedSize(0), 400 mCachedSize(0),
410 mLoaded(FALSE), 401 mLoaded(FALSE),
411 mSentRequest(UNSENT), 402 mSentRequest(UNSENT),
403 mDecodeHandle(0),
412 mDecoded(FALSE), 404 mDecoded(FALSE),
413 mWritten(FALSE), 405 mWritten(FALSE),
414 mNeedsAux(FALSE), 406 mNeedsAux(FALSE),
415 mHaveAllData(FALSE), 407 mHaveAllData(FALSE),
416 mInLocalCache(FALSE), 408 mInLocalCache(FALSE),
409 mHTTPFailCount(0),
417 mRetryAttempt(0), 410 mRetryAttempt(0),
418 mActiveCount(0), 411 mActiveCount(0),
412 mGetStatus(0),
419 mWorkMutex(NULL), 413 mWorkMutex(NULL),
420 mFirstPacket(0), 414 mFirstPacket(0),
421 mLastPacket(-1), 415 mLastPacket(-1),
@@ -425,12 +419,14 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
425 calcWorkPriority(); 419 calcWorkPriority();
426 mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL; 420 mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
427// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl; 421// llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
422 lockWorkMutex();
428 if (!mFetcher->mDebugPause) 423 if (!mFetcher->mDebugPause)
429 { 424 {
430 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; 425 U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
431 addWork(0, work_priority ); 426 addWork(0, work_priority );
432 } 427 }
433 setDesiredDiscard(discard, size); 428 setDesiredDiscard(discard, size);
429 unlockWorkMutex();
434} 430}
435 431
436LLTextureFetchWorker::~LLTextureFetchWorker() 432LLTextureFetchWorker::~LLTextureFetchWorker()
@@ -440,7 +436,7 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
440// << " Requested=" << mRequestedDiscard 436// << " Requested=" << mRequestedDiscard
441// << " Desired=" << mDesiredDiscard << llendl; 437// << " Desired=" << mDesiredDiscard << llendl;
442 llassert_always(!haveWork()); 438 llassert_always(!haveWork());
443 lockWorkData(); 439 lockWorkMutex();
444 if (mCacheReadHandle != LLTextureCache::nullHandle()) 440 if (mCacheReadHandle != LLTextureCache::nullHandle())
445 { 441 {
446 mFetcher->mTextureCache->readComplete(mCacheReadHandle, true); 442 mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
@@ -449,13 +445,9 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
449 { 445 {
450 mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true); 446 mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
451 } 447 }
452 if (mImageWorker)
453 {
454 mImageWorker->scheduleDelete();
455 }
456 mFormattedImage = NULL; 448 mFormattedImage = NULL;
457 clearPackets(); 449 clearPackets();
458 unlockWorkData(); 450 unlockWorkMutex();
459} 451}
460 452
461void LLTextureFetchWorker::clearPackets() 453void LLTextureFetchWorker::clearPackets()
@@ -467,6 +459,38 @@ void LLTextureFetchWorker::clearPackets()
467 mFirstPacket = 0; 459 mFirstPacket = 0;
468} 460}
469 461
462void LLTextureFetchWorker::setupPacketData()
463{
464 S32 data_size = 0;
465 if (mFormattedImage.notNull())
466 {
467 data_size = mFormattedImage->getDataSize();
468 }
469 if (data_size > 0)
470 {
471 // Only used for simulator requests
472 mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
473 if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
474 {
475 llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
476 removeFromCache();
477 resetFormattedData();
478 clearPackets();
479 }
480 else if (mFileSize > 0)
481 {
482 mLastPacket = mFirstPacket-1;
483 mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
484 }
485 else
486 {
487 // This file was cached using HTTP so we have to refetch the first packet
488 resetFormattedData();
489 clearPackets();
490 }
491 }
492}
493
470U32 LLTextureFetchWorker::calcWorkPriority() 494U32 LLTextureFetchWorker::calcWorkPriority()
471{ 495{
472// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerImage::maxDecodePriority()); 496// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerImage::maxDecodePriority());
@@ -538,7 +562,6 @@ void LLTextureFetchWorker::resetFormattedData()
538// Called from MAIN thread 562// Called from MAIN thread
539void LLTextureFetchWorker::startWork(S32 param) 563void LLTextureFetchWorker::startWork(S32 param)
540{ 564{
541 llassert(mImageWorker == NULL);
542 llassert(mFormattedImage.isNull()); 565 llassert(mFormattedImage.isNull());
543} 566}
544 567
@@ -549,6 +572,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
549{ 572{
550 LLMutexLock lock(&mWorkMutex); 573 LLMutexLock lock(&mWorkMutex);
551 574
575 if ((mFetcher->isQuitting() || (mImagePriority <= 0.0f) || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
576 {
577 if (mState < WRITE_TO_CACHE)
578 {
579 return true; // abort
580 }
581 }
582
552 if (mFetcher->mDebugPause) 583 if (mFetcher->mDebugPause)
553 { 584 {
554 return false; // debug: don't do any work 585 return false; // debug: don't do any work
@@ -563,14 +594,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
563 mFetchTimer.reset(); 594 mFetchTimer.reset();
564 } 595 }
565 596
566 if (mImagePriority <= 0.0f)
567 {
568 if (mState < WRITE_TO_CACHE)
569 {
570 return true; // cancel request
571 }
572 }
573
574 if (mState == INIT) 597 if (mState == INIT)
575 { 598 {
576 mRequestedDiscard = -1; 599 mRequestedDiscard = -1;
@@ -590,7 +613,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
590 clearPackets(); // TODO: Shouldn't be necessary 613 clearPackets(); // TODO: Shouldn't be necessary
591 mCacheReadHandle = LLTextureCache::nullHandle(); 614 mCacheReadHandle = LLTextureCache::nullHandle();
592 mCacheWriteHandle = LLTextureCache::nullHandle(); 615 mCacheWriteHandle = LLTextureCache::nullHandle();
593 mURL.clear();
594 mState = LOAD_FROM_TEXTURE_CACHE; 616 mState = LOAD_FROM_TEXTURE_CACHE;
595 // fall through 617 // fall through
596 } 618 }
@@ -612,16 +634,27 @@ bool LLTextureFetchWorker::doWork(S32 param)
612 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it 634 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
613 635
614 CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); 636 CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
615 if (getName().empty()) 637 if (mUrl.compare(0, 7, "file://") == 0)
638 {
639 // read file from local disk
640 std::string filename = mUrl.substr(7, std::string::npos);
641 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
642 offset, size, responder);
643 }
644 else if (mUrl.empty())
616 { 645 {
617 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, 646 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
618 offset, size, responder); 647 offset, size, responder);
619 } 648 }
620 else 649 else
621 { 650 {
622 // read file from local disk 651 if (!(mUrl.compare(0, 7, "http://") == 0))
623 mCacheReadHandle = mFetcher->mTextureCache->readFromCache(getName(), mID, cache_priority, 652 {
624 offset, size, responder); 653 // *TODO:?remove this warning
654 llwarns << "Unknown URL Type: " << mUrl << llendl;
655 }
656 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
657 mState = SEND_HTTP_REQ;
625 } 658 }
626 } 659 }
627 660
@@ -659,67 +692,92 @@ bool LLTextureFetchWorker::doWork(S32 param)
659 } 692 }
660 else 693 else
661 { 694 {
662 if (!getName().empty()) 695 if (mUrl.compare(0, 7, "file://") == 0)
663 { 696 {
664 // failed to load local file, we're done. 697 // failed to load local file, we're done.
665 return true; 698 return true;
666 } 699 }
667 // need more data 700 // need more data
668 mState = LOAD_FROM_NETWORK; 701 else
702 {
703 mState = LOAD_FROM_NETWORK; // CACHE_POST --> LOAD_FROM_NETWORK, or SEND_HTTP_REQ see below.
704 // This is true because mSentRequest is set to UNSENT in INIT and if we get here we went through
705 // the states INIT --> LOAD_FROM_TEXTURE_CACHE --> CACHE_POST. Therefore either
706 // mFetcher->addToNetworkQueue(this) is called below, or mState is set to SEND_HTTP_REQ.
707 llassert(mSentRequest == UNSENT);
708 }
669 // fall through 709 // fall through
670 } 710 }
671 } 711 }
672 712
673 if (mState == LOAD_FROM_NETWORK) 713 if (mState == LOAD_FROM_NETWORK)
674 { 714 {
675 if (mSentRequest == UNSENT) 715 bool get_url = gSavedSettings.getBOOL("ImagePipelineUseHTTP");
716 if (!mUrl.empty()) get_url = false;
717// if (mHost != LLHost::invalid) get_url = false;
718 if ( get_url )
676 { 719 {
677 if (mFormattedImage.isNull()) 720 LLViewerRegion* region = NULL;
678 { 721 if (mHost == LLHost::invalid)
679 mFormattedImage = new LLImageJ2C; 722 region = gAgent.getRegion();
680 } 723 else
681 // Add this to the network queue and sit here. 724 region = LLWorld::getInstance()->getRegion(mHost);
682 // LLTextureFetch::update() will send off a request which will change our state 725
683 S32 data_size = mFormattedImage->getDataSize(); 726 if (region)
684 if (data_size > 0)
685 { 727 {
686 // Only used for simulator requests 728 std::string http_url = region->getCapability("GetTexture");
687 mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1; 729 if (!http_url.empty())
688 if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
689 {
690// llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
691 removeFromCache();
692 resetFormattedData();
693 clearPackets();
694 }
695 else
696 { 730 {
697 mLastPacket = mFirstPacket-1; 731 mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
698 mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
699 } 732 }
700 } 733 }
734 else
735 {
736 llwarns << "Region not found for host: " << mHost << llendl;
737 }
738 }
739 if (!mUrl.empty())
740 {
741 mState = LLTextureFetchWorker::SEND_HTTP_REQ;
742 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
743 // don't return, fall through to next state
744 }
745 else if (mSentRequest == UNSENT)
746 {
747 // Add this to the network queue and sit here.
748 // LLTextureFetch::update() will send off a request which will change our state
701 mRequestedSize = mDesiredSize; 749 mRequestedSize = mDesiredSize;
702 mRequestedDiscard = mDesiredDiscard; 750 mRequestedDiscard = mDesiredDiscard;
703 mSentRequest = QUEUED; 751 mSentRequest = QUEUED;
704 mFetcher->lockQueue();
705 mFetcher->addToNetworkQueue(this); 752 mFetcher->addToNetworkQueue(this);
706 mFetcher->unlockQueue();
707 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); 753 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
754 return false;
755 }
756 else
757 {
758 // Shouldn't need to do anything here
759 //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
760 // Make certain this is in the network queue
761 //mFetcher->addToNetworkQueue(this);
762 //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
763 return false;
708 } 764 }
709 return false;
710 } 765 }
711 766
712 if (mState == LOAD_FROM_SIMULATOR) 767 if (mState == LOAD_FROM_SIMULATOR)
713 { 768 {
769 if (mFormattedImage.isNull())
770 {
771 mFormattedImage = new LLImageJ2C;
772 }
714 if (processSimulatorPackets()) 773 if (processSimulatorPackets())
715 { 774 {
716 mFetcher->lockQueue(); 775 mFetcher->removeFromNetworkQueue(this, false);
717 mFetcher->removeFromNetworkQueue(this);
718 mFetcher->unlockQueue();
719 if (mFormattedImage.isNull() || !mFormattedImage->getDataSize()) 776 if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
720 { 777 {
721 // processSimulatorPackets() failed 778 // processSimulatorPackets() failed
722// llwarns << "processSimulatorPackets() failed to load buffer" << llendl; 779// llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
780 // FIXME: Don't we need a mState change?
723 return true; // failed 781 return true; // failed
724 } 782 }
725 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 783 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
@@ -732,103 +790,91 @@ bool LLTextureFetchWorker::doWork(S32 param)
732 return false; 790 return false;
733 } 791 }
734 792
735#if 0 793 if (mState == SEND_HTTP_REQ)
736 if (mState == LOAD_FROM_HTTP_GET_URL) 794 {
737 { 795 {
738 if (!mSentRequest) 796 const S32 HTTP_QUEUE_MAX_SIZE = 32;
739 { 797 // *TODO: Integrate this with llviewerthrottle
740 mSentRequest = TRUE; 798 // Note: LLViewerThrottle uses dynamic throttling which makes sense for UDP,
741 mLoaded = FALSE; 799 // but probably not for Textures.
742 std::string url; 800 // Set the throttle to the entire bandwidth, assuming UDP packets will get priority
743 LLViewerRegion* region = gAgent.getRegion(); 801 // when they are needed
744 if (region) 802 F32 max_bandwidth = mFetcher->mMaxBandwidth;
803 if ((mFetcher->getHTTPQueueSize() >= HTTP_QUEUE_MAX_SIZE) ||
804 (mFetcher->getTextureBandwidth() > max_bandwidth))
745 { 805 {
746 url = region->getCapability("RequestTextureDownload"); 806 // Make normal priority and return (i.e. wait until there is room in the queue)
747 } 807 setPriority(LLWorkerThread::PRIORITY_NORMAL | mWorkPriority);
748 if (!url.empty())
749 {
750 LLSD sd;
751 sd = mID.asString();
752 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
753 LLHTTPClient::post(url, sd, new URLResponder(mFetcher, mID));
754 return false; 808 return false;
755 } 809 }
756 else 810
811 S32 cur_size = 0;
812 if (mFormattedImage.notNull())
757 { 813 {
758// llwarns << mID << ": HTTP get url failed, requesting from simulator" << llendl; 814 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
759 mSentRequest = FALSE;
760 mState = LOAD_FROM_SIMULATOR;
761 return false;
762 } 815 }
763 }
764 else
765 {
766 if (mLoaded)
767 {
768 if (!mURL.empty())
769 {
770 mState = LOAD_FROM_HTTP_GET_DATA;
771 mSentRequest = FALSE; // reset
772 mLoaded = FALSE; // reset
773 }
774 else
775 {
776// llwarns << mID << ": HTTP get url is empty, requesting from simulator" << llendl;
777 mSentRequest = FALSE;
778 mState = LOAD_FROM_SIMULATOR;
779 return false;
780 }
781 }
782 }
783 // fall through
784 }
785
786 if (mState == LOAD_FROM_HTTP_GET_DATA)
787 {
788 if (!mSentRequest)
789 {
790 mSentRequest = TRUE;
791 S32 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
792 mRequestedSize = mDesiredSize; 816 mRequestedSize = mDesiredSize;
793 mRequestedDiscard = mDesiredDiscard; 817 mRequestedDiscard = mDesiredDiscard;
794#if 1 // *TODO: LLCurl::getByteRange is broken (ignores range)
795 cur_size = 0;
796 mFormattedImage->deleteData();
797#endif
798 mRequestedSize -= cur_size; 818 mRequestedSize -= cur_size;
799 // F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1 819// F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1
800 S32 offset = cur_size; 820 S32 offset = cur_size;
801 mBufferSize = cur_size; // This will get modified by callbackHttpGet() 821 mBufferSize = cur_size; // This will get modified by callbackHttpGet()
802 std::string url; 822
803 if (mURL.empty()) 823 bool res = false;
824 if (!mUrl.empty())
804 { 825 {
805 //url = "http://asset.agni/0000002f-38ae-0e17-8e72-712e58964e9c.texture"; 826 mLoaded = FALSE;
806 std::stringstream urlstr; 827 mGetStatus = 0;
807 urlstr << "http://asset.agni/" << mID.asString() << ".texture"; 828 mGetReason.clear();
808 url = urlstr.str(); 829 lldebugs << "HTTP GET: " << mID << " Offset: " << offset
830 << " Bytes: " << mRequestedSize
831 << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth
832 << llendl;
833 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
834 mState = WAIT_HTTP_REQ;
835
836 mFetcher->addToHTTPQueue(mID);
837 // Will call callbackHttpGet when curl request completes
838 std::vector<std::string> headers;
839 headers.push_back("Accept: image/x-j2c");
840 res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
841 new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset));
809 } 842 }
810 else 843 if (!res)
811 { 844 {
812 url = mURL; 845 llwarns << "HTTP GET request failed for " << mID << llendl;
846 resetFormattedData();
847 ++mHTTPFailCount;
848 return true; // failed
813 } 849 }
814 mLoaded = FALSE; 850 // fall through
815// llinfos << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize << llendl;
816 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
817 LLCurl::getByteRange(url, offset, mRequestedSize,
818 new HTTPGetResponder(mFetcher, mID)); // *TODO: use mWorkPriority
819 return false; // not done
820 } 851 }
821 852 }
853
854 if (mState == WAIT_HTTP_REQ)
855 {
822 if (mLoaded) 856 if (mLoaded)
823 { 857 {
824 S32 cur_size = mFormattedImage->getDataSize(); 858 S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
825 if (mRequestedSize < 0) 859 if (mRequestedSize < 0)
826 { 860 {
827// llwarns << "http get failed for: " << mID << llendl; 861 const S32 HTTP_MAX_RETRY_COUNT = 4;
862 llinfos << "HTTP GET failed for: " << mUrl
863 << " Status: " << mGetStatus << " Reason: " << mGetReason
864 << " Try:" << mHTTPFailCount+1 << "/" << HTTP_MAX_RETRY_COUNT << llendl;
828 if (cur_size == 0) 865 if (cur_size == 0)
829 { 866 {
830 resetFormattedData(); 867 ++mHTTPFailCount;
831 return true; // failed 868 if (mGetStatus == HTTP_NOT_FOUND || mHTTPFailCount >= HTTP_MAX_RETRY_COUNT)
869 {
870 resetFormattedData();
871 return true; // failed
872 }
873 else
874 {
875 mState = SEND_HTTP_REQ;
876 return false; // retry
877 }
832 } 878 }
833 else 879 else
834 { 880 {
@@ -836,6 +882,18 @@ bool LLTextureFetchWorker::doWork(S32 param)
836 return false; // use what we have 882 return false; // use what we have
837 } 883 }
838 } 884 }
885
886 if (mFormattedImage.isNull())
887 {
888 // For now, create formatted image based on extension
889 std::string extension = gDirUtilp->getExtension(mUrl);
890 mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension));
891 if (mFormattedImage.isNull())
892 {
893 mFormattedImage = new LLImageJ2C; // default
894 }
895 }
896
839 llassert_always(mBufferSize == cur_size + mRequestedSize); 897 llassert_always(mBufferSize == cur_size + mRequestedSize);
840 if (mHaveAllData) 898 if (mHaveAllData)
841 { 899 {
@@ -854,16 +912,16 @@ bool LLTextureFetchWorker::doWork(S32 param)
854 mBuffer = NULL; 912 mBuffer = NULL;
855 mBufferSize = 0; 913 mBufferSize = 0;
856 mLoadedDiscard = mRequestedDiscard; 914 mLoadedDiscard = mRequestedDiscard;
857 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
858 mState = DECODE_IMAGE; 915 mState = DECODE_IMAGE;
916 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
917 return false;
918 }
919 else
920 {
921 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
859 return false; 922 return false;
860 } 923 }
861
862 // NOTE: Priority gets updated when the http get completes (in callbackHTTPGet())
863 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
864 return false;
865 } 924 }
866#endif
867 925
868 if (mState == DECODE_IMAGE) 926 if (mState == DECODE_IMAGE)
869 { 927 {
@@ -871,19 +929,19 @@ bool LLTextureFetchWorker::doWork(S32 param)
871 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it 929 setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
872 mRawImage = NULL; 930 mRawImage = NULL;
873 mAuxImage = NULL; 931 mAuxImage = NULL;
874 llassert_always(mImageWorker == NULL);
875 llassert_always(mFormattedImage.notNull()); 932 llassert_always(mFormattedImage.notNull());
876 S32 discard = mHaveAllData ? 0 : mLoadedDiscard; 933 S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
877 U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; 934 U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
878 mDecoded = FALSE; 935 mDecoded = FALSE;
879 mState = DECODE_IMAGE_UPDATE; 936 mState = DECODE_IMAGE_UPDATE;
880 mImageWorker = new LLImageWorker(mFormattedImage, image_priority, discard, new DecodeResponder(mFetcher, mID, this)); 937 mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux,
881 // fall though (need to call requestDecodedData() to start work) 938 new DecodeResponder(mFetcher, mID, this));
939 // fall though
882 } 940 }
883 941
884 if (mState == DECODE_IMAGE_UPDATE) 942 if (mState == DECODE_IMAGE_UPDATE)
885 { 943 {
886 if (decodeImage()) 944 if (mDecoded)
887 { 945 {
888 if (mDecodedDiscard < 0) 946 if (mDecodedDiscard < 0)
889 { 947 {
@@ -891,6 +949,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
891 { 949 {
892 // Cache file should be deleted, try again 950 // Cache file should be deleted, try again
893// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl; 951// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl;
952 llassert_always(mDecodeHandle == 0);
894 mFormattedImage = NULL; 953 mFormattedImage = NULL;
895 ++mRetryAttempt; 954 ++mRetryAttempt;
896 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 955 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
@@ -918,9 +977,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
918 977
919 if (mState == WRITE_TO_CACHE) 978 if (mState == WRITE_TO_CACHE)
920 { 979 {
921 if (mInLocalCache || !mFileSize || mSentRequest == UNSENT) 980 if (mInLocalCache || mSentRequest == UNSENT || mFormattedImage.isNull())
922 { 981 {
923 // If we're in a local cache or we didn't actually receive any new data, skip 982 // If we're in a local cache or we didn't actually receive any new data,
983 // or we failed to load anything, skip
924 mState = DONE; 984 mState = DONE;
925 return false; 985 return false;
926 } 986 }
@@ -979,10 +1039,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
979// Called from MAIN thread 1039// Called from MAIN thread
980void LLTextureFetchWorker::endWork(S32 param, bool aborted) 1040void LLTextureFetchWorker::endWork(S32 param, bool aborted)
981{ 1041{
982 if (mImageWorker) 1042 if (mDecodeHandle != 0)
983 { 1043 {
984 mImageWorker->scheduleDelete(); 1044 mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
985 mImageWorker = NULL; 1045 mDecodeHandle = 0;
986 } 1046 }
987 mFormattedImage = NULL; 1047 mFormattedImage = NULL;
988} 1048}
@@ -1035,7 +1095,7 @@ bool LLTextureFetchWorker::deleteOK()
1035 1095
1036 if ((haveWork() && 1096 if ((haveWork() &&
1037 // not ok to delete from these states 1097 // not ok to delete from these states
1038 ((mState >= LOAD_FROM_HTTP_GET_URL && mState <= LOAD_FROM_HTTP_GET_DATA) || 1098 ((mState >= SEND_HTTP_REQ && mState <= WAIT_HTTP_REQ) ||
1039 (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE)))) 1099 (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
1040 { 1100 {
1041 delete_ok = false; 1101 delete_ok = false;
@@ -1044,7 +1104,6 @@ bool LLTextureFetchWorker::deleteOK()
1044 return delete_ok; 1104 return delete_ok;
1045} 1105}
1046 1106
1047
1048void LLTextureFetchWorker::removeFromCache() 1107void LLTextureFetchWorker::removeFromCache()
1049{ 1108{
1050 if (!mInLocalCache) 1109 if (!mInLocalCache)
@@ -1061,6 +1120,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()
1061 if (mFormattedImage.isNull() || mRequestedSize < 0) 1120 if (mFormattedImage.isNull() || mRequestedSize < 0)
1062 { 1121 {
1063 // not sure how we got here, but not a valid state, abort! 1122 // not sure how we got here, but not a valid state, abort!
1123 llassert_always(mDecodeHandle == 0);
1064 mFormattedImage = NULL; 1124 mFormattedImage = NULL;
1065 return true; 1125 return true;
1066 } 1126 }
@@ -1074,6 +1134,12 @@ bool LLTextureFetchWorker::processSimulatorPackets()
1074 buffer_size += mPackets[i]->mSize; 1134 buffer_size += mPackets[i]->mSize;
1075 } 1135 }
1076 bool have_all_data = mLastPacket >= mTotalPackets-1; 1136 bool have_all_data = mLastPacket >= mTotalPackets-1;
1137 if (mRequestedSize <= 0)
1138 {
1139 // We received a packed but haven't requested anything yet (edge case)
1140 // Return true (we're "done") since we didn't request anything
1141 return true;
1142 }
1077 if (buffer_size >= mRequestedSize || have_all_data) 1143 if (buffer_size >= mRequestedSize || have_all_data)
1078 { 1144 {
1079 /// We have enough (or all) data 1145 /// We have enough (or all) data
@@ -1109,50 +1175,36 @@ bool LLTextureFetchWorker::processSimulatorPackets()
1109 1175
1110////////////////////////////////////////////////////////////////////////////// 1176//////////////////////////////////////////////////////////////////////////////
1111 1177
1112void LLTextureFetchWorker::callbackURLReceived(const LLSD& data, bool success) 1178void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
1179 const LLIOPipe::buffer_ptr_t& buffer,
1180 bool last_block, bool success)
1113{ 1181{
1114#if 0
1115 LLMutexLock lock(&mWorkMutex); 1182 LLMutexLock lock(&mWorkMutex);
1116 if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_URL)
1117 {
1118 llwarns << "callbackURLReceived for unrequested fetch worker, req="
1119 << mSentRequest << " state= " << mState << llendl;
1120 return;
1121 }
1122 if (success)
1123 {
1124 mURL = data.asString();
1125 }
1126 mLoaded = TRUE;
1127 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
1128#endif
1129}
1130 1183
1131////////////////////////////////////////////////////////////////////////////// 1184 if (mState != WAIT_HTTP_REQ)
1132
1133void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_block)
1134{
1135#if 0
1136 LLMutexLock lock(&mWorkMutex);
1137 if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_DATA)
1138 { 1185 {
1139 llwarns << "callbackHttpGet for unrequested fetch worker, req=" 1186 llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
1140 << mSentRequest << " state= " << mState << llendl; 1187 << " req=" << mSentRequest << " state= " << mState << llendl;
1141 return; 1188 return;
1142 } 1189 }
1143// llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
1144 if (mLoaded) 1190 if (mLoaded)
1145 { 1191 {
1146 llwarns << "Duplicate callback for " << mID.asString() << llendl; 1192 llwarns << "Duplicate callback for " << mID.asString() << llendl;
1147 return; // ignore duplicate callback 1193 return; // ignore duplicate callback
1148 } 1194 }
1149 if (data_size >= 0) 1195 if (success)
1150 { 1196 {
1197 // get length of stream:
1198 S32 data_size = buffer->countAfter(channels.in(), NULL);
1199
1200 gImageList.sTextureBits += data_size * 8; // Approximate - does not include header bits
1201
1202 //llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
1151 if (data_size > 0) 1203 if (data_size > 0)
1152 { 1204 {
1205 // *TODO: set the formatted image data here directly to avoid the copy
1153 mBuffer = new U8[data_size]; 1206 mBuffer = new U8[data_size];
1154 // *TODO: set the formatted image data here 1207 buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
1155 memcpy(mBuffer, data, data_size);
1156 mBufferSize += data_size; 1208 mBufferSize += data_size;
1157 if (data_size < mRequestedSize || last_block == true) 1209 if (data_size < mRequestedSize || last_block == true)
1158 { 1210 {
@@ -1160,10 +1212,11 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
1160 } 1212 }
1161 else if (data_size > mRequestedSize) 1213 else if (data_size > mRequestedSize)
1162 { 1214 {
1163 // *TODO: This will happen until we fix LLCurl::getByteRange() 1215 // *TODO: This shouldn't be happening any more
1164// llinfos << "HUH?" << llendl; 1216 llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
1165 mHaveAllData = TRUE; 1217 mHaveAllData = TRUE;
1166 mFormattedImage->deleteData(); 1218 llassert_always(mDecodeHandle == 0);
1219 mFormattedImage = NULL; // discard any previous data we had
1167 mBufferSize = data_size; 1220 mBufferSize = data_size;
1168 } 1221 }
1169 } 1222 }
@@ -1181,7 +1234,6 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
1181 } 1234 }
1182 mLoaded = TRUE; 1235 mLoaded = TRUE;
1183 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 1236 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
1184#endif
1185} 1237}
1186 1238
1187////////////////////////////////////////////////////////////////////////////// 1239//////////////////////////////////////////////////////////////////////////////
@@ -1197,7 +1249,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima
1197 } 1249 }
1198 if (success) 1250 if (success)
1199 { 1251 {
1200 llassert_always(imagesize > 0); 1252 llassert_always(imagesize >= 0);
1201 mFileSize = imagesize; 1253 mFileSize = imagesize;
1202 mFormattedImage = image; 1254 mFormattedImage = image;
1203 mImageCodec = image->getCodec(); 1255 mImageCodec = image->getCodec();
@@ -1225,65 +1277,49 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success)
1225 1277
1226////////////////////////////////////////////////////////////////////////////// 1278//////////////////////////////////////////////////////////////////////////////
1227 1279
1228void LLTextureFetchWorker::callbackDecoded(bool success) 1280void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux)
1229{ 1281{
1282 LLMutexLock lock(&mWorkMutex);
1283 if (mDecodeHandle == 0)
1284 {
1285 return; // aborted, ignore
1286 }
1230 if (mState != DECODE_IMAGE_UPDATE) 1287 if (mState != DECODE_IMAGE_UPDATE)
1231 { 1288 {
1232// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl; 1289// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl;
1290 mDecodeHandle = 0;
1233 return; 1291 return;
1234 } 1292 }
1235// llinfos << mID << " : DECODE COMPLETE " << llendl; 1293 llassert_always(mFormattedImage.notNull());
1236 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); 1294
1237} 1295 mDecodeHandle = 0;
1238 1296 if (success)
1239//////////////////////////////////////////////////////////////////////////////
1240
1241bool LLTextureFetchWorker::decodeImage()
1242{
1243 if(!mImageWorker)
1244 {
1245 //LLTextureFetchWorker is aborted, skip image decoding.
1246 return true ;
1247 }
1248
1249 bool res = true;
1250 if (mRawImage.isNull())
1251 {
1252 res = false;
1253 if (mImageWorker->requestDecodedData(mRawImage, -1))
1254 {
1255 res = true;
1256// llinfos << mID << " : BASE DECODE FINISHED" << llendl;
1257 }
1258 }
1259 if (res &&
1260 (mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
1261 (mNeedsAux && mAuxImage.isNull()))
1262 { 1297 {
1263 res = false; 1298 mRawImage = raw;
1264 if (mImageWorker->requestDecodedAuxData(mAuxImage, 4, -1)) 1299 mAuxImage = aux;
1265 { 1300 mDecodedDiscard = mFormattedImage->getDiscardLevel();
1266 res = true; 1301// llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
1267// llinfos << mID << " : AUX DECODE FINISHED" << llendl;
1268 }
1269 } 1302 }
1270 if (res) 1303 else
1271 { 1304 {
1272 if ((mRawImage.notNull() && mRawImage->getDataSize() > 0) && 1305 if (mFormattedImage.notNull())
1273 (!mNeedsAux || (mAuxImage.notNull() && mAuxImage->getDataSize() > 0)))
1274 { 1306 {
1275 mDecodedDiscard = mFormattedImage->getDiscardLevel(); 1307 LL_WARNS("http-texture") << "DECODE FAILED: id = " << mID << ", Discard = " << (S32)mFormattedImage->getDiscardLevel() << LL_ENDL;
1276// llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
1277 } 1308 }
1278 else 1309 else
1279 { 1310 {
1280// llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl; 1311 LL_WARNS("http-texture") << "DECODE FAILED: id = " << mID << ", mFormattedImage is Null!" << LL_ENDL;
1281 removeFromCache();
1282 } 1312 }
1283 mImageWorker->scheduleDelete(); 1313 removeFromCache();
1284 mImageWorker = NULL; 1314 mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
1285 } 1315 }
1286 return res; 1316 mDecoded = TRUE;
1317// llinfos << mID << " : DECODE COMPLETE " << llendl;
1318 setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
1319 // Set the decode flag at the end of the callback or we trigger race conditions between the fetch thread and the
1320 // decode threads that's calling this callback. The fetch thread might set mFormattedImage to NULL before we
1321 // have time here to call getDiscardLevel() which causes crashes
1322 mDecoded = TRUE;
1287} 1323}
1288 1324
1289////////////////////////////////////////////////////////////////////////////// 1325//////////////////////////////////////////////////////////////////////////////
@@ -1314,15 +1350,21 @@ bool LLTextureFetchWorker::writeToCacheComplete()
1314////////////////////////////////////////////////////////////////////////////// 1350//////////////////////////////////////////////////////////////////////////////
1315// public 1351// public
1316 1352
1317LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded) 1353LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded)
1318 : LLWorkerThread("TextureFetch", threaded), 1354 : LLWorkerThread("TextureFetch", threaded),
1319 mDebugCount(0), 1355 mDebugCount(0),
1320 mDebugPause(FALSE), 1356 mDebugPause(FALSE),
1321 mPacketCount(0), 1357 mPacketCount(0),
1322 mBadPacketCount(0), 1358 mBadPacketCount(0),
1323 mQueueMutex(getAPRPool()), 1359 mQueueMutex(getAPRPool()),
1324 mTextureCache(cache) 1360 mNetworkQueueMutex(getAPRPool()),
1361 mTextureCache(cache),
1362 mImageDecodeThread(imagedecodethread),
1363 mTextureBandwidth(0),
1364 mCurlGetRequest(NULL)
1325{ 1365{
1366 mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
1367 mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
1326} 1368}
1327 1369
1328LLTextureFetch::~LLTextureFetch() 1370LLTextureFetch::~LLTextureFetch()
@@ -1330,13 +1372,7 @@ LLTextureFetch::~LLTextureFetch()
1330 // ~LLQueuedThread() called here 1372 // ~LLQueuedThread() called here
1331} 1373}
1332 1374
1333bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 priority, 1375bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
1334 S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
1335{
1336 return createRequest(LLStringUtil::null, id, host, priority, w, h, c, desired_discard, needs_aux);
1337}
1338
1339bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
1340 S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux) 1376 S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
1341{ 1377{
1342 if (mDebugPause) 1378 if (mDebugPause)
@@ -1361,7 +1397,14 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
1361 } 1397 }
1362 1398
1363 S32 desired_size; 1399 S32 desired_size;
1364 if (desired_discard == 0) 1400 std::string exten = gDirUtilp->getExtension(url);
1401 if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
1402 {
1403 // Only do partial requests for J2C at the moment
1404 //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl;
1405 desired_size = MAX_IMAGE_DATA_SIZE;
1406 }
1407 else if (desired_discard == 0)
1365 { 1408 {
1366 // if we want the entire image, and we know its size, then get it all 1409 // if we want the entire image, and we know its size, then get it all
1367 // (calcDataSizeJ2C() below makes assumptions about how the image 1410 // (calcDataSizeJ2C() below makes assumptions about how the image
@@ -1389,28 +1432,25 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
1389 { 1432 {
1390 return false; // need to wait for previous aborted request to complete 1433 return false; // need to wait for previous aborted request to complete
1391 } 1434 }
1392 worker->lockWorkData(); 1435 worker->lockWorkMutex();
1393 worker->setImagePriority(priority); 1436 worker->setImagePriority(priority);
1394 worker->setDesiredDiscard(desired_discard, desired_size); 1437 worker->setDesiredDiscard(desired_discard, desired_size);
1395 worker->unlockWorkData(); 1438 worker->unlockWorkMutex();
1396 if (!worker->haveWork()) 1439 if (!worker->haveWork())
1397 { 1440 {
1441 worker->lockWorkMutex();
1442 if (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK || worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
1443 {
1444 removeFromNetworkQueue(worker, true);
1445 }
1398 worker->mState = LLTextureFetchWorker::INIT; 1446 worker->mState = LLTextureFetchWorker::INIT;
1447 worker->unlockWorkMutex();
1399 worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); 1448 worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
1400 } 1449 }
1401 } 1450 }
1402 else 1451 else
1403 { 1452 {
1404 if (filename.empty()) 1453 worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
1405 {
1406 // do remote fetch
1407 worker = new LLTextureFetchWorker(this, id, host, priority, desired_discard, desired_size);
1408 }
1409 else
1410 {
1411 // do local file fetch
1412 worker = new LLTextureFetchLocalFileWorker(this, filename, id, host, priority, desired_discard, desired_size);
1413 }
1414 mRequestMap[id] = worker; 1454 mRequestMap[id] = worker;
1415 } 1455 }
1416 worker->mActiveCount++; 1456 worker->mActiveCount++;
@@ -1430,10 +1470,9 @@ void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
1430} 1470}
1431 1471
1432// protected 1472// protected
1433
1434// call lockQueue() first!
1435void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker) 1473void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
1436{ 1474{
1475 LLMutexLock lock(&mNetworkQueueMutex);
1437 if (mRequestMap.find(worker->mID) != mRequestMap.end()) 1476 if (mRequestMap.find(worker->mID) != mRequestMap.end())
1438 { 1477 {
1439 // only add to the queue if in the request map 1478 // only add to the queue if in the request map
@@ -1447,10 +1486,27 @@ void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
1447 } 1486 }
1448} 1487}
1449 1488
1450// call lockQueue() first! 1489void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
1451void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker) 1490{
1491 LLMutexLock lock(&mNetworkQueueMutex);
1492 size_t erased = mNetworkQueue.erase(worker->mID);
1493 if (cancel && erased > 0)
1494 {
1495 mCancelQueue[worker->mHost].insert(worker->mID);
1496 }
1497}
1498
1499// protected
1500void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
1501{
1502 LLMutexLock lock(&mNetworkQueueMutex);
1503 mHTTPTextureQueue.insert(id);
1504}
1505
1506void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id)
1452{ 1507{
1453 mNetworkQueue.erase(worker->mID); 1508 LLMutexLock lock(&mNetworkQueueMutex);
1509 mHTTPTextureQueue.erase(id);
1454} 1510}
1455 1511
1456// call lockQueue() first! 1512// call lockQueue() first!
@@ -1458,11 +1514,7 @@ void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
1458{ 1514{
1459 size_t erased_1 = mRequestMap.erase(worker->mID); 1515 size_t erased_1 = mRequestMap.erase(worker->mID);
1460 llassert_always(erased_1 > 0) ; 1516 llassert_always(erased_1 > 0) ;
1461 size_t erased = mNetworkQueue.erase(worker->mID); 1517 removeFromNetworkQueue(worker, cancel);
1462 if (cancel && erased > 0)
1463 {
1464 mCancelQueue[worker->mHost].insert(worker->mID);
1465 }
1466 llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ; 1518 llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
1467 1519
1468 worker->scheduleDelete(); 1520 worker->scheduleDelete();
@@ -1511,7 +1563,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
1511 } 1563 }
1512 else 1564 else
1513 { 1565 {
1514 worker->lockWorkData(); 1566 worker->lockWorkMutex();
1515 if ((worker->mDecodedDiscard >= 0) && 1567 if ((worker->mDecodedDiscard >= 0) &&
1516 (worker->mDecodedDiscard < discard_level || discard_level < 0) && 1568 (worker->mDecodedDiscard < discard_level || discard_level < 0) &&
1517 (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE)) 1569 (worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE))
@@ -1521,7 +1573,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
1521 if (worker->mRawImage) raw = worker->mRawImage; 1573 if (worker->mRawImage) raw = worker->mRawImage;
1522 if (worker->mAuxImage) aux = worker->mAuxImage; 1574 if (worker->mAuxImage) aux = worker->mAuxImage;
1523 } 1575 }
1524 worker->unlockWorkData(); 1576 worker->unlockWorkMutex();
1525 } 1577 }
1526 } 1578 }
1527 else 1579 else
@@ -1538,9 +1590,9 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
1538 LLTextureFetchWorker* worker = getWorker(id); 1590 LLTextureFetchWorker* worker = getWorker(id);
1539 if (worker) 1591 if (worker)
1540 { 1592 {
1541 worker->lockWorkData(); 1593 worker->lockWorkMutex();
1542 worker->setImagePriority(priority); 1594 worker->setImagePriority(priority);
1543 worker->unlockWorkData(); 1595 worker->unlockWorkMutex();
1544 res = true; 1596 res = true;
1545 } 1597 }
1546 return res; 1598 return res;
@@ -1548,40 +1600,106 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
1548 1600
1549////////////////////////////////////////////////////////////////////////////// 1601//////////////////////////////////////////////////////////////////////////////
1550 1602
1603// MAIN THREAD
1551//virtual 1604//virtual
1552S32 LLTextureFetch::update(U32 max_time_ms) 1605S32 LLTextureFetch::update(U32 max_time_ms)
1553{ 1606{
1554 S32 res; 1607 S32 res;
1608
1609 mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
1610
1555 res = LLWorkerThread::update(max_time_ms); 1611 res = LLWorkerThread::update(max_time_ms);
1556 1612
1557 const F32 REQUEST_TIME = 1.f; 1613 if (!mDebugPause)
1558
1559 // Periodically, gather the list of textures that need data from the network
1560 // And send the requests out to the simulators
1561 if (mNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME)
1562 { 1614 {
1563 mNetworkTimer.reset();
1564 sendRequestListToSimulators(); 1615 sendRequestListToSimulators();
1565 } 1616 }
1566 1617
1567 return res; 1618 return res;
1568} 1619}
1569 1620
1621// WORKER THREAD
1622void LLTextureFetch::startThread()
1623{
1624 // Construct mCurlGetRequest from Worker Thread
1625 mCurlGetRequest = new LLCurlRequest();
1626}
1627
1628// WORKER THREAD
1629void LLTextureFetch::endThread()
1630{
1631 // Destroy mCurlGetRequest from Worker Thread
1632 delete mCurlGetRequest;
1633 mCurlGetRequest = NULL;
1634}
1635
1636// WORKER THREAD
1637void LLTextureFetch::threadedUpdate()
1638{
1639 llassert_always(mCurlGetRequest);
1640
1641 // Limit update frequency
1642 const F32 PROCESS_TIME = 0.05f;
1643 static LLFrameTimer process_timer;
1644 if (process_timer.getElapsedTimeF32() < PROCESS_TIME)
1645 {
1646 return;
1647 }
1648 process_timer.reset();
1649
1650 // Update Curl on same thread as mCurlGetRequest was constructed
1651 S32 processed = mCurlGetRequest->process();
1652 if (processed > 0)
1653 {
1654 lldebugs << "processed: " << processed << " messages." << llendl;
1655 }
1656
1657#if 0
1658 const F32 INFO_TIME = 1.0f;
1659 static LLFrameTimer info_timer;
1660 if (info_timer.getElapsedTimeF32() >= INFO_TIME)
1661 {
1662 S32 q = mCurlGetRequest->getQueued();
1663 if (q > 0)
1664 {
1665 llinfos << "Queued gets: " << q << llendl;
1666 info_timer.reset();
1667 }
1668 }
1669#endif
1670
1671}
1672
1570////////////////////////////////////////////////////////////////////////////// 1673//////////////////////////////////////////////////////////////////////////////
1571 1674
1572void LLTextureFetch::sendRequestListToSimulators() 1675void LLTextureFetch::sendRequestListToSimulators()
1573{ 1676{
1677 // All requests
1678 const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps
1679
1680 // Sim requests
1574 const S32 IMAGES_PER_REQUEST = 50; 1681 const S32 IMAGES_PER_REQUEST = 50;
1575 const F32 LAZY_FLUSH_TIMEOUT = 15.f; // 10.0f // temp 1682 const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
1576 const F32 MIN_REQUEST_TIME = 1.0f; 1683 const F32 MIN_REQUEST_TIME = 1.0f;
1577 const F32 MIN_DELTA_PRIORITY = 1000.f; 1684 const F32 MIN_DELTA_PRIORITY = 1000.f;
1578 1685
1579 LLMutexLock lock(&mQueueMutex); 1686 // Periodically, gather the list of textures that need data from the network
1687 // And send the requests out to the simulators
1688 static LLFrameTimer timer;
1689 if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME)
1690 {
1691 return;
1692 }
1693 timer.reset();
1580 1694
1695 LLMutexLock lock(&mQueueMutex);
1696
1581 // Send requests 1697 // Send requests
1582 typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t; 1698 typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t;
1583 typedef std::map< LLHost, request_list_t > work_request_map_t; 1699 typedef std::map< LLHost, request_list_t > work_request_map_t;
1584 work_request_map_t requests; 1700 work_request_map_t requests;
1701 {
1702 LLMutexLock lock2(&mNetworkQueueMutex);
1585 for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); ) 1703 for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); )
1586 { 1704 {
1587 queue_t::iterator curiter = iter++; 1705 queue_t::iterator curiter = iter++;
@@ -1591,65 +1709,66 @@ void LLTextureFetch::sendRequestListToSimulators()
1591 mNetworkQueue.erase(curiter); 1709 mNetworkQueue.erase(curiter);
1592 continue; // paranoia 1710 continue; // paranoia
1593 } 1711 }
1712 llassert(req->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK || LLTextureFetchWorker::LOAD_FROM_SIMULATOR);
1713 if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) &&
1714 (req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR))
1715 {
1716 // We really should never ever get here anymore.
1717 llwarns << "SNOW-119 failure: Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl;
1718 mNetworkQueue.erase(curiter);
1719 continue;
1720 }
1594 if (req->mID == mDebugID) 1721 if (req->mID == mDebugID)
1595 { 1722 {
1596 mDebugCount++; // for setting breakpoints 1723 mDebugCount++; // for setting breakpoints
1597 } 1724 }
1598 if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1) 1725 if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM &&
1726 req->mTotalPackets > 0 &&
1727 req->mLastPacket >= req->mTotalPackets-1)
1599 { 1728 {
1600 // We have all the packets... make sure this is high priority 1729 // We have all the packets... make sure this is high priority
1601// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority); 1730// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority);
1602 continue; 1731 continue;
1603 } 1732 }
1604 F32 elapsed = req->mRequestedTimer.getElapsedTimeF32(); 1733 F32 elapsed = req->mRequestedTimer.getElapsedTimeF32();
1605 F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
1606 if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
1607 (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
1608 (elapsed >= LAZY_FLUSH_TIMEOUT))
1609 { 1734 {
1610 requests[req->mHost].insert(req); 1735 F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
1736 if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
1737 (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
1738 (elapsed >= SIM_LAZY_FLUSH_TIMEOUT))
1739 {
1740 requests[req->mHost].insert(req);
1741 }
1611 } 1742 }
1612 } 1743 }
1613
1614 std::string http_url;
1615#if 0
1616 if (gSavedSettings.getBOOL("ImagePipelineUseHTTP"))
1617 {
1618 LLViewerRegion* region = gAgent.getRegion();
1619 if (region)
1620 {
1621 http_url = region->getCapability("RequestTextureDownload");
1622 }
1623 } 1744 }
1624#endif 1745
1625
1626 for (work_request_map_t::iterator iter1 = requests.begin(); 1746 for (work_request_map_t::iterator iter1 = requests.begin();
1627 iter1 != requests.end(); ++iter1) 1747 iter1 != requests.end(); ++iter1)
1628 { 1748 {
1629 bool use_http = http_url.empty() ? false : true;
1630 LLHost host = iter1->first; 1749 LLHost host = iter1->first;
1631 // invalid host = use agent host 1750 // invalid host = use agent host
1632 if (host == LLHost::invalid) 1751 if (host == LLHost::invalid)
1633 { 1752 {
1634 host = gAgent.getRegionHost(); 1753 host = gAgent.getRegionHost();
1635 } 1754 }
1636 else
1637 {
1638 use_http = false;
1639 }
1640 1755
1641 if (use_http) 1756 S32 sim_request_count = 0;
1642 { 1757
1643 } 1758 for (request_list_t::iterator iter2 = iter1->second.begin();
1644 else 1759 iter2 != iter1->second.end(); ++iter2)
1645 { 1760 {
1646 S32 request_count = 0; 1761 LLTextureFetchWorker* req = *iter2;
1647 for (request_list_t::iterator iter2 = iter1->second.begin(); 1762 if (gMessageSystem)
1648 iter2 != iter1->second.end(); ++iter2)
1649 { 1763 {
1650 LLTextureFetchWorker* req = *iter2; 1764 if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM)
1651 req->mSentRequest = LLTextureFetchWorker::SENT_SIM; 1765 {
1652 if (0 == request_count) 1766 // Initialize packet data based on data read from cache
1767 req->lockWorkMutex();
1768 req->setupPacketData();
1769 req->unlockWorkMutex();
1770 }
1771 if (0 == sim_request_count)
1653 { 1772 {
1654 gMessageSystem->newMessageFast(_PREHASH_RequestImage); 1773 gMessageSystem->newMessageFast(_PREHASH_RequestImage);
1655 gMessageSystem->nextBlockFast(_PREHASH_AgentData); 1774 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -1666,30 +1785,42 @@ void LLTextureFetch::sendRequestListToSimulators()
1666// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard 1785// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
1667// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl; 1786// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
1668 1787
1669 req->lockWorkData(); 1788 if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
1789 {
1790 mTextureInfo.setRequestStartTime(req->mID, LLTimer::getTotalTime());
1791 mTextureInfo.setRequestOffset(req->mID, 0);
1792 mTextureInfo.setRequestSize(req->mID, 0);
1793 mTextureInfo.setRequestType(req->mID, LLTextureInfoDetails::REQUEST_TYPE_UDP);
1794 }
1795
1796 req->lockWorkMutex();
1797 req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
1670 req->mSimRequestedDiscard = req->mDesiredDiscard; 1798 req->mSimRequestedDiscard = req->mDesiredDiscard;
1671 req->mRequestedPriority = req->mImagePriority; 1799 req->mRequestedPriority = req->mImagePriority;
1672 req->mRequestedTimer.reset(); 1800 req->mRequestedTimer.reset();
1673 req->unlockWorkData(); 1801 req->unlockWorkMutex();
1674 request_count++; 1802 sim_request_count++;
1675 if (request_count >= IMAGES_PER_REQUEST) 1803 if (sim_request_count >= IMAGES_PER_REQUEST)
1676 { 1804 {
1677// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; 1805// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
1806
1678 gMessageSystem->sendSemiReliable(host, NULL, NULL); 1807 gMessageSystem->sendSemiReliable(host, NULL, NULL);
1679 request_count = 0; 1808 sim_request_count = 0;
1680 } 1809 }
1681 } 1810 }
1682 if (request_count > 0 && request_count < IMAGES_PER_REQUEST) 1811 }
1683 { 1812 if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST)
1684// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; 1813 {
1685 gMessageSystem->sendSemiReliable(host, NULL, NULL); 1814// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
1686 request_count = 0; 1815 gMessageSystem->sendSemiReliable(host, NULL, NULL);
1687 } 1816 sim_request_count = 0;
1688 } 1817 }
1689 } 1818 }
1690 1819
1691 // Send cancelations 1820 // Send cancelations
1692 if (!mCancelQueue.empty()) 1821 {
1822 LLMutexLock lock2(&mNetworkQueueMutex);
1823 if (gMessageSystem && !mCancelQueue.empty())
1693 { 1824 {
1694 for (cancel_queue_t::iterator iter1 = mCancelQueue.begin(); 1825 for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
1695 iter1 != mCancelQueue.end(); ++iter1) 1826 iter1 != mCancelQueue.end(); ++iter1)
@@ -1732,6 +1863,7 @@ void LLTextureFetch::sendRequestListToSimulators()
1732 } 1863 }
1733 mCancelQueue.clear(); 1864 mCancelQueue.clear();
1734 } 1865 }
1866 }
1735} 1867}
1736 1868
1737////////////////////////////////////////////////////////////////////////////// 1869//////////////////////////////////////////////////////////////////////////////
@@ -1773,16 +1905,20 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
1773{ 1905{
1774 LLMutexLock lock(&mQueueMutex); 1906 LLMutexLock lock(&mQueueMutex);
1775 LLTextureFetchWorker* worker = getWorker(id); 1907 LLTextureFetchWorker* worker = getWorker(id);
1776 bool res = true;
1777 1908
1778 ++mPacketCount; 1909 ++mPacketCount;
1779 1910
1780 if (!worker) 1911 if (!worker)
1781 { 1912 {
1782// llwarns << "Received header for non active worker: " << id << llendl; 1913// llwarns << "Received header for non active worker: " << id << llendl;
1783 res = false; 1914 ++mBadPacketCount;
1915 mCancelQueue[host].insert(id);
1916 return false;
1784 } 1917 }
1785 else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK || 1918
1919 bool res = true;
1920 worker->lockWorkMutex();
1921 if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
1786 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM) 1922 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
1787 { 1923 {
1788// llwarns << "receiveImageHeader for worker: " << id 1924// llwarns << "receiveImageHeader for worker: " << id
@@ -1805,21 +1941,20 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
1805 { 1941 {
1806 ++mBadPacketCount; 1942 ++mBadPacketCount;
1807 mCancelQueue[host].insert(id); 1943 mCancelQueue[host].insert(id);
1808 return false;
1809 } 1944 }
1810 1945 else
1811 worker->lockWorkData(); 1946 {
1812 1947 // Copy header data into image object
1813 // Copy header data into image object 1948 worker->mImageCodec = codec;
1814 worker->mImageCodec = codec; 1949 worker->mTotalPackets = packets;
1815 worker->mTotalPackets = packets; 1950 worker->mFileSize = (S32)totalbytes;
1816 worker->mFileSize = (S32)totalbytes; 1951 llassert_always(totalbytes > 0);
1817 llassert_always(totalbytes > 0); 1952 llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
1818 llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); 1953 res = worker->insertPacket(0, data, data_size);
1819 res = worker->insertPacket(0, data, data_size); 1954 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
1820 worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); 1955 worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
1821 worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; 1956 }
1822 worker->unlockWorkData(); 1957 worker->unlockWorkMutex();
1823 return res; 1958 return res;
1824} 1959}
1825 1960
@@ -1853,7 +1988,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
1853 return false; 1988 return false;
1854 } 1989 }
1855 1990
1856 worker->lockWorkData(); 1991 worker->lockWorkMutex();
1857 1992
1858 res = worker->insertPacket(packet_num, data, data_size); 1993 res = worker->insertPacket(packet_num, data, data_size);
1859 1994
@@ -1866,12 +2001,19 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
1866 else 2001 else
1867 { 2002 {
1868// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id 2003// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
1869// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl; 2004// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
1870 removeFromNetworkQueue(worker); // failsafe
1871 mCancelQueue[host].insert(id);
1872 } 2005 }
1873 2006
1874 worker->unlockWorkData(); 2007 if(packet_num >= (worker->mTotalPackets - 1))
2008 {
2009 if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
2010 {
2011 U64 timeNow = LLTimer::getTotalTime();
2012 mTextureInfo.setRequestSize(id, worker->mFileSize);
2013 mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);
2014 }
2015 }
2016 worker->unlockWorkMutex();
1875 2017
1876 return res; 2018 return res;
1877} 2019}
@@ -1892,7 +2034,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
1892 LLTextureFetchWorker* worker = getWorker(id); 2034 LLTextureFetchWorker* worker = getWorker(id);
1893 if (worker && worker->haveWork()) 2035 if (worker && worker->haveWork())
1894 { 2036 {
1895 worker->lockWorkData(); 2037 worker->lockWorkMutex();
1896 state = worker->mState; 2038 state = worker->mState;
1897 fetch_dtime = worker->mFetchTimer.getElapsedTimeF32(); 2039 fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
1898 request_dtime = worker->mRequestedTimer.getElapsedTimeF32(); 2040 request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
@@ -1909,7 +2051,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
1909 data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize; 2051 data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
1910 } 2052 }
1911 } 2053 }
1912 if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA) 2054 if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
1913 { 2055 {
1914 requested_priority = worker->mRequestedPriority; 2056 requested_priority = worker->mRequestedPriority;
1915 } 2057 }
@@ -1918,7 +2060,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
1918 requested_priority = worker->mImagePriority; 2060 requested_priority = worker->mImagePriority;
1919 } 2061 }
1920 fetch_priority = worker->getPriority(); 2062 fetch_priority = worker->getPriority();
1921 worker->unlockWorkData(); 2063 worker->unlockWorkMutex();
1922 } 2064 }
1923 data_progress_p = data_progress; 2065 data_progress_p = data_progress;
1924 requested_priority_p = requested_priority; 2066 requested_priority_p = requested_priority;
@@ -1944,5 +2086,3 @@ void LLTextureFetch::dump()
1944 } 2086 }
1945} 2087}
1946 2088
1947
1948//////////////////////////////////////////////////////////////////////////////
diff --git a/linden/indra/newview/lltexturefetch.h b/linden/indra/newview/lltexturefetch.h
index 56650e7..c48f609 100644
--- a/linden/indra/newview/lltexturefetch.h
+++ b/linden/indra/newview/lltexturefetch.h
@@ -37,26 +37,29 @@
37#include "llimage.h" 37#include "llimage.h"
38#include "lluuid.h" 38#include "lluuid.h"
39#include "llworkerthread.h" 39#include "llworkerthread.h"
40#include "llcurl.h"
41#include "lltextureinfo.h"
40 42
41class LLViewerImage; 43class LLViewerImage;
42class LLTextureFetchWorker; 44class LLTextureFetchWorker;
45class HTTPGetResponder;
43class LLTextureCache; 46class LLTextureCache;
47class LLImageDecodeThread;
44class LLHost; 48class LLHost;
45 49
46// Interface class 50// Interface class
47class LLTextureFetch : public LLWorkerThread 51class LLTextureFetch : public LLWorkerThread
48{ 52{
49 friend class LLTextureFetchWorker; 53 friend class LLTextureFetchWorker;
54 friend class HTTPGetResponder;
50 55
51public: 56public:
52 LLTextureFetch(LLTextureCache* cache, bool threaded); 57 LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded);
53 ~LLTextureFetch(); 58 ~LLTextureFetch();
54 59
55 /*virtual*/ S32 update(U32 max_time_ms); 60 /*virtual*/ S32 update(U32 max_time_ms);
56 61
57 bool createRequest(const LLUUID& id, const LLHost& host, F32 priority, 62 bool createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
58 S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
59 bool createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
60 S32 w, S32 h, S32 c, S32 discard, bool needs_aux); 63 S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
61 void deleteRequest(const LLUUID& id, bool cancel); 64 void deleteRequest(const LLUUID& id, bool cancel);
62 bool getRequestFinished(const LLUUID& id, S32& discard_level, 65 bool getRequestFinished(const LLUUID& id, S32& discard_level,
@@ -66,24 +69,38 @@ public:
66 bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data); 69 bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data);
67 bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data); 70 bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data);
68 71
72 void setTextureBandwidth(F32 bandwidth) { mTextureBandwidth = bandwidth; }
73 F32 getTextureBandwidth() { return mTextureBandwidth; }
74
69 // Debug 75 // Debug
70 S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p, 76 S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p,
71 U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p); 77 U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p);
72 void dump(); 78 void dump();
73 S32 getNumRequests() { return mRequestMap.size(); } 79 S32 getNumRequests() { return mRequestMap.size(); }
80 S32 getNumHTTPRequests() { return mHTTPTextureQueue.size(); }
74 81
75 // Public for access by callbacks 82 // Public for access by callbacks
76 void lockQueue() { mQueueMutex.lock(); } 83 void lockQueue() { mQueueMutex.lock(); }
77 void unlockQueue() { mQueueMutex.unlock(); } 84 void unlockQueue() { mQueueMutex.unlock(); }
78 LLTextureFetchWorker* getWorker(const LLUUID& id); 85 LLTextureFetchWorker* getWorker(const LLUUID& id);
86
87 LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
79 88
80protected: 89protected:
81 void addToNetworkQueue(LLTextureFetchWorker* worker); 90 void addToNetworkQueue(LLTextureFetchWorker* worker);
82 void removeFromNetworkQueue(LLTextureFetchWorker* worker); 91 void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
92 void addToHTTPQueue(const LLUUID& id);
93 void removeFromHTTPQueue(const LLUUID& id);
94 S32 getHTTPQueueSize() { return (S32)mHTTPTextureQueue.size(); }
83 void removeRequest(LLTextureFetchWorker* worker, bool cancel); 95 void removeRequest(LLTextureFetchWorker* worker, bool cancel);
96 // Called from worker thread (during doWork)
97 void processCurlRequests();
84 98
85private: 99private:
86 void sendRequestListToSimulators(); 100 void sendRequestListToSimulators();
101 /*virtual*/ void startThread(void);
102 /*virtual*/ void endThread(void);
103 /*virtual*/ void threadedUpdate(void);
87 104
88public: 105public:
89 LLUUID mDebugID; 106 LLUUID mDebugID;
@@ -94,8 +111,11 @@ public:
94 111
95private: 112private:
96 LLMutex mQueueMutex; 113 LLMutex mQueueMutex;
114 LLMutex mNetworkQueueMutex;
97 115
98 LLTextureCache* mTextureCache; 116 LLTextureCache* mTextureCache;
117 LLImageDecodeThread* mImageDecodeThread;
118 LLCurlRequest* mCurlGetRequest;
99 119
100 // Map of all requests by UUID 120 // Map of all requests by UUID
101 typedef std::map<LLUUID,LLTextureFetchWorker*> map_t; 121 typedef std::map<LLUUID,LLTextureFetchWorker*> map_t;
@@ -104,10 +124,13 @@ private:
104 // Set of requests that require network data 124 // Set of requests that require network data
105 typedef std::set<LLUUID> queue_t; 125 typedef std::set<LLUUID> queue_t;
106 queue_t mNetworkQueue; 126 queue_t mNetworkQueue;
127 queue_t mHTTPTextureQueue;
107 typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t; 128 typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t;
108 cancel_queue_t mCancelQueue; 129 cancel_queue_t mCancelQueue;
109 130 F32 mTextureBandwidth;
110 LLFrameTimer mNetworkTimer; 131 F32 mMaxBandwidth;
132 LLTextureInfo mTextureInfo;
111}; 133};
112 134
113#endif // LL_LLTEXTUREFETCH_H 135#endif // LL_LLTEXTUREFETCH_H
136
diff --git a/linden/indra/newview/lltextureinfo.cpp b/linden/indra/newview/lltextureinfo.cpp
new file mode 100644
index 0000000..672a36a
--- /dev/null
+++ b/linden/indra/newview/lltextureinfo.cpp
@@ -0,0 +1,290 @@
1/**
2 * @file lltextureinfo.cpp
3 * @brief Object which handles local texture info
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "lltextureinfo.h"
36#include "lltexturestats.h"
37#include "llviewercontrol.h"
38
39LLTextureInfo::LLTextureInfo() :
40 mLogTextureDownloadsToViewerLog(false),
41 mLogTextureDownloadsToSimulator(false),
42 mTotalBytes(0),
43 mTotalMilliseconds(0),
44 mTextureDownloadsStarted(0),
45 mTextureDownloadsCompleted(0),
46 mTextureDownloadProtocol("NONE"),
47 mTextureLogThreshold(100 * 1024),
48 mCurrentStatsBundleStartTime(0)
49{
50 mTextures.clear();
51}
52
53void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold)
54{
55 mLogTextureDownloadsToViewerLog = writeToViewerLog;
56 mLogTextureDownloadsToSimulator = sendToSim;
57 mTextureLogThreshold = textureLogThreshold;
58}
59
60LLTextureInfo::~LLTextureInfo()
61{
62 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator;
63 for (iterator = mTextures.begin(); iterator != mTextures.end(); iterator++)
64 {
65 LLTextureInfoDetails *info = (*iterator).second;
66 delete info;
67 }
68
69 mTextures.clear();
70}
71
72void LLTextureInfo::addRequest(const LLUUID& id)
73{
74 LLTextureInfoDetails *info = new LLTextureInfoDetails();
75 mTextures[id] = info;
76}
77
78U32 LLTextureInfo::getTextureInfoMapSize()
79{
80 return mTextures.size();
81}
82
83bool LLTextureInfo::has(const LLUUID& id)
84{
85 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
86 if (iterator == mTextures.end())
87 {
88 return false;
89 }
90 else
91 {
92 return true;
93 }
94}
95
96void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime)
97{
98 if (!has(id))
99 {
100 addRequest(id);
101 }
102 mTextures[id]->mStartTime = startTime;
103 mTextureDownloadsStarted++;
104}
105
106void LLTextureInfo::setRequestSize(const LLUUID& id, U32 size)
107{
108 if (!has(id))
109 {
110 addRequest(id);
111 }
112 mTextures[id]->mSize = size;
113}
114
115void LLTextureInfo::setRequestOffset(const LLUUID& id, U32 offset)
116{
117 if (!has(id))
118 {
119 addRequest(id);
120 }
121 mTextures[id]->mOffset = offset;
122}
123
124void LLTextureInfo::setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type)
125{
126 if (!has(id))
127 {
128 addRequest(id);
129 }
130 mTextures[id]->mType = type;
131}
132
133void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime)
134{
135 if (!has(id))
136 {
137 addRequest(id);
138 }
139 mTextures[id]->mCompleteTime = completeTime;
140
141 std::string protocol = "NONE";
142 switch(mTextures[id]->mType)
143 {
144 case LLTextureInfoDetails::REQUEST_TYPE_HTTP:
145 protocol = "HTTP";
146 break;
147
148 case LLTextureInfoDetails::REQUEST_TYPE_UDP:
149 protocol = "UDP";
150 break;
151
152 case LLTextureInfoDetails::REQUEST_TYPE_NONE:
153 default:
154 break;
155 }
156
157 if (mLogTextureDownloadsToViewerLog)
158 {
159 llinfos << "texture=" << id
160 << " start=" << mTextures[id]->mStartTime
161 << " end=" << mTextures[id]->mCompleteTime
162 << " size=" << mTextures[id]->mSize
163 << " offset=" << mTextures[id]->mOffset
164 << " length_in_ms=" << (mTextures[id]->mCompleteTime - mTextures[id]->mStartTime) / 1000
165 << " protocol=" << protocol
166 << llendl;
167 }
168
169 if(mLogTextureDownloadsToSimulator)
170 {
171 S32 texture_stats_upload_threshold = mTextureLogThreshold;
172 mTotalBytes += mTextures[id]->mSize;
173 mTotalMilliseconds += mTextures[id]->mCompleteTime - mTextures[id]->mStartTime;
174 mTextureDownloadsCompleted++;
175 mTextureDownloadProtocol = protocol;
176 if (mTotalBytes >= texture_stats_upload_threshold)
177 {
178 LLSD texture_data;
179 std::stringstream startTime;
180 startTime << mCurrentStatsBundleStartTime;
181 texture_data["start_time"] = startTime.str();
182 std::stringstream endTime;
183 endTime << completeTime;
184 texture_data["end_time"] = endTime.str();
185 texture_data["averages"] = getAverages();
186 send_texture_stats_to_sim(texture_data);
187 resetTextureStatistics();
188 }
189 }
190
191 mTextures.erase(id);
192}
193
194LLSD LLTextureInfo::getAverages()
195{
196 LLSD averagedTextureData;
197 S32 averageDownloadRate;
198 if(mTotalMilliseconds == 0)
199 {
200 averageDownloadRate = 0;
201 }
202 else
203 {
204 averageDownloadRate = (mTotalBytes * 8) / mTotalMilliseconds;
205 }
206
207 averagedTextureData["bits_per_second"] = averageDownloadRate;
208 averagedTextureData["bytes_downloaded"] = mTotalBytes;
209 averagedTextureData["texture_downloads_started"] = mTextureDownloadsStarted;
210 averagedTextureData["texture_downloads_completed"] = mTextureDownloadsCompleted;
211 averagedTextureData["transport"] = mTextureDownloadProtocol;
212
213 return averagedTextureData;
214}
215
216void LLTextureInfo::resetTextureStatistics()
217{
218 mTotalMilliseconds = 0;
219 mTotalBytes = 0;
220 mTextureDownloadsStarted = 0;
221 mTextureDownloadsCompleted = 0;
222 mTextureDownloadProtocol = "NONE";
223 mCurrentStatsBundleStartTime = LLTimer::getTotalTime();
224}
225
226U32 LLTextureInfo::getRequestStartTime(const LLUUID& id)
227{
228 if (!has(id))
229 {
230 return 0;
231 }
232 else
233 {
234 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
235 return (*iterator).second->mStartTime;
236 }
237}
238
239U32 LLTextureInfo::getRequestSize(const LLUUID& id)
240{
241 if (!has(id))
242 {
243 return 0;
244 }
245 else
246 {
247 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
248 return (*iterator).second->mSize;
249 }
250}
251
252U32 LLTextureInfo::getRequestOffset(const LLUUID& id)
253{
254 if (!has(id))
255 {
256 return 0;
257 }
258 else
259 {
260 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
261 return (*iterator).second->mOffset;
262 }
263}
264
265LLTextureInfoDetails::LLRequestType LLTextureInfo::getRequestType(const LLUUID& id)
266{
267 if (!has(id))
268 {
269 return LLTextureInfoDetails::REQUEST_TYPE_NONE;
270 }
271 else
272 {
273 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
274 return (*iterator).second->mType;
275 }
276}
277
278U32 LLTextureInfo::getRequestCompleteTime(const LLUUID& id)
279{
280 if (!has(id))
281 {
282 return 0;
283 }
284 else
285 {
286 std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
287 return (*iterator).second->mCompleteTime;
288 }
289}
290
diff --git a/linden/indra/newview/lltextureinfo.h b/linden/indra/newview/lltextureinfo.h
new file mode 100644
index 0000000..71b0ea4
--- /dev/null
+++ b/linden/indra/newview/lltextureinfo.h
@@ -0,0 +1,80 @@
1/**
2 * @file lltextureinfo.h
3 * @brief Object for managing texture information.
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_LLTEXTUREINFO_H
34#define LL_LLTEXTUREINFO_H
35
36#include "lluuid.h"
37#include "lltextureinfodetails.h"
38#include <map>
39
40class LLTextureInfo
41{
42public:
43 LLTextureInfo();
44 ~LLTextureInfo();
45
46 void setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold);
47 bool has(const LLUUID& id);
48 void setRequestStartTime(const LLUUID& id, U64 startTime);
49 void setRequestSize(const LLUUID& id, U32 size);
50 void setRequestOffset(const LLUUID& id, U32 offset);
51 void setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type);
52 void setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime);
53 U32 getRequestStartTime(const LLUUID& id);
54 U32 getRequestSize(const LLUUID& id);
55 U32 getRequestOffset(const LLUUID& id);
56 LLTextureInfoDetails::LLRequestType getRequestType(const LLUUID& id);
57 U32 getRequestCompleteTime(const LLUUID& id);
58 void resetTextureStatistics();
59 U32 getTextureInfoMapSize();
60 LLSD getAverages();
61
62private:
63 void addRequest(const LLUUID& id);
64
65 std::map<LLUUID, LLTextureInfoDetails *> mTextures;
66
67 LLSD mAverages;
68
69 bool mLogTextureDownloadsToViewerLog;
70 bool mLogTextureDownloadsToSimulator;
71 S32 mTotalBytes;
72 S32 mTotalMilliseconds;
73 S32 mTextureDownloadsStarted;
74 S32 mTextureDownloadsCompleted;
75 std::string mTextureDownloadProtocol;
76 U32 mTextureLogThreshold; // in bytes
77 U64 mCurrentStatsBundleStartTime;
78};
79
80#endif // LL_LLTEXTUREINFO_H
diff --git a/linden/indra/newview/lltextureinfodetails.cpp b/linden/indra/newview/lltextureinfodetails.cpp
new file mode 100644
index 0000000..f6ef47a
--- /dev/null
+++ b/linden/indra/newview/lltextureinfodetails.cpp
@@ -0,0 +1,40 @@
1/**
2 * @file lltextureinfodetails.cpp
3 * @brief Object which handles details of any individual texture
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "lltextureinfodetails.h"
36
37LLTextureInfoDetails::LLTextureInfoDetails() : mStartTime(0), mCompleteTime(0), mSize(0), mType(REQUEST_TYPE_NONE), mOffset(0)
38{
39}
40
diff --git a/linden/indra/newview/lltextureinfodetails.h b/linden/indra/newview/lltextureinfodetails.h
new file mode 100644
index 0000000..091fa01
--- /dev/null
+++ b/linden/indra/newview/lltextureinfodetails.h
@@ -0,0 +1,58 @@
1/**
2 * @file lltextureinfo.h
3 * @brief Object for managing texture information.
4 *
5 * $LicenseInfo:firstyear=2000&license=viewergpl$
6 *
7 * Copyright (c) 2000-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_LLTEXTUREINFODETAILS_H
34#define LL_LLTEXTUREINFODETAILS_H
35
36#include "lluuid.h"
37
38class LLTextureInfoDetails
39{
40public:
41 enum LLRequestType
42 {
43 REQUEST_TYPE_NONE,
44 REQUEST_TYPE_HTTP,
45 REQUEST_TYPE_UDP
46 };
47
48 U32 mStartTime;
49 U32 mCompleteTime;
50 U32 mOffset;
51 U32 mSize;
52 LLRequestType mType;
53
54 LLTextureInfoDetails();
55};
56
57#endif // LL_LLTEXTUREINFODETAILS_H
58
diff --git a/linden/indra/newview/lltexturestats.cpp b/linden/indra/newview/lltexturestats.cpp
new file mode 100644
index 0000000..c91bfd4
--- /dev/null
+++ b/linden/indra/newview/lltexturestats.cpp
@@ -0,0 +1,61 @@
1/**
2 * @file lltexturerstats.cpp
3 * @brief texture stats helper methods
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "pipeline.h"
36#include "llagent.h"
37#include "lltexturefetch.h"
38#include "lltexturestats.h"
39#include "lltexturestatsuploader.h"
40#include "llviewerregion.h"
41
42void send_texture_stats_to_sim(const LLSD &texture_stats)
43{
44 LLSD texture_stats_report;
45 // Only send stats if the agent is connected to a region.
46 if (!gAgent.getRegion() || gNoRender)
47 {
48 return;
49 }
50
51 LLUUID agent_id = gAgent.getID();
52 texture_stats_report["agent_id"] = agent_id;
53 texture_stats_report["region_id"] = gAgent.getRegion()->getRegionID();
54 texture_stats_report["stats_data"] = texture_stats;
55
56 std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats");
57 LLTextureStatsUploader tsu;
58 llinfos << "uploading texture stats data to simulator" << llendl;
59 tsu.uploadStatsToSimulator(texture_cap_url, texture_stats);
60}
61
diff --git a/linden/indra/newview/lltexturestats.h b/linden/indra/newview/lltexturestats.h
new file mode 100644
index 0000000..2deb377
--- /dev/null
+++ b/linden/indra/newview/lltexturestats.h
@@ -0,0 +1,41 @@
1/**
2 * @file lltexturestats.h
3 * @brief texture stats utilities
4 *
5 * $LicenseInfo:firstyear=2009&license=viewergpl$
6 *
7 * Copyright (c) 2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_LLTEXTURESTATS_H
34#define LL_LLTEXTURESTATS_H
35
36#include "llappviewer.h"
37
38// utility functions to capture data on texture download speeds and send to simulator periodically
39void send_texture_stats_to_sim(const LLSD &texture_stats);
40
41#endif // LL_LLTEXTURESTATS_H
diff --git a/linden/indra/newview/lltexturestatsuploader.cpp b/linden/indra/newview/lltexturestatsuploader.cpp
new file mode 100644
index 0000000..e0358e1
--- /dev/null
+++ b/linden/indra/newview/lltexturestatsuploader.cpp
@@ -0,0 +1,59 @@
1/**
2 * @file lltexturerstats.cpp
3 * @brief texture stats upload class
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "lltexturestatsuploader.h"
36
37LLTextureStatsUploader::LLTextureStatsUploader()
38{
39}
40
41LLTextureStatsUploader::~LLTextureStatsUploader()
42{
43}
44
45void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats)
46{
47 if ( texture_cap_url != "" )
48 {
49 LLHTTPClient::post(texture_cap_url, texture_stats, NULL);
50 }
51 else
52 {
53 llinfos << "Not sending texture stats: "
54 << texture_stats
55 << " as there is no cap url."
56 << llendl;
57 }
58}
59
diff --git a/linden/indra/newview/lltexturestatsuploader.h b/linden/indra/newview/lltexturestatsuploader.h
new file mode 100644
index 0000000..f6cc8be
--- /dev/null
+++ b/linden/indra/newview/lltexturestatsuploader.h
@@ -0,0 +1,48 @@
1/**
2 * @file lltexturestatsuploader.h
3 * @brief Class to send the texture stats to the simulatore
4 *
5 * $LicenseInfo:firstyear=2009&license=viewergpl$
6 *
7 * Copyright (c) 2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_LLTEXTURESTATSUPLOADER_H
34#define LL_LLTEXTURESTATSUPLOADER_H
35
36#include "llappviewer.h"
37
38// utility functions to capture data on texture download speeds and send to simulator periodically
39
40class LLTextureStatsUploader
41{
42public:
43 LLTextureStatsUploader();
44 ~LLTextureStatsUploader();
45 void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats);
46};
47
48#endif // LL_LLTEXTURESTATSUPLOADER_H
diff --git a/linden/indra/newview/lltextureview.cpp b/linden/indra/newview/lltextureview.cpp
index d356bf9..b6159da 100644
--- a/linden/indra/newview/lltextureview.cpp
+++ b/linden/indra/newview/lltextureview.cpp
@@ -43,16 +43,17 @@
43#include "llimageworker.h" 43#include "llimageworker.h"
44#include "llrender.h" 44#include "llrender.h"
45 45
46#include "llappviewer.h"
46#include "llhoverview.h" 47#include "llhoverview.h"
47#include "llselectmgr.h" 48#include "llselectmgr.h"
48#include "lltexlayer.h" 49#include "lltexlayer.h"
49#include "lltexturecache.h" 50#include "lltexturecache.h"
50#include "lltexturefetch.h" 51#include "lltexturefetch.h"
52#include "llviewercontrol.h"
51#include "llviewerobject.h" 53#include "llviewerobject.h"
52#include "llviewerimage.h" 54#include "llviewerimage.h"
53#include "llviewerimagelist.h" 55#include "llviewerimagelist.h"
54#include "llappviewer.h" 56#include "llvovolume.h"
55
56extern F32 texmem_lower_bound_scale; 57extern F32 texmem_lower_bound_scale;
57 58
58LLTextureView *gTextureView = NULL; 59LLTextureView *gTextureView = NULL;
@@ -466,9 +467,9 @@ void LLGLTexMemBar::draw()
466 LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount, 467 LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount,
467 LLAppViewer::getTextureCache()->getNumReads(), LLAppViewer::getTextureCache()->getNumWrites(), 468 LLAppViewer::getTextureCache()->getNumReads(), LLAppViewer::getTextureCache()->getNumWrites(),
468 LLLFSThread::sLocal->getPending(), 469 LLLFSThread::sLocal->getPending(),
469 LLImageWorker::sCount, LLImageWorker::getWorkerThread()->getNumDeletes(), 470 LLAppViewer::getImageDecodeThread()->getPending(),
470 LLImageRaw::sRawImageCount, LLViewerImage::sRawCount, LLViewerImage::sAuxCount, 471 LLImageRaw::sRawImageCount,
471 gImageList.mCallbackList.size()); 472 LLAppViewer::getTextureFetch()->getNumHTTPRequests());
472 473
473 LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, line_height*2, 474 LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, line_height*2,
474 text_color, LLFontGL::LEFT, LLFontGL::TOP); 475 text_color, LLFontGL::LEFT, LLFontGL::TOP);
diff --git a/linden/indra/newview/llviewercamera.cpp b/linden/indra/newview/llviewercamera.cpp
index 72d1494..dade65f 100644
--- a/linden/indra/newview/llviewercamera.cpp
+++ b/linden/indra/newview/llviewercamera.cpp
@@ -102,10 +102,13 @@ LLViewerCamera::LLViewerCamera() : LLCamera()
102{ 102{
103 calcProjection(getFar()); 103 calcProjection(getFar());
104 mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW; 104 mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
105 mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
105 mPixelMeterRatio = 0.f; 106 mPixelMeterRatio = 0.f;
106 mScreenPixelArea = 0; 107 mScreenPixelArea = 0;
107 mZoomFactor = 1.f; 108 mZoomFactor = 1.f;
108 mZoomSubregion = 1; 109 mZoomSubregion = 1;
110 mAverageSpeed = 0.f;
111 mAverageAngularSpeed = 0.f;
109} 112}
110 113
111void LLViewerCamera::updateCameraLocation(const LLVector3 &center, 114void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
@@ -144,15 +147,22 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
144 147
145 setOriginAndLookAt(origin, up_direction, point_of_interest); 148 setOriginAndLookAt(origin, up_direction, point_of_interest);
146 149
147 F32 dpos = (center - last_position).magVec(); 150 mVelocityDir = center - last_position ;
151 F32 dpos = mVelocityDir.normVec() ;
148 LLQuaternion rotation; 152 LLQuaternion rotation;
149 rotation.shortestArc(last_axis, getAtAxis()); 153 rotation.shortestArc(last_axis, getAtAxis());
150 154
151 F32 x, y, z; 155 F32 x, y, z;
152 F32 drot; 156 F32 drot;
153 rotation.getAngleAxis(&drot, &x, &y, &z); 157 rotation.getAngleAxis(&drot, &x, &y, &z);
158
154 mVelocityStat.addValue(dpos); 159 mVelocityStat.addValue(dpos);
155 mAngularVelocityStat.addValue(drot); 160 mAngularVelocityStat.addValue(drot);
161
162 mAverageSpeed = mVelocityStat.getMeanPerSec() ;
163 mAverageAngularSpeed = mAngularVelocityStat.getMeanPerSec() ;
164 mCosHalfCameraFOV = cosf(0.5f * getView() * llmax(1.0f, getAspect()));
165
156 // update pixel meter ratio using default fov, not modified one 166 // update pixel meter ratio using default fov, not modified one
157 mPixelMeterRatio = getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5)); 167 mPixelMeterRatio = getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5));
158 // update screen pixel area 168 // update screen pixel area
@@ -759,8 +769,8 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
759 769
760 BOOL in_frustum = pointInFrustum(LLVector3(vec)) > 0; 770 BOOL in_frustum = pointInFrustum(LLVector3(vec)) > 0;
761 771
762 if ( !in_frustum && all_verts || 772 if (( !in_frustum && all_verts) ||
763 in_frustum && !all_verts) 773 (in_frustum && !all_verts))
764 { 774 {
765 return !all_verts; 775 return !all_verts;
766 } 776 }
@@ -797,9 +807,11 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
797 LLCamera::setView(vertical_fov_rads); // call base implementation 807 LLCamera::setView(vertical_fov_rads); // call base implementation
798} 808}
799 809
800void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) { 810void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads)
811{
801 vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView()); 812 vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
802 setView(vertical_fov_rads); 813 setView(vertical_fov_rads);
803 mCameraFOVDefault = vertical_fov_rads; 814 mCameraFOVDefault = vertical_fov_rads;
815 mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
804} 816}
805 817
diff --git a/linden/indra/newview/llviewercamera.h b/linden/indra/newview/llviewercamera.h
index 6a0c42b..d25d063 100644
--- a/linden/indra/newview/llviewercamera.h
+++ b/linden/indra/newview/llviewercamera.h
@@ -71,17 +71,20 @@ public:
71 BOOL projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp = TRUE) const; 71 BOOL projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp = TRUE) const;
72 BOOL projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const; 72 BOOL projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const;
73 73
74 74 const LLVector3* getVelocityDir() const {return &mVelocityDir;}
75 LLStat *getVelocityStat() { return &mVelocityStat; } 75 LLStat *getVelocityStat() { return &mVelocityStat; }
76 LLStat *getAngularVelocityStat() { return &mAngularVelocityStat; } 76 LLStat *getAngularVelocityStat() { return &mAngularVelocityStat; }
77 F32 getCosHalfFov() {return mCosHalfCameraFOV;}
78 F32 getAverageSpeed() {return mAverageSpeed ;}
79 F32 getAverageAngularSpeed() {return mAverageAngularSpeed;}
77 80
78 void getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right); 81 void getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right);
79 LLVector3 roundToPixel(const LLVector3 &pos_agent); 82 LLVector3 roundToPixel(const LLVector3 &pos_agent);
80 83
81 // Sets the current matrix 84 // Sets the current matrix
82 /* virtual */ void setView(F32 vertical_fov_rads); 85 /* virtual */ void setView(F32 vertical_fov_rads);
83 // Sets the current matrix AND remembers result as default view 86
84 void setDefaultFOV(F32 vertical_fov_rads); 87 void setDefaultFOV(F32 fov) ;
85 F32 getDefaultFOV() { return mCameraFOVDefault; } 88 F32 getDefaultFOV() { return mCameraFOVDefault; }
86 89
87 BOOL cameraUnderWater() const; 90 BOOL cameraUnderWater() const;
@@ -100,9 +103,14 @@ protected:
100 103
101 LLStat mVelocityStat; 104 LLStat mVelocityStat;
102 LLStat mAngularVelocityStat; 105 LLStat mAngularVelocityStat;
106 LLVector3 mVelocityDir ;
107 F32 mAverageSpeed ;
108 F32 mAverageAngularSpeed ;
109
103 mutable LLMatrix4 mProjectionMatrix; // Cache of perspective matrix 110 mutable LLMatrix4 mProjectionMatrix; // Cache of perspective matrix
104 mutable LLMatrix4 mModelviewMatrix; 111 mutable LLMatrix4 mModelviewMatrix;
105 F32 mCameraFOVDefault; 112 F32 mCameraFOVDefault;
113 F32 mCosHalfCameraFOV;
106 LLVector3 mLastPointOfInterest; 114 LLVector3 mLastPointOfInterest;
107 F32 mPixelMeterRatio; // Divide by distance from camera to get pixels per meter at that distance. 115 F32 mPixelMeterRatio; // Divide by distance from camera to get pixels per meter at that distance.
108 S32 mScreenPixelArea; // Pixel area of entire window 116 S32 mScreenPixelArea; // Pixel area of entire window
diff --git a/linden/indra/newview/llviewercontrol.cpp b/linden/indra/newview/llviewercontrol.cpp
index 08e9d45..6d62db5 100644
--- a/linden/indra/newview/llviewercontrol.cpp
+++ b/linden/indra/newview/llviewercontrol.cpp
@@ -91,6 +91,8 @@ std::string gCurrentVersion;
91extern BOOL gResizeScreenTexture; 91extern BOOL gResizeScreenTexture;
92extern BOOL gDebugGL; 92extern BOOL gDebugGL;
93 93
94extern BOOL gAuditTexture;
95
94//////////////////////////////////////////////////////////////////////////// 96////////////////////////////////////////////////////////////////////////////
95// Listeners 97// Listeners
96 98
@@ -374,6 +376,12 @@ static bool handleRenderUseImpostorsChanged(const LLSD& newvalue)
374 return true; 376 return true;
375} 377}
376 378
379static bool handleAuditTextureChanged(const LLSD& newvalue)
380{
381 gAuditTexture = newvalue.asBoolean();
382 return true;
383}
384
377static bool handleRenderDebugGLChanged(const LLSD& newvalue) 385static bool handleRenderDebugGLChanged(const LLSD& newvalue)
378{ 386{
379 gDebugGL = newvalue.asBoolean(); 387 gDebugGL = newvalue.asBoolean();
@@ -527,6 +535,7 @@ void settings_setup_listeners()
527 gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); 535 gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1));
528 gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); 536 gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1));
529 gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _1)); 537 gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _1));
538 gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _1));
530 gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); 539 gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1));
531 gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); 540 gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1));
532 gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); 541 gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1));
diff --git a/linden/indra/newview/llviewerimage.cpp b/linden/indra/newview/llviewerimage.cpp
index 272fcb5..3a14bf0 100644
--- a/linden/indra/newview/llviewerimage.cpp
+++ b/linden/indra/newview/llviewerimage.cpp
@@ -59,6 +59,8 @@
59#include "llviewercontrol.h" 59#include "llviewercontrol.h"
60#include "pipeline.h" 60#include "pipeline.h"
61#include "llappviewer.h" 61#include "llappviewer.h"
62#include "llface.h"
63#include "llviewercamera.h"
62/////////////////////////////////////////////////////////////////////////////// 64///////////////////////////////////////////////////////////////////////////////
63 65
64// statics 66// statics
@@ -72,6 +74,7 @@ S32 LLViewerImage::sImageCount = 0;
72S32 LLViewerImage::sRawCount = 0; 74S32 LLViewerImage::sRawCount = 0;
73S32 LLViewerImage::sAuxCount = 0; 75S32 LLViewerImage::sAuxCount = 0;
74LLTimer LLViewerImage::sEvaluationTimer; 76LLTimer LLViewerImage::sEvaluationTimer;
77S8 LLViewerImage::sCameraMovingDiscardBias = 0 ;
75F32 LLViewerImage::sDesiredDiscardBias = 0.f; 78F32 LLViewerImage::sDesiredDiscardBias = 0.f;
76static F32 sDesiredDiscardBiasMin = -2.0f; // -max number of levels to improve image quality by 79static F32 sDesiredDiscardBiasMin = -2.0f; // -max number of levels to improve image quality by
77static F32 sDesiredDiscardBiasMax = 1.5f; // max number of levels to reduce image quality by 80static F32 sDesiredDiscardBiasMax = 1.5f; // max number of levels to reduce image quality by
@@ -83,16 +86,26 @@ S32 LLViewerImage::sMaxTotalTextureMemInMegaBytes = 0;
83S32 LLViewerImage::sMaxDesiredTextureMemInBytes = 0 ; 86S32 LLViewerImage::sMaxDesiredTextureMemInBytes = 0 ;
84BOOL LLViewerImage::sDontLoadVolumeTextures = FALSE; 87BOOL LLViewerImage::sDontLoadVolumeTextures = FALSE;
85 88
89S32 LLViewerImage::sMaxSculptRez = 128 ; //max sculpt image size
90const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64 ;
91const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerImage::sMaxSculptRez * LLViewerImage::sMaxSculptRez ;
92const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128 ;
93S32 LLViewerImage::sMinLargeImageSize = 65536 ; //256 * 256.
94S32 LLViewerImage::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ;
95BOOL LLViewerImage::sFreezeImageScalingDown = FALSE ;
96//debug use
97S32 LLViewerImage::sLLViewerImageCount = 0 ;
98
86// static 99// static
87void LLViewerImage::initClass() 100void LLViewerImage::initClass()
88{ 101{
89 sNullImagep = new LLImageGL(1,1,3,TRUE); 102 sNullImagep = new LLImageGL(1,1,3,TRUE);
90 LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,3); 103 LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,3);
91 raw->clear(0x77, 0x77, 0x77, 0xFF); 104 raw->clear(0x77, 0x77, 0x77, 0xFF);
92 sNullImagep->createGLTexture(0, raw); 105 sNullImagep->createGLTexture(0, raw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
93 106
94#if 1 107#if 1
95 LLPointer<LLViewerImage> imagep = new LLViewerImage(IMG_DEFAULT, TRUE); 108 LLPointer<LLViewerImage> imagep = new LLViewerImage(IMG_DEFAULT);
96 sDefaultImagep = imagep; 109 sDefaultImagep = imagep;
97 const S32 dim = 128; 110 const S32 dim = 128;
98 LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3); 111 LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
@@ -118,7 +131,7 @@ void LLViewerImage::initClass()
118 } 131 }
119 } 132 }
120 } 133 }
121 imagep->createGLTexture(0, image_raw); 134 imagep->createGLTexture(0, image_raw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
122 image_raw = NULL; 135 image_raw = NULL;
123 gImageList.addImage(imagep); 136 gImageList.addImage(imagep);
124 imagep->dontDiscard(); 137 imagep->dontDiscard();
@@ -128,17 +141,48 @@ void LLViewerImage::initClass()
128 sSmokeImagep = gImageList.getImage(IMG_SMOKE, TRUE, TRUE); 141 sSmokeImagep = gImageList.getImage(IMG_SMOKE, TRUE, TRUE);
129 sSmokeImagep->setNoDelete() ; 142 sSmokeImagep->setNoDelete() ;
130 143
144 if(gAuditTexture)
145 {
146 sDefaultTexturep = new LLImageGL() ;
147 image_raw = new LLImageRaw(dim,dim,3);
148 data = image_raw->getData();
149 for (S32 i = 0; i<dim; i++)
150 {
151 for (S32 j = 0; j<dim; j++)
152 {
153 const S32 border = 2;
154 if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
155 {
156 *data++ = 0xff;
157 *data++ = 0xff;
158 *data++ = 0xff;
159 }
160 else
161 {
162 *data++ = 0xff;
163 *data++ = 0xff;
164 *data++ = 0x00;
165 }
166 }
167 }
168 sDefaultTexturep->createGLTexture(0, image_raw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
169 image_raw = NULL;
170 sDefaultTexturep->dontDiscard();
171 }
131} 172}
132 173
133// static 174// static
134void LLViewerImage::cleanupClass() 175void LLViewerImage::cleanupClass()
135{ 176{
136 stop_glerror(); 177 stop_glerror();
178 LLImageGL::cleanupClass() ;
179
137 sNullImagep = NULL; 180 sNullImagep = NULL;
138 sDefaultImagep = NULL; 181 sDefaultImagep = NULL;
139 sSmokeImagep = NULL; 182 sSmokeImagep = NULL;
140 sMissingAssetImagep = NULL; 183 sMissingAssetImagep = NULL;
141 sWhiteImagep = NULL; 184 sWhiteImagep = NULL;
185 sDefaultTexturep = NULL ;
142} 186}
143 187
144// tuning params 188// tuning params
@@ -186,6 +230,13 @@ void LLViewerImage::updateClass(const F32 velocity, const F32 angular_velocity)
186 } 230 }
187 } 231 }
188 sDesiredDiscardBias = llclamp(sDesiredDiscardBias, sDesiredDiscardBiasMin, sDesiredDiscardBiasMax); 232 sDesiredDiscardBias = llclamp(sDesiredDiscardBias, sDesiredDiscardBiasMin, sDesiredDiscardBiasMax);
233
234 F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
235 F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
236 sCameraMovingDiscardBias = (S8)llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1) ;
237
238 LLViewerImage::sFreezeImageScalingDown = (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < 0.75f * sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) &&
239 (BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < 0.75f * sMaxTotalTextureMemInMegaBytes * texmem_middle_bound_scale) ;
189} 240}
190 241
191// static 242// static
@@ -198,18 +249,19 @@ LLViewerImage* LLViewerImage::getImage(const LLUUID& image_id)
198 249
199const U32 LLViewerImage::sCurrentFileVersion = 1; 250const U32 LLViewerImage::sCurrentFileVersion = 1;
200 251
201LLViewerImage::LLViewerImage(const LLUUID& id, BOOL usemipmaps) 252LLViewerImage::LLViewerImage(const LLUUID& id, const LLHost& host, BOOL usemipmaps)
202 : LLImageGL(usemipmaps), 253 : LLImageGL(usemipmaps),
203 mID(id) 254 mID(id),
255 mTargetHost(host)
204{ 256{
205 init(true); 257 init(true);
206 sImageCount++; 258 sImageCount++;
207} 259}
208 260
209LLViewerImage::LLViewerImage(const std::string& filename, const LLUUID& id, BOOL usemipmaps) 261LLViewerImage::LLViewerImage(const std::string& url, const LLUUID& id, BOOL usemipmaps)
210 : LLImageGL(usemipmaps), 262 : LLImageGL(usemipmaps),
211 mID(id), 263 mID(id),
212 mLocalFileName(filename) 264 mUrl(url)
213{ 265{
214 init(true); 266 init(true);
215 sImageCount++; 267 sImageCount++;
@@ -265,7 +317,7 @@ void LLViewerImage::init(bool firstinit)
265 } 317 }
266 mIsMediaTexture = FALSE; 318 mIsMediaTexture = FALSE;
267 319
268 mBoostLevel = LLViewerImage::BOOST_NONE; 320 mBoostLevel = LLViewerImageBoostLevel::BOOST_NONE;
269 321
270 // Only set mIsMissingAsset true when we know for certain that the database 322 // Only set mIsMissingAsset true when we know for certain that the database
271 // does not contain this image. 323 // does not contain this image.
@@ -277,8 +329,6 @@ void LLViewerImage::init(bool firstinit)
277 mRawDiscardLevel = INVALID_DISCARD_LEVEL; 329 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
278 mMinDiscardLevel = 0; 330 mMinDiscardLevel = 0;
279 331
280 mTargetHost = LLHost::invalid;
281
282 mHasFetcher = FALSE; 332 mHasFetcher = FALSE;
283 mIsFetching = FALSE; 333 mIsFetching = FALSE;
284 mFetchState = 0; 334 mFetchState = 0;
@@ -287,6 +337,15 @@ void LLViewerImage::init(bool firstinit)
287 mFetchDeltaTime = 999999.f; 337 mFetchDeltaTime = 999999.f;
288 mDecodeFrame = 0; 338 mDecodeFrame = 0;
289 mVisibleFrame = 0; 339 mVisibleFrame = 0;
340 mForSculpt = FALSE ;
341 mCachedRawImage = NULL ;
342 mCachedRawDiscardLevel = -1 ;
343 mCachedRawImageReady = FALSE ;
344 mNeedsResetMaxVirtualSize = FALSE ;
345
346 mForceToSaveRawImage = FALSE ;
347 mSavedRawDiscardLevel = -1 ;
348 mDesiredSavedRawDiscardLevel = -1 ;
290} 349}
291 350
292// virtual 351// virtual
@@ -322,6 +381,7 @@ LLViewerImage::~LLViewerImage()
322 381
323void LLViewerImage::cleanup() 382void LLViewerImage::cleanup()
324{ 383{
384 mFaceList.clear() ;
325 for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); 385 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
326 iter != mLoadedCallbackList.end(); ) 386 iter != mLoadedCallbackList.end(); )
327 { 387 {
@@ -336,7 +396,9 @@ void LLViewerImage::cleanup()
336 396
337 // Clean up image data 397 // Clean up image data
338 destroyRawImage(); 398 destroyRawImage();
339 399 mCachedRawImage = NULL ;
400 mCachedRawDiscardLevel = -1 ;
401 mCachedRawImageReady = FALSE ;
340 // LLImageGL::cleanup will get called more than once when this is used in the destructor. 402 // LLImageGL::cleanup will get called more than once when this is used in the destructor.
341 LLImageGL::cleanup(); 403 LLImageGL::cleanup();
342} 404}
@@ -365,6 +427,63 @@ void LLViewerImage::destroyTexture()
365 destroyGLTexture() ; 427 destroyGLTexture() ;
366} 428}
367 429
430void LLViewerImage::addToCreateTexture()
431{
432 if(isForSculptOnly())
433 {
434 //just update some variables, not to create a real GL texture.
435 createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE) ;
436 mNeedsCreateTexture = FALSE ;
437 destroyRawImage();
438 }
439 else
440 {
441#if 1
442 //
443 //if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
444 //so do not scale down the over qualified image.
445 //Note: scaling down image is expensensive. Do it only when very necessary.
446 //
447 if(mRequestedDiscardLevel <= mDesiredDiscardLevel)
448 {
449 S32 w = mFullWidth >> mRawDiscardLevel;
450 S32 h = mFullHeight >> mRawDiscardLevel;
451
452 //if big image, do not load extra data
453 //scale it down to size >= LLViewerImage::sMinLargeImageSize
454 if(w * h > LLViewerImage::sMinLargeImageSize)
455 {
456 S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel ;
457
458 if(d_level > 0)
459 {
460 S32 i = 0 ;
461 while((d_level > 0) && ((w >> i) * (h >> i) > LLViewerImage::sMinLargeImageSize))
462 {
463 i++;
464 d_level--;
465 }
466 if(i > 0)
467 {
468 mRawDiscardLevel += i ;
469 if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)
470 {
471 mNeedsCreateTexture = FALSE ;
472 destroyRawImage();
473 return ;
474 }
475 mRawImage->scale(w >> i, h >> i) ;
476 }
477 }
478 }
479 }
480#endif
481 mNeedsCreateTexture = TRUE;
482 gImageList.mCreateTextureList.insert(this);
483 }
484 return ;
485}
486
368// ONLY called from LLViewerImageList 487// ONLY called from LLViewerImageList
369BOOL LLViewerImage::createTexture(S32 usename/*= 0*/) 488BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
370{ 489{
@@ -386,7 +505,7 @@ BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
386 if (!gNoRender) 505 if (!gNoRender)
387 { 506 {
388 // store original size only for locally-sourced images 507 // store original size only for locally-sourced images
389 if (!mLocalFileName.empty()) 508 if (mUrl.compare(0, 7, "file://") == 0)
390 { 509 {
391 mOrigWidth = mRawImage->getWidth(); 510 mOrigWidth = mRawImage->getWidth();
392 mOrigHeight = mRawImage->getHeight(); 511 mOrigHeight = mRawImage->getHeight();
@@ -457,29 +576,54 @@ BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
457 576
458//============================================================================ 577//============================================================================
459 578
460void LLViewerImage::addTextureStats(F32 virtual_size) const // = 1.0 579void LLViewerImage::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const
461{ 580{
462 if (virtual_size > mMaxVirtualSize) 581 if(needs_gltexture)
463 { 582 {
464 mMaxVirtualSize = virtual_size; 583 mNeedsGLTexture = TRUE ;
465 } 584 }
466}
467 585
468void LLViewerImage::resetTextureStats(BOOL zero) 586 if(mNeedsResetMaxVirtualSize)
469{
470 if (zero)
471 { 587 {
472 mMaxVirtualSize = 0.0f; 588 //flag to reset the values because the old values are used.
589 mNeedsResetMaxVirtualSize = FALSE ;
590 mMaxVirtualSize = virtual_size;
591 mAdditionalDecodePriority = 0.f ;
592 mNeedsGLTexture = needs_gltexture ;
473 } 593 }
474 else 594 else if (virtual_size > mMaxVirtualSize)
475 { 595 {
476 mMaxVirtualSize -= mMaxVirtualSize * .10f; // decay by 5%/update 596 mMaxVirtualSize = virtual_size;
477 } 597 }
598}
599
600void LLViewerImage::resetTextureStats()
601{
602 mMaxVirtualSize = 0.0f;
603 mAdditionalDecodePriority = 0.f ;
604 mNeedsResetMaxVirtualSize = FALSE ;
605}
606
607BOOL LLViewerImage::isUpdateFrozen()
608{
609 return LLViewerImage::sFreezeImageScalingDown && !getDiscardLevel() ;
610}
611
612BOOL LLViewerImage::isLargeImage()
613{
614 return mTexelsPerImage > LLViewerImage::sMinLargeImageSize ;
478} 615}
479 616
480// This is gauranteed to get called periodically for every texture 617// This is gauranteed to get called periodically for every texture
481void LLViewerImage::processTextureStats() 618void LLViewerImage::processTextureStats()
482{ 619{
620 //no need to update if the texture reaches its highest res and the memory is sufficient.
621 //if(isUpdateFrozen())
622 //{
623 // return ;
624 //}
625
626 updateVirtualSize() ;
483 // Generate the request priority and render priority 627 // Generate the request priority and render priority
484 if (mDontDiscard || !getUseMipMaps()) 628 if (mDontDiscard || !getUseMipMaps())
485 { 629 {
@@ -487,7 +631,7 @@ void LLViewerImage::processTextureStats()
487 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) 631 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
488 mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 632 mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
489 } 633 }
490 else if (mBoostLevel < LLViewerImage::BOOST_HIGH && mMaxVirtualSize <= 10.f) 634 else if (mBoostLevel < LLViewerImageBoostLevel::BOOST_HIGH && mMaxVirtualSize <= 10.f)
491 { 635 {
492 // If the image has not been significantly visible in a while, we don't want it 636 // If the image has not been significantly visible in a while, we don't want it
493 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1)); 637 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1));
@@ -504,15 +648,14 @@ void LLViewerImage::processTextureStats()
504 S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT); 648 S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT);
505 S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT); 649 S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT);
506 mTexelsPerImage = (F32)fullwidth * fullheight; 650 mTexelsPerImage = (F32)fullwidth * fullheight;
507
508 F32 discard_level = 0.f; 651 F32 discard_level = 0.f;
509 652
510 // If we know the output width and height, we can force the discard 653 // If we know the output width and height, we can force the discard
511 // level to the correct value, and thus not decode more texture 654 // level to the correct value, and thus not decode more texture
512 // data than we need to. 655 // data than we need to.
513 if (mBoostLevel == LLViewerImage::BOOST_UI || 656 if (mBoostLevel == LLViewerImageBoostLevel::BOOST_UI ||
514 mBoostLevel == LLViewerImage::BOOST_PREVIEW || 657 mBoostLevel == LLViewerImageBoostLevel::BOOST_PREVIEW ||
515 mBoostLevel == LLViewerImage::BOOST_AVATAR_SELF) // JAMESDEBUG what about AVATAR_BAKED_SELF? 658 mBoostLevel == LLViewerImageBoostLevel::BOOST_AVATAR_SELF) // JAMESDEBUG what about AVATAR_BAKED_SELF?
516 { 659 {
517 discard_level = 0; // full res 660 discard_level = 0; // full res
518 } 661 }
@@ -527,6 +670,12 @@ void LLViewerImage::processTextureStats()
527 } 670 }
528 else 671 else
529 { 672 {
673 if(isLargeImage() && !isJustBound() && mAdditionalDecodePriority < 1.0f)
674 {
675 //if is a big image and not being used recently, nor close to the view point, do not load hi-res data.
676 mMaxVirtualSize = llmin(mMaxVirtualSize, (F32)LLViewerImage::sMinLargeImageSize) ;
677 }
678
530 if ((mCalculatedDiscardLevel >= 0.f) && 679 if ((mCalculatedDiscardLevel >= 0.f) &&
531 (llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f)) 680 (llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f))
532 { 681 {
@@ -541,15 +690,14 @@ void LLViewerImage::processTextureStats()
541 mCalculatedDiscardLevel = discard_level; 690 mCalculatedDiscardLevel = discard_level;
542 } 691 }
543 } 692 }
544 if (mBoostLevel < LLViewerImage::BOOST_HIGH) 693 if (mBoostLevel < LLViewerImageBoostLevel::BOOST_HIGH)
545 { 694 {
546 static const F32 discard_bias = -.5f; // Must be < 1 or highest discard will never load!
547 discard_level += discard_bias;
548 discard_level += sDesiredDiscardBias; 695 discard_level += sDesiredDiscardBias;
549 discard_level *= sDesiredDiscardScale; // scale 696 discard_level *= sDesiredDiscardScale; // scale
697
698 discard_level += sCameraMovingDiscardBias ;
550 } 699 }
551 discard_level = floorf(discard_level); 700 discard_level = floorf(discard_level);
552// discard_level -= (gImageList.mVideoMemorySetting>>1); // more video ram = higher detail
553 701
554 F32 min_discard = 0.f; 702 F32 min_discard = 0.f;
555 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) 703 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
@@ -567,43 +715,76 @@ void LLViewerImage::processTextureStats()
567 // if possible. Now we check to see if we have it, and take the 715 // if possible. Now we check to see if we have it, and take the
568 // proper action if we don't. 716 // proper action if we don't.
569 // 717 //
570
571 BOOL increase_discard = FALSE;
572 S32 current_discard = getDiscardLevel(); 718 S32 current_discard = getDiscardLevel();
573 if ((sDesiredDiscardBias > 0.0f) && 719 if ((sDesiredDiscardBias > 0.0f) &&
574 (current_discard >= 0 && mDesiredDiscardLevel >= current_discard)) 720 (current_discard >= 0 && mDesiredDiscardLevel >= current_discard))
575 { 721 {
576 if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) 722 // Limit the amount of GL memory bound each frame
723 if ( (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) &&
724 (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
577 { 725 {
578 // Limit the amount of GL memory bound each frame 726 scaleDown() ;
579 if (mDesiredDiscardLevel > current_discard)
580 {
581 increase_discard = TRUE;
582 }
583 } 727 }
584 if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale) 728 // Only allow GL to have 2x the video card memory
729 else if ( (BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale) &&
730 (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
585 { 731 {
586 // Only allow GL to have 2x the video card memory 732 scaleDown() ;
587 if (!getBoundRecently())
588 {
589 increase_discard = TRUE;
590 }
591 } 733 }
592 if (increase_discard) 734 }
735 }
736}
737void LLViewerImage::updateVirtualSize()
738{
739#if 1
740 if(mNeedsResetMaxVirtualSize)
741 {
742 addTextureStats(0.f, FALSE) ;//reset
743 }
744 if(mFaceList.size() > 0)
745 {
746 for(std::list<LLFace*>::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter)
747 {
748 LLFace* facep = *iter ;
749 if(facep->getDrawable()->isRecentlyVisible())
593 { 750 {
594 // llinfos << "DISCARDED: " << mID << " Discard: " << current_discard << llendl; 751 addTextureStats(facep->getVirtualSize()) ;
595 sBoundTextureMemoryInBytes -= mTextureMemory; 752 setAdditionalDecodePriority(facep->getImportanceToCamera()) ;
596 sTotalTextureMemoryInBytes -= mTextureMemory;
597 // Increase the discard level (reduce the texture res)
598 S32 new_discard = current_discard+1;
599 setDiscardLevel(new_discard);
600 sBoundTextureMemoryInBytes += mTextureMemory;
601 sTotalTextureMemoryInBytes += mTextureMemory;
602 } 753 }
603 } 754 }
604 } 755 }
756 mNeedsResetMaxVirtualSize = TRUE ;
757#endif
605} 758}
759void LLViewerImage::scaleDown()
760{
761 if(getHasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())
762 {
763 switchToCachedImage() ;
764 }
765}
766
767//use the mCachedRawImage to (re)generate the gl texture.
768void LLViewerImage::switchToCachedImage()
769{
770 if(mCachedRawImage.notNull())
771 {
772 mRawImage = mCachedRawImage ;
773
774 if (getComponents() != mRawImage->getComponents())
775 {
776 // We've changed the number of components, so we need to move any
777 // objects using this pool to a different pool.
778 mComponents = mRawImage->getComponents();
779 gImageList.dirtyImage(this);
780 }
606 781
782 mIsRawImageValid = TRUE;
783 mRawDiscardLevel = mCachedRawDiscardLevel ;
784 gImageList.mCreateTextureList.insert(this);
785 mNeedsCreateTexture = TRUE;
786 }
787}
607//============================================================================ 788//============================================================================
608 789
609F32 LLViewerImage::calcDecodePriority() 790F32 LLViewerImage::calcDecodePriority()
@@ -619,9 +800,19 @@ F32 LLViewerImage::calcDecodePriority()
619 { 800 {
620 return mDecodePriority; // no change while waiting to create 801 return mDecodePriority; // no change while waiting to create
621 } 802 }
803 if(mForceToSaveRawImage)
804 {
805 return maxDecodePriority() ;
806 }
622 807
623 F32 priority;
624 S32 cur_discard = getDiscardLevel(); 808 S32 cur_discard = getDiscardLevel();
809
810 //no need to update if the texture reaches its highest res and the memory is sufficient.
811 //if(LLViewerImage::sFreezeImageScalingDown && !cur_discard)
812 //{
813 // return -5.0f ;
814 //}
815
625 bool have_all_data = (cur_discard >= 0 && (cur_discard <= mDesiredDiscardLevel)); 816 bool have_all_data = (cur_discard >= 0 && (cur_discard <= mDesiredDiscardLevel));
626 F32 pixel_priority = fsqrtf(mMaxVirtualSize); 817 F32 pixel_priority = fsqrtf(mMaxVirtualSize);
627 const S32 MIN_NOT_VISIBLE_FRAMES = 30; // NOTE: this function is not called every frame 818 const S32 MIN_NOT_VISIBLE_FRAMES = 30; // NOTE: this function is not called every frame
@@ -631,23 +822,36 @@ F32 LLViewerImage::calcDecodePriority()
631 mVisibleFrame = mDecodeFrame; 822 mVisibleFrame = mDecodeFrame;
632 } 823 }
633 824
825 F32 priority = 0.f;
634 if (mIsMissingAsset) 826 if (mIsMissingAsset)
635 { 827 {
636 priority = 0.0f; 828 priority = 0.0f;
829 }
830 else if(mDesiredDiscardLevel >= cur_discard && cur_discard > -1)
831 {
832 priority = -1.0f ;
833 }
834 else if (!isJustBound() && mCachedRawImageReady)
835 {
836 priority = -1.0f;
837 }
838 else if(mCachedRawDiscardLevel > -1 && mDesiredDiscardLevel >= mCachedRawDiscardLevel)
839 {
840 priority = -1.0f;
637 } 841 }
638 else if (mDesiredDiscardLevel > mMaxDiscardLevel) 842 else if (mDesiredDiscardLevel > mMaxDiscardLevel)
639 { 843 {
640 // Don't decode anything we don't need 844 // Don't decode anything we don't need
641 priority = -1.0f; 845 priority = -1.0f;
642 } 846 }
643 else if (mBoostLevel == LLViewerImage::BOOST_UI && !have_all_data) 847 else if (mBoostLevel == LLViewerImageBoostLevel::BOOST_UI && !have_all_data)
644 { 848 {
645 priority = 1.f; 849 priority = 1.f;
646 } 850 }
647 else if (pixel_priority <= 0.f && !have_all_data) 851 else if (pixel_priority <= 0.f && !have_all_data)
648 { 852 {
649 // Not on screen but we might want some data 853 // Not on screen but we might want some data
650 if (mBoostLevel > BOOST_HIGH) 854 if (mBoostLevel > LLViewerImageBoostLevel::BOOST_HIGH)
651 { 855 {
652 // Always want high boosted images 856 // Always want high boosted images
653 priority = 1.f; 857 priority = 1.f;
@@ -695,12 +899,16 @@ F32 LLViewerImage::calcDecodePriority()
695 ddiscard-=2; 899 ddiscard-=2;
696 } 900 }
697 ddiscard = llclamp(ddiscard, 0, 4); 901 ddiscard = llclamp(ddiscard, 0, 4);
902
698 priority = ddiscard*100000.f; 903 priority = ddiscard*100000.f;
699 } 904 }
700 if (priority > 0.0f) 905 if (priority > 0.0f)
701 { 906 {
702 pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f); // priority range = 100000-900000 907 // priority range = 100000-900000
703 if ( mBoostLevel > BOOST_HIGH) 908 pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f);
909
910 // priority range = [100000.f, 2000000.f]
911 if ( mBoostLevel > LLViewerImageBoostLevel::BOOST_HIGH)
704 { 912 {
705 priority = 1000000.f + pixel_priority + 1000.f * mBoostLevel; 913 priority = 1000000.f + pixel_priority + 1000.f * mBoostLevel;
706 } 914 }
@@ -708,7 +916,14 @@ F32 LLViewerImage::calcDecodePriority()
708 { 916 {
709 priority += 0.f + pixel_priority + 1000.f * mBoostLevel; 917 priority += 0.f + pixel_priority + 1000.f * mBoostLevel;
710 } 918 }
919
920 // priority range = [2100000.f, 5000000.f] if mAdditionalDecodePriority > 1.0
921 if(mAdditionalDecodePriority > 1.0f)
922 {
923 priority += 2000000.f + mAdditionalDecodePriority ;
924 }
711 } 925 }
926
712 return priority; 927 return priority;
713} 928}
714 929
@@ -716,7 +931,7 @@ F32 LLViewerImage::calcDecodePriority()
716//static 931//static
717F32 LLViewerImage::maxDecodePriority() 932F32 LLViewerImage::maxDecodePriority()
718{ 933{
719 return 2000000.f; 934 return 6000000.f;
720} 935}
721 936
722void LLViewerImage::setDecodePriority(F32 priority) 937void LLViewerImage::setDecodePriority(F32 priority)
@@ -725,15 +940,30 @@ void LLViewerImage::setDecodePriority(F32 priority)
725 mDecodePriority = priority; 940 mDecodePriority = priority;
726} 941}
727 942
728void LLViewerImage::setBoostLevel(S32 level) 943F32 LLViewerImage::maxAdditionalDecodePriority()
944{
945 return 2000000.f;
946}
947void LLViewerImage::setAdditionalDecodePriority(F32 priority)
729{ 948{
949 priority *= maxAdditionalDecodePriority();
950 if(mAdditionalDecodePriority < priority)
951 {
952 mAdditionalDecodePriority = priority;
953 }
954}
955//------------------------------------------------------------
956
957void LLViewerImage::setBoostLevel(S32 level)
958{
730 mBoostLevel = level; 959 mBoostLevel = level;
731 if (level >= LLViewerImage::BOOST_HIGH) 960
961 if(gAuditTexture)
732 { 962 {
733 processTextureStats(); 963 setCategory(mBoostLevel);
734 } 964 }
735 965
736 if(mBoostLevel != LLViewerImage::BOOST_NONE) 966 if(mBoostLevel != LLViewerImageBoostLevel::BOOST_NONE)
737 { 967 {
738 setNoDelete() ; 968 setNoDelete() ;
739 } 969 }
@@ -785,11 +1015,20 @@ bool LLViewerImage::updateFetch()
785 S32 desired_discard = getDesiredDiscardLevel(); 1015 S32 desired_discard = getDesiredDiscardLevel();
786 F32 decode_priority = getDecodePriority(); 1016 F32 decode_priority = getDecodePriority();
787 decode_priority = llmax(decode_priority, 0.0f); 1017 decode_priority = llmax(decode_priority, 0.0f);
1018 decode_priority = llmin(decode_priority, maxDecodePriority());
788 1019
789 if (mIsFetching) 1020 if (mIsFetching)
790 { 1021 {
791 // Sets mRawDiscardLevel, mRawImage, mAuxRawImage 1022 // Sets mRawDiscardLevel, mRawImage, mAuxRawImage
792 S32 fetch_discard = current_discard; 1023 S32 fetch_discard = current_discard;
1024 if(mForceToSaveRawImage)
1025 {
1026 if(fetch_discard >= 0)
1027 {
1028 fetch_discard = llmax(fetch_discard, mSavedRawDiscardLevel) ;
1029 }
1030 }
1031
793 if (mRawImage.notNull()) sRawCount--; 1032 if (mRawImage.notNull()) sRawCount--;
794 if (mAuxRawImage.notNull()) sAuxCount--; 1033 if (mAuxRawImage.notNull()) sAuxCount--;
795 bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); 1034 bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
@@ -809,6 +1048,7 @@ bool LLViewerImage::updateFetch()
809 if (mRawImage.notNull()) 1048 if (mRawImage.notNull())
810 { 1049 {
811 mRawDiscardLevel = fetch_discard; 1050 mRawDiscardLevel = fetch_discard;
1051
812 if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) && 1052 if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) &&
813 (current_discard < 0 || mRawDiscardLevel < current_discard)) 1053 (current_discard < 0 || mRawDiscardLevel < current_discard))
814 { 1054 {
@@ -819,11 +1059,25 @@ bool LLViewerImage::updateFetch()
819 mComponents = mRawImage->getComponents(); 1059 mComponents = mRawImage->getComponents();
820 gImageList.dirtyImage(this); 1060 gImageList.dirtyImage(this);
821 } 1061 }
822 mIsRawImageValid = TRUE; 1062
823 gImageList.mCreateTextureList.insert(this);
824 mNeedsCreateTexture = TRUE;
825 mFullWidth = mRawImage->getWidth() << mRawDiscardLevel; 1063 mFullWidth = mRawImage->getWidth() << mRawDiscardLevel;
826 mFullHeight = mRawImage->getHeight() << mRawDiscardLevel; 1064 mFullHeight = mRawImage->getHeight() << mRawDiscardLevel;
1065
1066 if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE)
1067 {
1068 //discard all oversized textures.
1069 destroyRawImage();
1070 setIsMissingAsset();
1071 mRawDiscardLevel = INVALID_DISCARD_LEVEL ;
1072 mIsFetching = FALSE ;
1073 }
1074 else
1075 {
1076 mIsRawImageValid = TRUE;
1077 addToCreateTexture() ;
1078 }
1079
1080 return TRUE ;
827 } 1081 }
828 else 1082 else
829 { 1083 {
@@ -846,7 +1100,7 @@ bool LLViewerImage::updateFetch()
846 } 1100 }
847 else 1101 else
848 { 1102 {
849 llwarns << mID << ": Setting min discard to " << current_discard << llendl; 1103 //llwarns << mID << ": Setting min discard to " << current_discard << llendl;
850 mMinDiscardLevel = current_discard; 1104 mMinDiscardLevel = current_discard;
851 desired_discard = current_discard; 1105 desired_discard = current_discard;
852 } 1106 }
@@ -865,8 +1119,19 @@ bool LLViewerImage::updateFetch()
865 } 1119 }
866 } 1120 }
867 1121
868 bool make_request = true; 1122 if (!mDontDiscard)
869 1123 {
1124 if (mBoostLevel == 0)
1125 {
1126 desired_discard = llmax(desired_discard, current_discard-1);
1127 }
1128 else
1129 {
1130 desired_discard = llmax(desired_discard, current_discard-2);
1131 }
1132 }
1133
1134 bool make_request = true;
870 if (decode_priority <= 0) 1135 if (decode_priority <= 0)
871 { 1136 {
872 make_request = false; 1137 make_request = false;
@@ -879,6 +1144,10 @@ bool LLViewerImage::updateFetch()
879 { 1144 {
880 make_request = false; 1145 make_request = false;
881 } 1146 }
1147 else if (!isJustBound() && mCachedRawImageReady)
1148 {
1149 make_request = false;
1150 }
882 else 1151 else
883 { 1152 {
884 if (mIsFetching) 1153 if (mIsFetching)
@@ -906,41 +1175,21 @@ bool LLViewerImage::updateFetch()
906 h = getHeight(0); 1175 h = getHeight(0);
907 c = getComponents(); 1176 c = getComponents();
908 } 1177 }
909 if (!mDontDiscard) 1178
910 {
911 if (mBoostLevel == 0)
912 {
913 desired_discard = llmax(desired_discard, current_discard-1);
914 }
915 else
916 {
917 desired_discard = llmax(desired_discard, current_discard-2);
918 }
919 }
920
921 // bypass texturefetch directly by pulling from LLTextureCache 1179 // bypass texturefetch directly by pulling from LLTextureCache
922 bool fetch_request_created = false; 1180 bool fetch_request_created = false;
923 if (mLocalFileName.empty()) 1181 fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), decode_priority,
924 { 1182 w, h, c, desired_discard, needsAux());
925 fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(getID(), getTargetHost(), decode_priority,
926 w, h, c, desired_discard,
927 needsAux());
928 }
929 else
930 {
931 fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mLocalFileName, getID(),getTargetHost(), decode_priority,
932 w, h, c, desired_discard,
933 needsAux());
934 }
935 1183
936 if (fetch_request_created) 1184 if (fetch_request_created)
937 { 1185 {
938 mHasFetcher = TRUE; 1186 mHasFetcher = TRUE;
939 mIsFetching = TRUE; 1187 mIsFetching = TRUE;
940 mRequestedDiscardLevel = desired_discard; 1188 mRequestedDiscardLevel = desired_discard;
1189
941 mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, 1190 mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
942 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime); 1191 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
943 } 1192 }
944 1193
945 // if createRequest() failed, we're finishing up a request for this UUID, 1194 // if createRequest() failed, we're finishing up a request for this UUID,
946 // wait for it to complete 1195 // wait for it to complete
@@ -962,9 +1211,81 @@ bool LLViewerImage::updateFetch()
962 return mIsFetching ? true : false; 1211 return mIsFetching ? true : false;
963} 1212}
964 1213
1214//
1215//force to fetch a new raw image for this texture
1216//this function is to replace readBackRaw().
1217//
1218BOOL LLViewerImage::forceFetch()
1219{
1220 if(!mForceToSaveRawImage)
1221 {
1222 return false ;
1223 }
1224 if (mIsMediaTexture)
1225 {
1226 mForceToSaveRawImage = false ;
1227 llassert_always(!mHasFetcher);
1228 return false; // skip
1229 }
1230 if (mIsMissingAsset)
1231 {
1232 mForceToSaveRawImage = false ;
1233 llassert_always(!mHasFetcher);
1234 return false; // skip
1235 }
1236 if (!mLoadedCallbackList.empty() && mRawImage.notNull())
1237 {
1238 return false; // process any raw image data in callbacks before replacing
1239 }
1240 if(mRawImage.notNull() && mRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
1241 {
1242 return false ; // mRawImage is enough
1243 }
1244 if(mIsFetching)
1245 {
1246 return false ;
1247 }
1248
1249 S32 desired_discard = mDesiredSavedRawDiscardLevel ;
1250 S32 current_discard = getDiscardLevel();
1251
1252 bool fetch_request_created = false;
1253 S32 w=0, h=0, c=0;
1254 if (current_discard >= 0)
1255 {
1256 w = getWidth(0);
1257 h = getHeight(0);
1258 c = getComponents();
1259 }
1260 fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), maxDecodePriority(),
1261 w, h, c, desired_discard, needsAux());
1262
1263 if (fetch_request_created)
1264 {
1265 mHasFetcher = TRUE;
1266 mIsFetching = TRUE;
1267 // Set the image's decode priority to maxDecodePriority() too, or updateFetch() will set
1268 // the request priority to 0 and terminate the fetch before we even started (SNOW-203).
1269 gImageList.bumpToMaxDecodePriority(this);
1270 mRequestedDiscardLevel = desired_discard ;
1271
1272 mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
1273 mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
1274 }
1275
1276 return mIsFetching ? true : false;
1277}
1278
965void LLViewerImage::setIsMissingAsset() 1279void LLViewerImage::setIsMissingAsset()
966{ 1280{
967 llwarns << mLocalFileName << " " << mID << ": Marking image as missing" << llendl; 1281 if (mUrl.empty())
1282 {
1283 llwarns << mID << ": Marking image as missing" << llendl;
1284 }
1285 else
1286 {
1287 llwarns << mUrl << ": Marking image as missing" << llendl;
1288 }
968 if (mHasFetcher) 1289 if (mHasFetcher)
969 { 1290 {
970 LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); 1291 LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
@@ -1252,7 +1573,7 @@ bool LLViewerImage::bindError(S32 stage) const
1252 return res; 1573 return res;
1253} 1574}
1254 1575
1255bool LLViewerImage::bindDefaultImage(S32 stage) const 1576bool LLViewerImage::bindDefaultImage(S32 stage)
1256{ 1577{
1257 if (stage < 0) return false; 1578 if (stage < 0) return false;
1258 1579
@@ -1271,24 +1592,17 @@ bool LLViewerImage::bindDefaultImage(S32 stage) const
1271 llwarns << "LLViewerImage::bindError failed." << llendl; 1592 llwarns << "LLViewerImage::bindError failed." << llendl;
1272 } 1593 }
1273 stop_glerror(); 1594 stop_glerror();
1595
1596 //check if there is cached raw image and switch to it if possible
1597 switchToCachedImage() ;
1598
1274 return res; 1599 return res;
1275} 1600}
1276 1601
1277//virtual 1602//virtual
1278void LLViewerImage::forceImmediateUpdate() 1603void LLViewerImage::forceImmediateUpdate()
1279{ 1604{
1280 //only immediately update a deleted texture which is now being re-used. 1605 gImageList.bumpToMaxDecodePriority(this) ;
1281 if(!isDeleted())
1282 {
1283 return ;
1284 }
1285 //if already called forceImmediateUpdate()
1286 if(mInImageList && mDecodePriority == LLViewerImage::maxDecodePriority())
1287 {
1288 return ;
1289 }
1290
1291 gImageList.forceImmediateUpdate(this) ;
1292 return ; 1606 return ;
1293} 1607}
1294 1608
@@ -1302,21 +1616,165 @@ LLImageRaw* LLViewerImage::readBackRawImage(S8 discard_level)
1302 llerrs << "called with existing mRawImage" << llendl; 1616 llerrs << "called with existing mRawImage" << llendl;
1303 mRawImage = NULL; 1617 mRawImage = NULL;
1304 } 1618 }
1305 mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), mComponents);
1306 sRawCount++;
1307 mRawDiscardLevel = discard_level;
1308 readBackRaw(mRawDiscardLevel, mRawImage, false);
1309 mIsRawImageValid = TRUE;
1310 1619
1620 if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level)
1621 {
1622 mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ;
1623 mRawImage->copy(mSavedRawImage) ;
1624 mRawDiscardLevel = discard_level ;
1625 }
1626 else
1627 {
1628 mRawImage = mCachedRawImage ;
1629 mRawDiscardLevel = mCachedRawDiscardLevel;
1630 }
1631
1632 sRawCount++;
1633 mIsRawImageValid = TRUE;
1634
1311 return mRawImage; 1635 return mRawImage;
1312} 1636}
1313 1637
1638void LLViewerImage::saveRawImage()
1639{
1640 if(mRawImage.isNull() || mRawDiscardLevel > mDesiredSavedRawDiscardLevel)
1641 {
1642 forceFetch() ;
1643 }
1644
1645 if(mRawImage.isNull() || mSavedRawDiscardLevel == mRawDiscardLevel)
1646 {
1647 return ;
1648 }
1649
1650 mSavedRawDiscardLevel = mRawDiscardLevel ;
1651 mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()) ;
1652
1653 if(mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
1654 {
1655 mForceToSaveRawImage = FALSE ;
1656 }
1657}
1658
1659void LLViewerImage::forceToSaveRawImage(S32 desired_discard)
1660{
1661 mForceToSaveRawImage = TRUE ;
1662 mDesiredSavedRawDiscardLevel = desired_discard ;
1663
1664 forceFetch() ;
1665}
1666void LLViewerImage::destroySavedRawImage()
1667{
1668 mSavedRawImage = NULL ;
1669 mForceToSaveRawImage = FALSE ;
1670 mSavedRawDiscardLevel = -1 ;
1671 mDesiredSavedRawDiscardLevel = -1 ;
1672}
1673
1314void LLViewerImage::destroyRawImage() 1674void LLViewerImage::destroyRawImage()
1315{ 1675{
1316 if (mRawImage.notNull()) sRawCount--; 1676 if (mRawImage.notNull()) sRawCount--;
1317 if (mAuxRawImage.notNull()) sAuxCount--; 1677 if (mAuxRawImage.notNull()) sAuxCount--;
1678
1679 if(mForceToSaveRawImage)
1680 {
1681 saveRawImage() ;
1682 }
1683
1684 setCachedRawImage() ;
1685
1318 mRawImage = NULL; 1686 mRawImage = NULL;
1319 mAuxRawImage = NULL; 1687 mAuxRawImage = NULL;
1320 mIsRawImageValid = FALSE; 1688 mIsRawImageValid = FALSE;
1321 mRawDiscardLevel = INVALID_DISCARD_LEVEL; 1689 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
1322} 1690}
1691
1692void LLViewerImage::setCachedRawImage()
1693{
1694 if(mRawImage == mCachedRawImage)
1695 {
1696 return ;
1697 }
1698 if(!mIsRawImageValid)
1699 {
1700 return ;
1701 }
1702
1703 if(mCachedRawImageReady)
1704 {
1705 return ;
1706 }
1707
1708 if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel)
1709 {
1710 S32 i = 0 ;
1711 S32 w = mRawImage->getWidth() ;
1712 S32 h = mRawImage->getHeight() ;
1713
1714 S32 max_size = MAX_CACHED_RAW_IMAGE_AREA ;
1715 if(LLViewerImageBoostLevel::BOOST_TERRAIN == mBoostLevel)
1716 {
1717 max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA ;
1718 }
1719 if(mForSculpt)
1720 {
1721 max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA ;
1722 }
1723
1724 while(((w >> i) * (h >> i)) > max_size)
1725 {
1726 ++i ;
1727 }
1728 mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)) ;
1729
1730 if(i)
1731 {
1732 if(!(w >> i) || !(h >> i))
1733 {
1734 --i ;
1735 }
1736 mRawImage->scale(w >> i, h >> i) ;
1737 }
1738 mCachedRawImage = mRawImage ;
1739 mCachedRawDiscardLevel = mRawDiscardLevel + i ;
1740 }
1741}
1742
1743void LLViewerImage::checkCachedRawSculptImage()
1744{
1745 if(mCachedRawImageReady && mCachedRawDiscardLevel > 0)
1746 {
1747 if(mCachedRawImage->getWidth() * mCachedRawImage->getHeight() < MAX_CACHED_RAW_SCULPT_IMAGE_AREA)
1748 {
1749 mCachedRawImageReady = FALSE ;
1750 }
1751 else if(isForSculptOnly())
1752 {
1753 resetTextureStats() ; //do not update this image any more.
1754 }
1755 }
1756}
1757
1758BOOL LLViewerImage::isForSculptOnly() const
1759{
1760 return mForSculpt && !mNeedsGLTexture ;
1761}
1762
1763void LLViewerImage::setForSculpt()
1764{
1765 mForSculpt = TRUE ;
1766 if(isForSculptOnly() && !getBoundRecently())
1767 {
1768 destroyGLTexture() ; //sculpt image does not need gl texture.
1769 }
1770 checkCachedRawSculptImage() ;
1771}
1772
1773void LLViewerImage::addFace(LLFace* facep)
1774{
1775 mFaceList.push_back(facep) ;
1776}
1777void LLViewerImage::removeFace(LLFace* facep)
1778{
1779 mFaceList.remove(facep) ;
1780}
diff --git a/linden/indra/newview/llviewerimage.h b/linden/indra/newview/llviewerimage.h
index 980ff56..fdf8ff0 100644
--- a/linden/indra/newview/llviewerimage.h
+++ b/linden/indra/newview/llviewerimage.h
@@ -41,6 +41,7 @@
41#include <map> 41#include <map>
42#include <list> 42#include <list>
43 43
44class LLFace;
44#define MIN_VIDEO_RAM_IN_MEGA_BYTES 32 45#define MIN_VIDEO_RAM_IN_MEGA_BYTES 32
45#define MAX_VIDEO_RAM_IN_MEGA_BYTES 512 // 512MB max for performance reasons. 46#define MAX_VIDEO_RAM_IN_MEGA_BYTES 512 // 512MB max for performance reasons.
46 47
@@ -75,6 +76,43 @@ public:
75 76
76class LLTextureBar; 77class LLTextureBar;
77 78
79//=====================================
80struct LLViewerImageBoostLevel
81{
82 enum
83 {
84 BOOST_NONE = 0,
85 BOOST_AVATAR_BAKED = 1,
86 BOOST_AVATAR = 2,
87 BOOST_CLOUDS = 3,
88 BOOST_SCULPTED = 4,
89
90 BOOST_HIGH = 5,
91 BOOST_TERRAIN , // has to be high priority for minimap / low detail
92 BOOST_SELECTED ,
93 BOOST_HUD ,
94 BOOST_AVATAR_BAKED_SELF ,
95 BOOST_UI ,
96 BOOST_PREVIEW ,
97 BOOST_MAP ,
98 BOOST_MAP_VISIBLE ,
99 BOOST_AVATAR_SELF ,// needed for baking avatar
100 BOOST_MAX_LEVEL,
101
102 //LLImageGLCategory
103 TEXLAYER_BUMP = BOOST_MAX_LEVEL,
104 AVATAR_SCRATCH_TEX,
105 FONT,
106 BUMP_IMAGE,
107 DYNAMIC_TEX,
108 TEXLAYER_CACHE,
109 MEDIA,
110 ATLAS,
111 OTHER,
112 MAX_GL_IMAGE_CATEGORY
113 };
114};
115//=====================================
78class LLViewerImage : public LLImageGL 116class LLViewerImage : public LLImageGL
79{ 117{
80 LOG_CLASS(LLViewerImage); 118 LOG_CLASS(LLViewerImage);
@@ -175,15 +213,15 @@ protected:
175 /*virtual*/ ~LLViewerImage(); 213 /*virtual*/ ~LLViewerImage();
176 214
177public: 215public:
178 LLViewerImage(const std::string& filename, const LLUUID& id, BOOL usemipmaps = TRUE); 216 LLViewerImage(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE);
179 LLViewerImage(const LLUUID& id, BOOL usemipmaps = TRUE); 217 LLViewerImage(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
180 LLViewerImage(const U32 width, const U32 height, const U8 components, BOOL usemipmaps); 218 LLViewerImage(const U32 width, const U32 height, const U8 components, BOOL usemipmaps);
181 LLViewerImage(const LLImageRaw* raw, BOOL usemipmaps); 219 LLViewerImage(const LLImageRaw* raw, BOOL usemipmaps);
182 220
183 /*virtual*/ void dump(); // debug info to llinfos 221 /*virtual*/ void dump(); // debug info to llinfos
184 222
185 /*virtual*/ bool bindError(const S32 stage = 0) const; 223 /*virtual*/ bool bindError(const S32 stage = 0) const;
186 /*virtual*/ bool bindDefaultImage(const S32 stage = 0) const; 224 /*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
187 /*virtual*/ void forceImmediateUpdate() ; 225 /*virtual*/ void forceImmediateUpdate() ;
188 226
189 void reinit(BOOL usemipmaps = TRUE); 227 void reinit(BOOL usemipmaps = TRUE);
@@ -192,8 +230,13 @@ public:
192 230
193 // New methods for determining image quality/priority 231 // New methods for determining image quality/priority
194 // texel_area_ratio is ("scaled" texel area)/(original texel area), approximately. 232 // texel_area_ratio is ("scaled" texel area)/(original texel area), approximately.
195 void addTextureStats(F32 virtual_size) const; 233 void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
196 void resetTextureStats(BOOL zero = FALSE); 234 void resetTextureStats();
235 void setAdditionalDecodePriority(F32 priority) ;
236 F32 maxAdditionalDecodePriority() ;
237
238 BOOL isLargeImage() ;
239 BOOL isUpdateFrozen() ;
197 240
198 // Process image stats to determine priority/quality requirements. 241 // Process image stats to determine priority/quality requirements.
199 void processTextureStats(); 242 void processTextureStats();
@@ -207,6 +250,7 @@ public:
207 // ONLY call from LLViewerImageList 250 // ONLY call from LLViewerImageList
208 BOOL createTexture(S32 usename = 0); 251 BOOL createTexture(S32 usename = 0);
209 void destroyTexture() ; 252 void destroyTexture() ;
253 void addToCreateTexture();
210 254
211 BOOL needsAux() const { return mNeedsAux; } 255 BOOL needsAux() const { return mNeedsAux; }
212 256
@@ -217,32 +261,12 @@ public:
217 void setMinDiscardLevel(S32 discard) { mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); } 261 void setMinDiscardLevel(S32 discard) { mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
218 262
219 // Host we think might have this image, used for baked av textures. 263 // Host we think might have this image, used for baked av textures.
220 void setTargetHost(LLHost host) { mTargetHost = host; }
221 LLHost getTargetHost() const { return mTargetHost; } 264 LLHost getTargetHost() const { return mTargetHost; }
222 265
223 enum
224 {
225 BOOST_NONE = 0,
226 BOOST_AVATAR_BAKED = 1,
227 BOOST_AVATAR = 2,
228 BOOST_CLOUDS = 3,
229 BOOST_SCULPTED = 4,
230
231 BOOST_HIGH = 10,
232 BOOST_TERRAIN = 11, // has to be high priority for minimap / low detail
233 BOOST_SELECTED = 12,
234 BOOST_HUD = 13,
235 BOOST_AVATAR_BAKED_SELF = 14,
236 BOOST_UI = 15,
237 BOOST_PREVIEW = 16,
238 BOOST_MAP = 17,
239 BOOST_MAP_LAYER = 18,
240 BOOST_AVATAR_SELF = 19, // needed for baking avatar
241 BOOST_MAX_LEVEL
242 };
243 void setBoostLevel(S32 level); 266 void setBoostLevel(S32 level);
244 S32 getBoostLevel() { return mBoostLevel; } 267 S32 getBoostLevel() { return mBoostLevel; }
245 268
269 void updateVirtualSize() ;
246 F32 getDecodePriority() const { return mDecodePriority; }; 270 F32 getDecodePriority() const { return mDecodePriority; };
247 F32 calcDecodePriority(); 271 F32 calcDecodePriority();
248 static F32 maxDecodePriority(); 272 static F32 maxDecodePriority();
@@ -271,6 +295,24 @@ public:
271 S32 getOriginalWidth() { return mOrigWidth; } 295 S32 getOriginalWidth() { return mOrigWidth; }
272 S32 getOriginalHeight() { return mOrigHeight; } 296 S32 getOriginalHeight() { return mOrigHeight; }
273 297
298 BOOL isForSculptOnly() const ;
299 void setForSculpt();
300
301 void checkCachedRawSculptImage() ;
302 LLImageRaw* getRawImage()const { return mRawImage ;}
303 S32 getRawImageLevel() const {return mRawDiscardLevel;}
304 LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
305 S32 getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
306 BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;}
307 BOOL isRawImageValid()const { return mIsRawImageValid ; }
308
309 void forceToSaveRawImage(S32 desired_discard = 0) ;
310 void destroySavedRawImage() ;
311
312 BOOL isSameTexture(const LLViewerImage* tex) const ;
313
314 void addFace(LLFace* facep) ;
315 void removeFace(LLFace* facep) ;
274private: 316private:
275 /*virtual*/ void cleanup(); // Cleanup the LLViewerImage (so we can reinitialize it) 317 /*virtual*/ void cleanup(); // Cleanup the LLViewerImage (so we can reinitialize it)
276 318
@@ -279,14 +321,19 @@ private:
279 // Used to be in LLImageGL 321 // Used to be in LLImageGL
280 LLImageRaw* readBackRawImage(S8 discard_level = 0); 322 LLImageRaw* readBackRawImage(S8 discard_level = 0);
281 void destroyRawImage(); 323 void destroyRawImage();
282 324 void saveRawImage() ;
325 BOOL forceFetch() ;
326
327 void scaleDown() ;
328 void switchToCachedImage();
329 void setCachedRawImage() ;
283public: 330public:
284 S32 mFullWidth; 331 S32 mFullWidth;
285 S32 mFullHeight; 332 S32 mFullHeight;
286 333
287 S32 mOrigWidth; 334 S32 mOrigWidth;
288 S32 mOrigHeight; 335 S32 mOrigHeight;
289 std::string mLocalFileName; 336 std::string mUrl;
290 337
291 // Data used for calculating required image priority/quality level/decimation 338 // Data used for calculating required image priority/quality level/decimation
292 mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need? 339 mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need?
@@ -318,6 +365,7 @@ private:
318 S8 mDesiredDiscardLevel; // The discard level we'd LIKE to have - if we have it and there's space 365 S8 mDesiredDiscardLevel; // The discard level we'd LIKE to have - if we have it and there's space
319 S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have 366 S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have
320 S8 mNeedsCreateTexture; 367 S8 mNeedsCreateTexture;
368 mutable S8 mNeedsGLTexture;
321 S8 mNeedsAux; // We need to decode the auxiliary channels 369 S8 mNeedsAux; // We need to decode the auxiliary channels
322 S8 mDecodingAux; // Are we decoding high components 370 S8 mDecodingAux; // Are we decoding high components
323 S8 mIsRawImageValid; 371 S8 mIsRawImageValid;
@@ -332,6 +380,7 @@ private:
332 S32 mKnownDrawHeight; 380 S32 mKnownDrawHeight;
333 381
334 F32 mDecodePriority; // The priority for decoding this image. 382 F32 mDecodePriority; // The priority for decoding this image.
383 mutable F32 mAdditionalDecodePriority; // priority add to mDecodePriority.
335 S32 mBoostLevel; // enum describing priority level 384 S32 mBoostLevel; // enum describing priority level
336 385
337 typedef std::list<LLLoadedCallbackEntry*> callback_list_t; 386 typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
@@ -342,12 +391,30 @@ private:
342 S32 mMinDiscardLevel; 391 S32 mMinDiscardLevel;
343 F32 mCalculatedDiscardLevel; // Last calculated discard level 392 F32 mCalculatedDiscardLevel; // Last calculated discard level
344 393
394 //keep a copy of mRawImage for some special purposes
395 //when mForceToSaveRawImage is set.
396 BOOL mForceToSaveRawImage ;
397 LLPointer<LLImageRaw> mSavedRawImage;
398 S32 mSavedRawDiscardLevel;
399 S32 mDesiredSavedRawDiscardLevel;
400
345 // Used ONLY for cloth meshes right now. Make SURE you know what you're 401 // Used ONLY for cloth meshes right now. Make SURE you know what you're
346 // doing if you use it for anything else! - djs 402 // doing if you use it for anything else! - djs
347 LLPointer<LLImageRaw> mAuxRawImage; 403 LLPointer<LLImageRaw> mAuxRawImage;
348 404
405 //a small version of the copy of the raw image (<= 64 * 64)
406 LLPointer<LLImageRaw> mCachedRawImage;
407 S32 mCachedRawDiscardLevel;
408 BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.
409
349 LLHost mTargetHost; // if LLHost::invalid, just request from agent's simulator 410 LLHost mTargetHost; // if LLHost::invalid, just request from agent's simulator
350 411
412 BOOL mForSculpt ; //a flag if the texture is used for a sculpt data.
413 mutable BOOL mNeedsResetMaxVirtualSize ;
414
415 typedef std::list<LLFace*> ll_face_list_t ;
416 ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture
417
351public: 418public:
352 static const U32 sCurrentFileVersion; 419 static const U32 sCurrentFileVersion;
353 // Default textures 420 // Default textures
@@ -361,6 +428,7 @@ public:
361 static S32 sRawCount; 428 static S32 sRawCount;
362 static S32 sAuxCount; 429 static S32 sAuxCount;
363 static LLTimer sEvaluationTimer; 430 static LLTimer sEvaluationTimer;
431 static S8 sCameraMovingDiscardBias;
364 static F32 sDesiredDiscardBias; 432 static F32 sDesiredDiscardBias;
365 static F32 sDesiredDiscardScale; 433 static F32 sDesiredDiscardScale;
366 static S32 sBoundTextureMemoryInBytes; 434 static S32 sBoundTextureMemoryInBytes;
@@ -369,6 +437,12 @@ public:
369 static S32 sMaxTotalTextureMemInMegaBytes; 437 static S32 sMaxTotalTextureMemInMegaBytes;
370 static S32 sMaxDesiredTextureMemInBytes ; 438 static S32 sMaxDesiredTextureMemInBytes ;
371 static BOOL sDontLoadVolumeTextures; 439 static BOOL sDontLoadVolumeTextures;
440
441 static S32 sMaxSculptRez ;
442 static S32 sMinLargeImageSize ;
443 static S32 sMaxSmallImageSize ;
444 static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
445 static S32 sLLViewerImageCount ;
372}; 446};
373 447
374#endif 448#endif
diff --git a/linden/indra/newview/llviewerimagelist.cpp b/linden/indra/newview/llviewerimagelist.cpp
index bd834a0..2280937 100644
--- a/linden/indra/newview/llviewerimagelist.cpp
+++ b/linden/indra/newview/llviewerimagelist.cpp
@@ -42,6 +42,7 @@
42#include "llimagetga.h" 42#include "llimagetga.h"
43#include "llimagejpeg.h" 43#include "llimagejpeg.h"
44#include "llimagepng.h" 44#include "llimagepng.h"
45#include "llimageworker.h"
45 46
46#include "llsdserialize.h" 47#include "llsdserialize.h"
47#include "llsys.h" 48#include "llsys.h"
@@ -58,6 +59,7 @@
58#include "llviewerimage.h" 59#include "llviewerimage.h"
59#include "llviewermedia.h" 60#include "llviewermedia.h"
60#include "llviewerregion.h" 61#include "llviewerregion.h"
62#include "llviewerstats.h"
61#include "pipeline.h" 63#include "pipeline.h"
62#include "llappviewer.h" 64#include "llappviewer.h"
63 65
@@ -70,11 +72,6 @@ void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL;
70U32 LLViewerImageList::sTextureBits = 0; 72U32 LLViewerImageList::sTextureBits = 0;
71U32 LLViewerImageList::sTexturePackets = 0; 73U32 LLViewerImageList::sTexturePackets = 0;
72 74
73const S32 IMAGES_PER_REQUEST = 42;
74const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame
75const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame
76const F32 RESEND_IMAGE_REQUEST_TIME = 15.f; // seconds
77
78LLViewerImageList gImageList; 75LLViewerImageList gImageList;
79 76
80S32 LLViewerImageList::sNumImages = 0; 77S32 LLViewerImageList::sNumImages = 0;
@@ -182,6 +179,7 @@ static std::string get_texture_list_name()
182 179
183void LLViewerImageList::doPrefetchImages() 180void LLViewerImageList::doPrefetchImages()
184{ 181{
182#if 1
185 if (LLAppViewer::instance()->getPurgeCache()) 183 if (LLAppViewer::instance()->getPurgeCache())
186 { 184 {
187 // cache was purged, no point 185 // cache was purged, no point
@@ -209,7 +207,7 @@ void LLViewerImageList::doPrefetchImages()
209 image->addTextureStats((F32)pixel_area); 207 image->addTextureStats((F32)pixel_area);
210 } 208 }
211 } 209 }
212 210#endif
213 211
214} 212}
215 213
@@ -237,6 +235,10 @@ void LLViewerImageList::shutdown()
237 { 235 {
238 continue; // avoid UI, baked, and other special images 236 continue; // avoid UI, baked, and other special images
239 } 237 }
238 if(!image->getBoundRecently())
239 {
240 continue ;
241 }
240 S32 desired = image->getDesiredDiscardLevel(); 242 S32 desired = image->getDesiredDiscardLevel();
241 if (desired >= 0 && desired < MAX_DISCARD_LEVEL) 243 if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
242 { 244 {
@@ -323,17 +325,29 @@ LLViewerImage* LLViewerImageList::getImageFromFile(const std::string& filename,
323 LLGLenum primary_format, 325 LLGLenum primary_format,
324 const LLUUID& force_id) 326 const LLUUID& force_id)
325{ 327{
326 if (gNoRender) 328 std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename);
329 if (full_path.empty())
327 { 330 {
328 // Never mind that this ignores image_set_id; 331 llwarns << "Failed to find local image file: " << filename << llendl;
329 // getImage() will handle that later.
330 return getImage(IMG_DEFAULT, TRUE, TRUE); 332 return getImage(IMG_DEFAULT, TRUE, TRUE);
331 } 333 }
332 334
333 std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename); 335 std::string url = "file://" + full_path;
334 if (full_path.empty()) 336
337 return getImageFromUrl(url, usemipmaps, level_immediate, internal_format, primary_format, force_id);
338}
339
340LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url,
341 BOOL usemipmaps,
342 BOOL level_immediate,
343 LLGLint internal_format,
344 LLGLenum primary_format,
345 const LLUUID& force_id)
346{
347 if (gNoRender)
335 { 348 {
336 llwarns << "Failed to find local image file: " << filename << llendl; 349 // Never mind that this ignores image_set_id;
350 // getImage() will handle that later.
337 return getImage(IMG_DEFAULT, TRUE, TRUE); 351 return getImage(IMG_DEFAULT, TRUE, TRUE);
338 } 352 }
339 353
@@ -345,14 +359,14 @@ LLViewerImage* LLViewerImageList::getImageFromFile(const std::string& filename,
345 } 359 }
346 else 360 else
347 { 361 {
348 new_id.generate(full_path); 362 new_id.generate(url);
349 } 363 }
350 364
351 LLPointer<LLViewerImage> imagep = hasImage(new_id); 365 LLPointer<LLViewerImage> imagep = hasImage(new_id);
352 366
353 if (imagep.isNull()) 367 if (imagep.isNull())
354 { 368 {
355 imagep = new LLViewerImage(full_path, new_id, usemipmaps); 369 imagep = new LLViewerImage(url, new_id, usemipmaps);
356 370
357 if (internal_format && primary_format) 371 if (internal_format && primary_format)
358 { 372 {
@@ -364,7 +378,7 @@ LLViewerImage* LLViewerImageList::getImageFromFile(const std::string& filename,
364 if (level_immediate) 378 if (level_immediate)
365 { 379 {
366 imagep->dontDiscard(); 380 imagep->dontDiscard();
367 imagep->setBoostLevel(LLViewerImage::BOOST_UI); 381 imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_UI);
368 } 382 }
369 } 383 }
370 384
@@ -394,9 +408,7 @@ LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
394 408
395 if (imagep.isNull()) 409 if (imagep.isNull())
396 { 410 {
397 imagep = new LLViewerImage(image_id, usemipmaps); 411 imagep = new LLViewerImage(image_id, request_from_host, usemipmaps);
398 // Might want to request from host other than where the agent is. JC
399 imagep->setTargetHost(request_from_host);
400 412
401 if (internal_format && primary_format) 413 if (internal_format && primary_format)
402 { 414 {
@@ -408,7 +420,7 @@ LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
408 if (level_immediate) 420 if (level_immediate)
409 { 421 {
410 imagep->dontDiscard(); 422 imagep->dontDiscard();
411 imagep->setBoostLevel(LLViewerImage::BOOST_UI); 423 imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_UI);
412 } 424 }
413 else 425 else
414 { 426 {
@@ -511,23 +523,29 @@ void LLViewerImageList::dirtyImage(LLViewerImage *image)
511void LLViewerImageList::updateImages(F32 max_time) 523void LLViewerImageList::updateImages(F32 max_time)
512{ 524{
513 llpushcallstacks ; 525 llpushcallstacks ;
526 LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());
527
514 sNumImagesStat.addValue(sNumImages); 528 sNumImagesStat.addValue(sNumImages);
515 sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount); 529 sNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
516 sGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes)); 530 sGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes));
517 sGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes)); 531 sGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes));
518 sRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageRaw::sGlobalRawMemory)); 532 sRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageRaw::sGlobalRawMemory));
519 sFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory)); 533 sFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory));
520 534
521 llpushcallstacks ; 535 llpushcallstacks ;
536
522 updateImagesDecodePriorities(); 537 updateImagesDecodePriorities();
538
523 llpushcallstacks ; 539 llpushcallstacks ;
540 F32 total_max_time = max_time;
524 max_time -= updateImagesFetchTextures(max_time); 541 max_time -= updateImagesFetchTextures(max_time);
542
525 llpushcallstacks ; 543 llpushcallstacks ;
526 max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f); 544 max_time = llmax(max_time, total_max_time*.25f); // at least 25% of max_time
527 max_time -= updateImagesCreateTextures(max_time); 545 max_time -= updateImagesCreateTextures(max_time);
546
528 llpushcallstacks ; 547 llpushcallstacks ;
529 max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f); 548
530 llpushcallstacks ;
531 if (!mDirtyTextureList.empty()) 549 if (!mDirtyTextureList.empty())
532 { 550 {
533 LLFastTimer t(LLFastTimer::FTM_IMAGE_MARK_DIRTY); 551 LLFastTimer t(LLFastTimer::FTM_IMAGE_MARK_DIRTY);
@@ -541,7 +559,7 @@ void LLViewerImageList::updateImages(F32 max_time)
541 { 559 {
542 //trigger loaded callbacks on local textures immediately 560 //trigger loaded callbacks on local textures immediately
543 LLViewerImage* image = *iter++; 561 LLViewerImage* image = *iter++;
544 if (!image->mLocalFileName.empty()) 562 if (!image->mUrl.empty())
545 { 563 {
546 // Do stuff to handle callbacks, update priorities, etc. 564 // Do stuff to handle callbacks, update priorities, etc.
547 didone = image->doLoadedCallbacks(); 565 didone = image->doLoadedCallbacks();
@@ -627,7 +645,7 @@ void LLViewerImageList::updateImagesDecodePriorities()
627 imagep->setInactive() ; 645 imagep->setInactive() ;
628 } 646 }
629 } 647 }
630 648
631 imagep->processTextureStats(); 649 imagep->processTextureStats();
632 F32 old_priority = imagep->getDecodePriority(); 650 F32 old_priority = imagep->getDecodePriority();
633 F32 old_priority_test = llmax(old_priority, 0.0f); 651 F32 old_priority_test = llmax(old_priority, 0.0f);
@@ -701,7 +719,7 @@ F32 LLViewerImageList::updateImagesCreateTextures(F32 max_time)
701 return create_timer.getElapsedTimeF32(); 719 return create_timer.getElapsedTimeF32();
702} 720}
703 721
704void LLViewerImageList::forceImmediateUpdate(LLViewerImage* imagep) 722void LLViewerImageList::bumpToMaxDecodePriority(LLViewerImage* imagep)
705{ 723{
706 if(!imagep) 724 if(!imagep)
707 { 725 {
@@ -709,6 +727,11 @@ void LLViewerImageList::forceImmediateUpdate(LLViewerImage* imagep)
709 } 727 }
710 if(imagep->mInImageList) 728 if(imagep->mInImageList)
711 { 729 {
730 if (imagep->getDecodePriority() == LLViewerImage::maxDecodePriority())
731 {
732 // Already at maximum.
733 return;
734 }
712 removeImageFromList(imagep); 735 removeImageFromList(imagep);
713 } 736 }
714 737
@@ -731,74 +754,76 @@ F32 LLViewerImageList::updateImagesFetchTextures(F32 max_time)
731 const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256); 754 const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256);
732 755
733 // 32 high priority entries 756 // 32 high priority entries
734 std::set<LLViewerImage*> entries; 757 typedef std::vector<LLViewerImage*> entries_list_t;
758 entries_list_t entries;
735 size_t update_counter = llmin(max_priority_count, mImageList.size()); 759 size_t update_counter = llmin(max_priority_count, mImageList.size());
736 image_priority_list_t::iterator iter1 = mImageList.begin(); 760 image_priority_list_t::iterator iter1 = mImageList.begin();
737 while(update_counter > 0) 761 while(update_counter > 0)
738 { 762 {
739 // added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad 763 entries.push_back(*iter1);
740 if(iter1 == mImageList.end())
741 {
742 llerrs << "DEV-12002: update_counter not calculated correctly!" << llendl;
743 return 0.f;
744 }
745
746 LLPointer<LLViewerImage> const & ptr = *iter1;
747
748 LLViewerImage * img = ptr.get();
749
750 // added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad
751 if(img == NULL)
752 {
753 llwarns << "DEV-12002: image is NULL!" << llendl;
754 }
755
756 entries.insert(img);
757
758 ++iter1; 764 ++iter1;
759 update_counter--; 765 update_counter--;
760 } 766 }
761 767
762 // 256 cycled entries 768 // 256 cycled entries
763 update_counter = llmin(max_update_count, mUUIDMap.size()); 769 update_counter = llmin(max_update_count, mUUIDMap.size());
764 uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID); 770 if (update_counter > 0)
765 while(update_counter > 0)
766 { 771 {
767 if (iter2 == mUUIDMap.end()) 772 uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
773 uuid_map_t::iterator iter2p = iter2;
774 while(update_counter > 0)
768 { 775 {
769 iter2 = mUUIDMap.begin(); 776 if (iter2 == mUUIDMap.end())
777 {
778 iter2 = mUUIDMap.begin();
779 }
780 entries.push_back(iter2->second);
781 iter2p = iter2++;
782 update_counter--;
770 } 783 }
771 mLastFetchUUID = iter2->first; 784 mLastFetchUUID = iter2p->first;
772 entries.insert(iter2->second);
773 ++iter2;
774 update_counter--;
775 } 785 }
776 786
787 S32 fetch_count = 0;
777 S32 min_count = max_priority_count + max_update_count/4; 788 S32 min_count = max_priority_count + max_update_count/4;
778 for (std::set<LLViewerImage*>::iterator iter3 = entries.begin(); 789 for (entries_list_t::iterator iter3 = entries.begin();
779 iter3 != entries.end(); ) 790 iter3 != entries.end(); )
780 { 791 {
781 LLPointer<LLViewerImage> imagep = *iter3++; 792 LLPointer<LLViewerImage> imagep = *iter3++;
782 793
783 imagep->updateFetch(); 794 bool fetching = imagep->updateFetch();
795 if (fetching)
796 {
797 fetch_count++;
798 }
784 if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time) 799 if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
785 { 800 {
786 break; 801 break;
787 } 802 }
788 min_count--; 803 min_count--;
789 } 804 }
805 if (fetch_count == 0)
806 {
807 gDebugTimers[0].pause();
808 }
809 else
810 {
811 gDebugTimers[0].unpause();
812 }
813
814
790 return image_op_timer.getElapsedTimeF32(); 815 return image_op_timer.getElapsedTimeF32();
791} 816}
792 817
793void LLViewerImageList::updateImagesUpdateStats() 818void LLViewerImageList::updateImagesUpdateStats()
794{ 819{
795 if (mUpdateStats) 820 if (mUpdateStats && mForceResetTextureStats)
796 { 821 {
797 for (image_priority_list_t::iterator iter = mImageList.begin(); 822 for (image_priority_list_t::iterator iter = mImageList.begin();
798 iter != mImageList.end(); ) 823 iter != mImageList.end(); )
799 { 824 {
800 LLViewerImage* imagep = *iter++; 825 LLViewerImage* imagep = *iter++;
801 imagep->resetTextureStats(mForceResetTextureStats); 826 imagep->resetTextureStats();
802 } 827 }
803 mUpdateStats = FALSE; 828 mUpdateStats = FALSE;
804 mForceResetTextureStats = FALSE; 829 mForceResetTextureStats = FALSE;
@@ -1348,7 +1373,7 @@ void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerImage *src_vi, LLImag
1348 1373
1349 // for images grabbed from local files, apply clipping rectangle to restore original dimensions 1374 // for images grabbed from local files, apply clipping rectangle to restore original dimensions
1350 // from power-of-2 gl image 1375 // from power-of-2 gl image
1351 if (success && imagep.notNull() && src_vi && !src_vi->mLocalFileName.empty()) 1376 if (success && imagep.notNull() && src_vi && (src_vi->mUrl.compare(0, 7, "file://")==0))
1352 { 1377 {
1353 F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getWidth(0); 1378 F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getWidth(0);
1354 F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getHeight(0); 1379 F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getHeight(0);
diff --git a/linden/indra/newview/llviewerimagelist.h b/linden/indra/newview/llviewerimagelist.h
index 5fad0a2..561e8e5 100644
--- a/linden/indra/newview/llviewerimagelist.h
+++ b/linden/indra/newview/llviewerimagelist.h
@@ -97,7 +97,7 @@ public:
97 LLHost request_from_host = LLHost() 97 LLHost request_from_host = LLHost()
98 ); 98 );
99 99
100 LLViewerImage * getImageFromFile(const std::string& filename, 100 LLViewerImage * getImageFromUrl(const std::string& url,
101 BOOL usemipmap = TRUE, 101 BOOL usemipmap = TRUE,
102 BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. 102 BOOL level_immediate = FALSE, // Get the requested level immediately upon creation.
103 LLGLint internal_format = 0, 103 LLGLint internal_format = 0,
@@ -105,6 +105,14 @@ public:
105 const LLUUID& force_id = LLUUID::null 105 const LLUUID& force_id = LLUUID::null
106 ); 106 );
107 107
108 LLViewerImage * getImageFromFile(const std::string& filename,
109 BOOL usemipmap = TRUE,
110 BOOL level_immediate = FALSE, // Get the requested level immediately upon creation.
111 LLGLint internal_format = 0,
112 LLGLenum primary_format = 0,
113 const LLUUID& force_id = LLUUID::null
114 );
115
108 // Request image from a specific host, used for baked avatar textures. 116 // Request image from a specific host, used for baked avatar textures.
109 // Implemented in header in case someone changes default params above. JC 117 // Implemented in header in case someone changes default params above. JC
110 LLViewerImage* getImageFromHost(const LLUUID& image_id, LLHost host) 118 LLViewerImage* getImageFromHost(const LLUUID& image_id, LLHost host)
@@ -121,7 +129,7 @@ public:
121 129
122 // Using image stats, determine what images are necessary, and perform image updates. 130 // Using image stats, determine what images are necessary, and perform image updates.
123 void updateImages(F32 max_time); 131 void updateImages(F32 max_time);
124 void forceImmediateUpdate(LLViewerImage* imagep) ; 132 void bumpToMaxDecodePriority(LLViewerImage* imagep) ;
125 133
126 // Decode and create textures for all images currently in list. 134 // Decode and create textures for all images currently in list.
127 void decodeAllImages(F32 max_decode_time); 135 void decodeAllImages(F32 max_decode_time);
diff --git a/linden/indra/newview/llviewermessage.cpp b/linden/indra/newview/llviewermessage.cpp
index 94ae3ab..8bdbc30 100644
--- a/linden/indra/newview/llviewermessage.cpp
+++ b/linden/indra/newview/llviewermessage.cpp
@@ -106,6 +106,7 @@
106#include "llstatenums.h" 106#include "llstatenums.h"
107#include "llstatusbar.h" 107#include "llstatusbar.h"
108#include "llimview.h" 108#include "llimview.h"
109#include "lltexturestats.h"
109#include "lltool.h" 110#include "lltool.h"
110#include "lltoolbar.h" 111#include "lltoolbar.h"
111#include "lltoolmgr.h" 112#include "lltoolmgr.h"
diff --git a/linden/indra/newview/llviewerobject.cpp b/linden/indra/newview/llviewerobject.cpp
index 51908a5..860052c 100644
--- a/linden/indra/newview/llviewerobject.cpp
+++ b/linden/indra/newview/llviewerobject.cpp
@@ -2900,7 +2900,7 @@ F32 LLViewerObject::getMidScale() const
2900} 2900}
2901 2901
2902 2902
2903void LLViewerObject::updateTextures(LLAgent &agent) 2903void LLViewerObject::updateTextures()
2904{ 2904{
2905} 2905}
2906 2906
@@ -2915,14 +2915,14 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
2915 S32 tex_count = getNumTEs(); 2915 S32 tex_count = getNumTEs();
2916 for (i = 0; i < tex_count; i++) 2916 for (i = 0; i < tex_count; i++)
2917 { 2917 {
2918 getTEImage(i)->setBoostLevel(LLViewerImage::BOOST_SELECTED); 2918 getTEImage(i)->setBoostLevel(LLViewerImageBoostLevel::BOOST_SELECTED);
2919 } 2919 }
2920 2920
2921 if (isSculpted()) 2921 if (isSculpted())
2922 { 2922 {
2923 LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); 2923 LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
2924 LLUUID sculpt_id = sculpt_params->getSculptTexture(); 2924 LLUUID sculpt_id = sculpt_params->getSculptTexture();
2925 gImageList.getImage(sculpt_id)->setBoostLevel(LLViewerImage::BOOST_SELECTED); 2925 gImageList.getImage(sculpt_id)->setBoostLevel(LLViewerImageBoostLevel::BOOST_SELECTED);
2926 } 2926 }
2927 2927
2928 if (boost_children) 2928 if (boost_children)
diff --git a/linden/indra/newview/llviewerobject.h b/linden/indra/newview/llviewerobject.h
index 633e0eb..88f967f 100644
--- a/linden/indra/newview/llviewerobject.h
+++ b/linden/indra/newview/llviewerobject.h
@@ -190,7 +190,7 @@ public:
190 S32 getNumFaces() const { return mNumFaces; } 190 S32 getNumFaces() const { return mNumFaces; }
191 191
192 // Graphical stuff for objects - maybe broken out into render class later? 192 // Graphical stuff for objects - maybe broken out into render class later?
193 virtual void updateTextures(LLAgent &agent); 193 virtual void updateTextures();
194 virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object 194 virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object
195 195
196 virtual LLDrawable* createDrawable(LLPipeline *pipeline); 196 virtual LLDrawable* createDrawable(LLPipeline *pipeline);
diff --git a/linden/indra/newview/llviewerobjectlist.cpp b/linden/indra/newview/llviewerobjectlist.cpp
index 059925e..3ac8fc4 100644
--- a/linden/indra/newview/llviewerobjectlist.cpp
+++ b/linden/indra/newview/llviewerobjectlist.cpp
@@ -612,7 +612,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
612 612
613 // Update distance & gpw 613 // Update distance & gpw
614 objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area 614 objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area
615 objectp->updateTextures(agent); // Update the image levels of textures for this object. 615 objectp->updateTextures(); // Update the image levels of textures for this object.
616 } 616 }
617 } 617 }
618 618
diff --git a/linden/indra/newview/llviewerparceloverlay.cpp b/linden/indra/newview/llviewerparceloverlay.cpp
index 866c2a9..5cea9c2 100644
--- a/linden/indra/newview/llviewerparceloverlay.cpp
+++ b/linden/indra/newview/llviewerparceloverlay.cpp
@@ -71,7 +71,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
71 // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges 71 // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges
72 mTexture = new LLImageGL(FALSE); 72 mTexture = new LLImageGL(FALSE);
73 mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS); 73 mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS);
74 mTexture->createGLTexture(0, mImageRaw); 74 mTexture->createGLTexture(0, mImageRaw, 0, TRUE, LLViewerImageBoostLevel::OTHER);
75 gGL.getTexUnit(0)->activate(); 75 gGL.getTexUnit(0)->activate();
76 gGL.getTexUnit(0)->bind(mTexture); 76 gGL.getTexUnit(0)->bind(mTexture);
77 mTexture->setAddressMode(LLTexUnit::TAM_CLAMP); 77 mTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
diff --git a/linden/indra/newview/llviewerregion.cpp b/linden/indra/newview/llviewerregion.cpp
index 19b646c..1d380d7 100644
--- a/linden/indra/newview/llviewerregion.cpp
+++ b/linden/indra/newview/llviewerregion.cpp
@@ -1408,9 +1408,9 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
1408 capabilityNames.append("EstateChangeInfo"); 1408 capabilityNames.append("EstateChangeInfo");
1409 capabilityNames.append("EventQueueGet"); 1409 capabilityNames.append("EventQueueGet");
1410 capabilityNames.append("FetchInventory"); 1410 capabilityNames.append("FetchInventory");
1411 capabilityNames.append("WebFetchInventoryDescendents");
1412 capabilityNames.append("FetchLib"); 1411 capabilityNames.append("FetchLib");
1413 capabilityNames.append("FetchLibDescendents"); 1412 capabilityNames.append("FetchLibDescendents");
1413 capabilityNames.append("GetTexture");
1414 capabilityNames.append("GroupProposalBallot"); 1414 capabilityNames.append("GroupProposalBallot");
1415 capabilityNames.append("HomeLocation"); 1415 capabilityNames.append("HomeLocation");
1416 capabilityNames.append("MapLayer"); 1416 capabilityNames.append("MapLayer");
@@ -1429,6 +1429,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
1429 capabilityNames.append("SendUserReportWithScreenshot"); 1429 capabilityNames.append("SendUserReportWithScreenshot");
1430 capabilityNames.append("ServerReleaseNotes"); 1430 capabilityNames.append("ServerReleaseNotes");
1431 capabilityNames.append("StartGroupProposal"); 1431 capabilityNames.append("StartGroupProposal");
1432 capabilityNames.append("TextureStats");
1432 capabilityNames.append("UntrustedSimulatorMessage"); 1433 capabilityNames.append("UntrustedSimulatorMessage");
1433 capabilityNames.append("UpdateAgentInformation"); 1434 capabilityNames.append("UpdateAgentInformation");
1434 capabilityNames.append("UpdateAgentLanguage"); 1435 capabilityNames.append("UpdateAgentLanguage");
@@ -1441,6 +1442,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
1441 capabilityNames.append("UploadBakedTexture"); 1442 capabilityNames.append("UploadBakedTexture");
1442 capabilityNames.append("ViewerStartAuction"); 1443 capabilityNames.append("ViewerStartAuction");
1443 capabilityNames.append("ViewerStats"); 1444 capabilityNames.append("ViewerStats");
1445 capabilityNames.append("WebFetchInventoryDescendents");
1444 // Please add new capabilities alphabetically to reduce 1446 // Please add new capabilities alphabetically to reduce
1445 // merge conflicts. 1447 // merge conflicts.
1446 1448
diff --git a/linden/indra/newview/llviewerwindow.cpp b/linden/indra/newview/llviewerwindow.cpp
index ef4e728..3d884ad 100644
--- a/linden/indra/newview/llviewerwindow.cpp
+++ b/linden/indra/newview/llviewerwindow.cpp
@@ -115,6 +115,7 @@
115#include "llhudview.h" 115#include "llhudview.h"
116#include "llimagebmp.h" 116#include "llimagebmp.h"
117#include "llimagej2c.h" 117#include "llimagej2c.h"
118#include "llimageworker.h"
118#include "llinventoryview.h" 119#include "llinventoryview.h"
119#include "llkeyboard.h" 120#include "llkeyboard.h"
120#include "lllineeditor.h" 121#include "lllineeditor.h"
@@ -1310,6 +1311,7 @@ LLViewerWindow::LLViewerWindow(
1310 1311
1311 // Init the image list. Must happen after GL is initialized and before the images that 1312 // Init the image list. Must happen after GL is initialized and before the images that
1312 // LLViewerWindow needs are requested. 1313 // LLViewerWindow needs are requested.
1314 LLImageGL::initClass(LLViewerImageBoostLevel::MAX_GL_IMAGE_CATEGORY) ;
1313 gImageList.init(); 1315 gImageList.init();
1314 LLViewerImage::initClass(); 1316 LLViewerImage::initClass();
1315 gBumpImageList.init(); 1317 gBumpImageList.init();
diff --git a/linden/indra/newview/llvlcomposition.cpp b/linden/indra/newview/llvlcomposition.cpp
index a269225..9c383c7 100644
--- a/linden/indra/newview/llvlcomposition.cpp
+++ b/linden/indra/newview/llvlcomposition.cpp
@@ -234,7 +234,7 @@ BOOL LLVLComposition::generateComposition()
234 { 234 {
235 if (mDetailTextures[i]->getDiscardLevel() < 0) 235 if (mDetailTextures[i]->getDiscardLevel() < 0)
236 { 236 {
237 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); // in case we are at low detail 237 mDetailTextures[i]->setBoostLevel(LLViewerImageBoostLevel::BOOST_TERRAIN); // in case we are at low detail
238 mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE); 238 mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE);
239 return FALSE; 239 return FALSE;
240 } 240 }
@@ -251,7 +251,7 @@ BOOL LLVLComposition::generateComposition()
251 ddiscard++; 251 ddiscard++;
252 min_dim /= 2; 252 min_dim /= 2;
253 } 253 }
254 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); // in case we are at low detail 254 mDetailTextures[i]->setBoostLevel(LLViewerImageBoostLevel::BOOST_TERRAIN); // in case we are at low detail
255 mDetailTextures[i]->setMinDiscardLevel(ddiscard); 255 mDetailTextures[i]->setMinDiscardLevel(ddiscard);
256 return FALSE; 256 return FALSE;
257 } 257 }
@@ -292,10 +292,10 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
292 ddiscard++; 292 ddiscard++;
293 min_dim /= 2; 293 min_dim /= 2;
294 } 294 }
295 if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i], false)) 295 mRawImages[i] = mDetailTextures[i]->getCachedRawImage() ;
296 if (!mRawImages[i])
296 { 297 {
297 llwarns << "Unable to read raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl; 298 llwarns << "no cached raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl;
298 mRawImages[i] = NULL;
299 return FALSE; 299 return FALSE;
300 } 300 }
301 if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE || 301 if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE ||
@@ -460,7 +460,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
460 for (S32 i = 0; i < 4; i++) 460 for (S32 i = 0; i < 4; i++)
461 { 461 {
462 // Un-boost detatil textures (will get re-boosted if rendering in high detail) 462 // Un-boost detatil textures (will get re-boosted if rendering in high detail)
463 mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_NONE); 463 mDetailTextures[i]->setBoostLevel(LLViewerImageBoostLevel::BOOST_NONE);
464 mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1); 464 mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1);
465 } 465 }
466 466
diff --git a/linden/indra/newview/llvoavatar.cpp b/linden/indra/newview/llvoavatar.cpp
index ab5d83e..d2f4a58 100644
--- a/linden/indra/newview/llvoavatar.cpp
+++ b/linden/indra/newview/llvoavatar.cpp
@@ -1272,6 +1272,49 @@ void LLVOAvatar::resetImpostors()
1272// static 1272// static
1273void LLVOAvatar::deleteCachedImages(bool clearAll) 1273void LLVOAvatar::deleteCachedImages(bool clearAll)
1274{ 1274{
1275if(gAuditTexture)
1276 {
1277 S32 total_tex_size = sScratchTexBytes ;
1278 S32 tex_size = SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT ;
1279
1280 if( LLVOAvatar::sScratchTexNames.checkData( GL_LUMINANCE ) )
1281 {
1282 LLImageGL::decTextureCounterStatic(tex_size, 1, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1283 total_tex_size -= tex_size ;
1284 }
1285 if( LLVOAvatar::sScratchTexNames.checkData( GL_ALPHA ) )
1286 {
1287 LLImageGL::decTextureCounterStatic(tex_size, 1, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1288 total_tex_size -= tex_size ;
1289 }
1290 if( LLVOAvatar::sScratchTexNames.checkData( GL_COLOR_INDEX ) )
1291 {
1292 LLImageGL::decTextureCounterStatic(tex_size, 1, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1293 total_tex_size -= tex_size ;
1294 }
1295 if( LLVOAvatar::sScratchTexNames.checkData( GL_LUMINANCE_ALPHA ) )
1296 {
1297 LLImageGL::decTextureCounterStatic(tex_size, 2, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1298 total_tex_size -= 2 * tex_size ;
1299 }
1300 if( LLVOAvatar::sScratchTexNames.checkData( GL_RGB ) )
1301 {
1302 LLImageGL::decTextureCounterStatic(tex_size, 3, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1303 total_tex_size -= 3 * tex_size ;
1304 }
1305 if( LLVOAvatar::sScratchTexNames.checkData( GL_RGBA ) )
1306 {
1307 LLImageGL::decTextureCounterStatic(tex_size, 4, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1308 total_tex_size -= 4 * tex_size ;
1309 }
1310 //others
1311 while(total_tex_size > 0)
1312 {
1313 LLImageGL::decTextureCounterStatic(tex_size, 4, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
1314 total_tex_size -= 4 * tex_size ;
1315 }
1316 }
1317
1275 if (LLTexLayerSet::sHasCaches) 1318 if (LLTexLayerSet::sHasCaches)
1276 { 1319 {
1277 lldebugs << "Deleting layer set caches" << llendl; 1320 lldebugs << "Deleting layer set caches" << llendl;
@@ -4701,7 +4744,7 @@ U32 LLVOAvatar::renderFootShadows()
4701 LLGLDepthTest test(GL_TRUE, GL_FALSE); 4744 LLGLDepthTest test(GL_TRUE, GL_FALSE);
4702 //render foot shadows 4745 //render foot shadows
4703 LLGLEnable blend(GL_BLEND); 4746 LLGLEnable blend(GL_BLEND);
4704 gGL.getTexUnit(0)->bind(mShadowImagep.get()); 4747 gGL.getTexUnit(0)->bind(mShadowImagep.get(), TRUE);
4705 glColor4fv(mShadow0Facep->getRenderColor().mV); 4748 glColor4fv(mShadow0Facep->getRenderColor().mV);
4706 mShadow0Facep->renderIndexed(foot_mask); 4749 mShadow0Facep->renderIndexed(foot_mask);
4707 glColor4fv(mShadow1Facep->getRenderColor().mV); 4750 glColor4fv(mShadow1Facep->getRenderColor().mV);
@@ -4749,7 +4792,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color)
4749//------------------------------------------------------------------------ 4792//------------------------------------------------------------------------
4750// LLVOAvatar::updateTextures() 4793// LLVOAvatar::updateTextures()
4751//------------------------------------------------------------------------ 4794//------------------------------------------------------------------------
4752void LLVOAvatar::updateTextures(LLAgent &agent) 4795void LLVOAvatar::updateTextures()
4753{ 4796{
4754 BOOL render_avatar = TRUE; 4797 BOOL render_avatar = TRUE;
4755 4798
@@ -4816,9 +4859,9 @@ void LLVOAvatar::updateTextures(LLAgent &agent)
4816 if (imagep) 4859 if (imagep)
4817 { 4860 {
4818 // Debugging code - maybe non-self avatars are downloading textures? 4861 // Debugging code - maybe non-self avatars are downloading textures?
4819 //llinfos << "avatar self " << mIsSelf << " tex " << i 4862 //llinfos << "avatar self " << mIsSelf << " tex " << index
4820 // << " decode " << imagep->getDecodePriority() 4863 // << " decode " << imagep->getDecodePriority()
4821 // << " boost " << boost_avatar 4864 // << " boost " << imagep->getBoostLevel()
4822 // << " size " << imagep->getWidth() << "x" << imagep->getHeight() 4865 // << " size " << imagep->getWidth() << "x" << imagep->getHeight()
4823 // << " discard " << imagep->getDiscardLevel() 4866 // << " discard " << imagep->getDiscardLevel()
4824 // << " desired " << imagep->getDesiredDiscardLevel() 4867 // << " desired " << imagep->getDesiredDiscardLevel()
@@ -4826,7 +4869,7 @@ void LLVOAvatar::updateTextures(LLAgent &agent)
4826 4869
4827 const LLTextureEntry *te = getTE(index); 4870 const LLTextureEntry *te = getTE(index);
4828 F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); 4871 F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT);
4829 S32 boost_level = mIsSelf ? LLViewerImage::BOOST_AVATAR_BAKED_SELF : LLViewerImage::BOOST_AVATAR_BAKED; 4872 S32 boost_level = mIsSelf ? LLViewerImageBoostLevel::BOOST_AVATAR_BAKED_SELF : LLViewerImageBoostLevel::BOOST_AVATAR_BAKED;
4830 4873
4831 // Spam if this is a baked texture, not set to default image, without valid host info 4874 // Spam if this is a baked texture, not set to default image, without valid host info
4832 if (isIndexBakedTexture((ETextureIndex)index) 4875 if (isIndexBakedTexture((ETextureIndex)index)
@@ -4849,6 +4892,12 @@ void LLVOAvatar::updateTextures(LLAgent &agent)
4849 if (texture_dict->mIsLocalTexture) 4892 if (texture_dict->mIsLocalTexture)
4850 { 4893 {
4851 addLocalTextureStats((ETextureIndex)index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]); 4894 addLocalTextureStats((ETextureIndex)index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]);
4895 // SNOW-8 : temporary snowglobe1.0 fix for baked textures
4896 if (render_avatar && !gGLManager.mIsDisabled )
4897 {
4898 // bind the texture so that its boost level won't be slammed
4899 gGL.getTexUnit(0)->bind(imagep);
4900 }
4852 } 4901 }
4853 else if (texture_dict->mIsBakedTexture) 4902 else if (texture_dict->mIsBakedTexture)
4854 { 4903 {
@@ -4886,12 +4935,12 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerImage* imagep,
4886 if( mIsSelf ) 4935 if( mIsSelf )
4887 { 4936 {
4888 desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_SELF ); 4937 desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_SELF );
4889 imagep->setBoostLevel(LLViewerImage::BOOST_AVATAR_SELF); 4938 imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_AVATAR_SELF);
4890 } 4939 }
4891 else 4940 else
4892 { 4941 {
4893 desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_OTHER ); 4942 desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_OTHER );
4894 imagep->setBoostLevel(LLViewerImage::BOOST_AVATAR); 4943 imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_AVATAR);
4895 } 4944 }
4896 imagep->addTextureStats( desired_pixels / texel_area_ratio ); 4945 imagep->addTextureStats( desired_pixels / texel_area_ratio );
4897 if (imagep->getDiscardLevel() < 0) 4946 if (imagep->getDiscardLevel() < 0)
@@ -7111,12 +7160,12 @@ BOOL LLVOAvatar::bindScratchTexture( LLGLenum format )
7111 if( *last_bind_time != LLImageGL::sLastFrameTime ) 7160 if( *last_bind_time != LLImageGL::sLastFrameTime )
7112 { 7161 {
7113 *last_bind_time = LLImageGL::sLastFrameTime; 7162 *last_bind_time = LLImageGL::sLastFrameTime;
7114 LLImageGL::updateBoundTexMem(texture_bytes); 7163 LLImageGL::updateBoundTexMemStatic(texture_bytes, SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
7115 } 7164 }
7116 } 7165 }
7117 else 7166 else
7118 { 7167 {
7119 LLImageGL::updateBoundTexMem(texture_bytes); 7168 LLImageGL::updateBoundTexMemStatic(texture_bytes, SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
7120 LLVOAvatar::sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) ); 7169 LLVOAvatar::sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) );
7121 } 7170 }
7122 7171
@@ -7138,7 +7187,8 @@ LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes )
7138 { 7187 {
7139 case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break; 7188 case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break;
7140 case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break; 7189 case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break;
7141 case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break; 7190// Support for GL_EXT_paletted_texture is deprecated
7191// case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break;
7142 case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break; 7192 case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break;
7143 case GL_RGB: components = 3; internal_format = GL_RGB8; break; 7193 case GL_RGB: components = 3; internal_format = GL_RGB8; break;
7144 case GL_RGBA: components = 4; internal_format = GL_RGBA8; break; 7194 case GL_RGBA: components = 4; internal_format = GL_RGBA8; break;
@@ -7180,6 +7230,12 @@ LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes )
7180 7230
7181 LLVOAvatar::sScratchTexBytes += *texture_bytes; 7231 LLVOAvatar::sScratchTexBytes += *texture_bytes;
7182 LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes; 7232 LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes;
7233
7234 if(gAuditTexture)
7235 {
7236 LLImageGL::incTextureCounterStatic(SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, components, LLViewerImageBoostLevel::AVATAR_SCRATCH_TEX) ;
7237 }
7238
7183 return name; 7239 return name;
7184 } 7240 }
7185} 7241}
@@ -7495,7 +7551,8 @@ void LLVOAvatar::clearChat()
7495 7551
7496S32 LLVOAvatar::getLocalDiscardLevel( ETextureIndex index ) 7552S32 LLVOAvatar::getLocalDiscardLevel( ETextureIndex index )
7497{ 7553{
7498 if (!isIndexLocalTexture(index)) return FALSE; 7554 // If the texture is not local, we don't care and treat it as fully loaded
7555 if (!isIndexLocalTexture(index)) return 0;
7499 7556
7500 LocalTextureData &local_tex_data = mLocalTextureData[index]; 7557 LocalTextureData &local_tex_data = mLocalTextureData[index];
7501 if (index >= 0 7558 if (index >= 0
diff --git a/linden/indra/newview/llvoavatar.h b/linden/indra/newview/llvoavatar.h
index f759e15..33cec69 100644
--- a/linden/indra/newview/llvoavatar.h
+++ b/linden/indra/newview/llvoavatar.h
@@ -133,7 +133,7 @@ public:
133 LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point 133 LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point
134 ); 134 );
135 135
136 /*virtual*/ void updateTextures(LLAgent &agent); 136 /*virtual*/ void updateTextures();
137 // If setting a baked texture, need to request it from a non-local sim. 137 // If setting a baked texture, need to request it from a non-local sim.
138 /*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid); 138 /*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid);
139 /*virtual*/ void onShift(const LLVector3& shift_vector); 139 /*virtual*/ void onShift(const LLVector3& shift_vector);
diff --git a/linden/indra/newview/llvoclouds.cpp b/linden/indra/newview/llvoclouds.cpp
index 9095ee4..a489f91 100644
--- a/linden/indra/newview/llvoclouds.cpp
+++ b/linden/indra/newview/llvoclouds.cpp
@@ -62,7 +62,7 @@ LLVOClouds::LLVOClouds(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
62 mbCanSelect = FALSE; 62 mbCanSelect = FALSE;
63 setNumTEs(1); 63 setNumTEs(1);
64 LLViewerImage* image = gImageList.getImage(gCloudTextureID); 64 LLViewerImage* image = gImageList.getImage(gCloudTextureID);
65 image->setBoostLevel(LLViewerImage::BOOST_CLOUDS); 65 image->setBoostLevel(LLViewerImageBoostLevel::BOOST_CLOUDS);
66 setTEImage(0, image); 66 setTEImage(0, image);
67} 67}
68 68
@@ -101,7 +101,7 @@ void LLVOClouds::setPixelAreaAndAngle(LLAgent &agent)
101 mPixelArea = 1500*100; 101 mPixelArea = 1500*100;
102} 102}
103 103
104void LLVOClouds::updateTextures(LLAgent &agent) 104void LLVOClouds::updateTextures()
105{ 105{
106 getTEImage(0)->addTextureStats(mPixelArea); 106 getTEImage(0)->addTextureStats(mPixelArea);
107} 107}
diff --git a/linden/indra/newview/llvoclouds.h b/linden/indra/newview/llvoclouds.h
index f70ea5b..52e5a68 100644
--- a/linden/indra/newview/llvoclouds.h
+++ b/linden/indra/newview/llvoclouds.h
@@ -65,7 +65,7 @@ public:
65 /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. 65 /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
66 F32 getPartSize(S32 idx); 66 F32 getPartSize(S32 idx);
67 67
68 /*virtual*/ void updateTextures(LLAgent &agent); 68 /*virtual*/ void updateTextures();
69 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area 69 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
70 70
71 void updateFaceSize(S32 idx) { } 71 void updateFaceSize(S32 idx) { }
diff --git a/linden/indra/newview/llvograss.cpp b/linden/indra/newview/llvograss.cpp
index dd4dabb..d0a36b0 100644
--- a/linden/indra/newview/llvograss.cpp
+++ b/linden/indra/newview/llvograss.cpp
@@ -339,7 +339,7 @@ void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent)
339 339
340 340
341// BUG could speed this up by caching the relative_position and range calculations 341// BUG could speed this up by caching the relative_position and range calculations
342void LLVOGrass::updateTextures(LLAgent &agent) 342void LLVOGrass::updateTextures()
343{ 343{
344 if (getTEImage(0)) 344 if (getTEImage(0))
345 { 345 {
diff --git a/linden/indra/newview/llvograss.h b/linden/indra/newview/llvograss.h
index b759488..abfc7e1 100644
--- a/linden/indra/newview/llvograss.h
+++ b/linden/indra/newview/llvograss.h
@@ -72,7 +72,7 @@ public:
72 LLStrider<U16>& indicesp); 72 LLStrider<U16>& indicesp);
73 73
74 void updateFaceSize(S32 idx) { } 74 void updateFaceSize(S32 idx) { }
75 /*virtual*/ void updateTextures(LLAgent &agent); 75 /*virtual*/ void updateTextures();
76 /*virtual*/ BOOL updateLOD(); 76 /*virtual*/ BOOL updateLOD();
77 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area 77 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
78 78
diff --git a/linden/indra/newview/llvoground.cpp b/linden/indra/newview/llvoground.cpp
index fe19e18..0ef0196 100644
--- a/linden/indra/newview/llvoground.cpp
+++ b/linden/indra/newview/llvoground.cpp
@@ -71,7 +71,7 @@ BOOL LLVOGround::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
71} 71}
72 72
73 73
74void LLVOGround::updateTextures(LLAgent &agent) 74void LLVOGround::updateTextures()
75{ 75{
76} 76}
77 77
diff --git a/linden/indra/newview/llvoground.h b/linden/indra/newview/llvoground.h
index f485bd0..b58ebae 100644
--- a/linden/indra/newview/llvoground.h
+++ b/linden/indra/newview/llvoground.h
@@ -51,7 +51,7 @@ public:
51 51
52 // Graphical stuff for objects - maybe broken out into render class 52 // Graphical stuff for objects - maybe broken out into render class
53 // later? 53 // later?
54 /*virtual*/ void updateTextures(LLAgent &agent); 54 /*virtual*/ void updateTextures();
55 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); 55 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
56 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 56 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
57 57
diff --git a/linden/indra/newview/llvopartgroup.cpp b/linden/indra/newview/llvopartgroup.cpp
index 29036f4..a0f8068 100644
--- a/linden/indra/newview/llvopartgroup.cpp
+++ b/linden/indra/newview/llvopartgroup.cpp
@@ -108,7 +108,7 @@ void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent)
108 } 108 }
109} 109}
110 110
111void LLVOPartGroup::updateTextures(LLAgent &agent) 111void LLVOPartGroup::updateTextures()
112{ 112{
113 // Texture stats for particles need to be updated in a different way... 113 // Texture stats for particles need to be updated in a different way...
114} 114}
diff --git a/linden/indra/newview/llvopartgroup.h b/linden/indra/newview/llvopartgroup.h
index 3dc3292..18583b4 100644
--- a/linden/indra/newview/llvopartgroup.h
+++ b/linden/indra/newview/llvopartgroup.h
@@ -61,7 +61,7 @@ public:
61 virtual U32 getPartitionType() const; 61 virtual U32 getPartitionType() const;
62 62
63 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); 63 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
64 /*virtual*/ void updateTextures(LLAgent &agent); 64 /*virtual*/ void updateTextures();
65 65
66 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); 66 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
67 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 67 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/linden/indra/newview/llvosky.cpp b/linden/indra/newview/llvosky.cpp
index d4df141..1b9c7c0 100644
--- a/linden/indra/newview/llvosky.cpp
+++ b/linden/indra/newview/llvosky.cpp
@@ -289,7 +289,7 @@ void LLSkyTex::create(const F32 brightness)
289 289
290void LLSkyTex::createGLImage(S32 which) 290void LLSkyTex::createGLImage(S32 which)
291{ 291{
292 mImageGL[which]->createGLTexture(0, mImageRaw[which]); 292 mImageGL[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLViewerImageBoostLevel::OTHER);
293 mImageGL[which]->setAddressMode(LLTexUnit::TAM_CLAMP); 293 mImageGL[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
294} 294}
295 295
@@ -1180,7 +1180,7 @@ BOOL LLVOSky::updateSky()
1180 return TRUE; 1180 return TRUE;
1181} 1181}
1182 1182
1183void LLVOSky::updateTextures(LLAgent &agent) 1183void LLVOSky::updateTextures()
1184{ 1184{
1185 if (mSunTexturep) 1185 if (mSunTexturep)
1186 { 1186 {
diff --git a/linden/indra/newview/llvosky.h b/linden/indra/newview/llvosky.h
index 3cf454d..333e144 100644
--- a/linden/indra/newview/llvosky.h
+++ b/linden/indra/newview/llvosky.h
@@ -492,7 +492,7 @@ public:
492 492
493 // Graphical stuff for objects - maybe broken out into render class 493 // Graphical stuff for objects - maybe broken out into render class
494 // later? 494 // later?
495 /*virtual*/ void updateTextures(LLAgent &agent); 495 /*virtual*/ void updateTextures();
496 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); 496 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
497 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 497 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
498 498
diff --git a/linden/indra/newview/llvosurfacepatch.cpp b/linden/indra/newview/llvosurfacepatch.cpp
index 4980b50..d86f758 100644
--- a/linden/indra/newview/llvosurfacepatch.cpp
+++ b/linden/indra/newview/llvosurfacepatch.cpp
@@ -134,7 +134,7 @@ void LLVOSurfacePatch::setPixelAreaAndAngle(LLAgent &agent)
134} 134}
135 135
136 136
137void LLVOSurfacePatch::updateTextures(LLAgent &agent) 137void LLVOSurfacePatch::updateTextures()
138{ 138{
139} 139}
140 140
diff --git a/linden/indra/newview/llvosurfacepatch.h b/linden/indra/newview/llvosurfacepatch.h
index 2dd8651..d3b1447 100644
--- a/linden/indra/newview/llvosurfacepatch.h
+++ b/linden/indra/newview/llvosurfacepatch.h
@@ -74,7 +74,7 @@ public:
74 LLStrider<LLVector2> &texCoords1p, 74 LLStrider<LLVector2> &texCoords1p,
75 LLStrider<U16> &indicesp); 75 LLStrider<U16> &indicesp);
76 76
77 /*virtual*/ void updateTextures(LLAgent &agent); 77 /*virtual*/ void updateTextures();
78 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area 78 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
79 79
80 /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); 80 /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
diff --git a/linden/indra/newview/llvotextbubble.cpp b/linden/indra/newview/llvotextbubble.cpp
index de69aac..5943f9b 100644
--- a/linden/indra/newview/llvotextbubble.cpp
+++ b/linden/indra/newview/llvotextbubble.cpp
@@ -116,7 +116,7 @@ BOOL LLVOTextBubble::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
116} 116}
117 117
118 118
119void LLVOTextBubble::updateTextures(LLAgent &agent) 119void LLVOTextBubble::updateTextures()
120{ 120{
121 // Update the image levels of all textures... 121 // Update the image levels of all textures...
122 122
diff --git a/linden/indra/newview/llvotextbubble.h b/linden/indra/newview/llvotextbubble.h
index 45d4df2..7f84dbf 100644
--- a/linden/indra/newview/llvotextbubble.h
+++ b/linden/indra/newview/llvotextbubble.h
@@ -44,7 +44,7 @@ public:
44 /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. 44 /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
45 /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); 45 /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
46 46
47 /*virtual*/ void updateTextures(LLAgent &agent); 47 /*virtual*/ void updateTextures();
48 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); 48 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
49 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 49 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
50 /*virtual*/ BOOL updateLOD(); 50 /*virtual*/ BOOL updateLOD();
diff --git a/linden/indra/newview/llvotree.cpp b/linden/indra/newview/llvotree.cpp
index 3523d87..237f581 100644
--- a/linden/indra/newview/llvotree.cpp
+++ b/linden/indra/newview/llvotree.cpp
@@ -475,7 +475,7 @@ void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
475#endif 475#endif
476} 476}
477 477
478void LLVOTree::updateTextures(LLAgent &agent) 478void LLVOTree::updateTextures()
479{ 479{
480 if (mTreeImagep) 480 if (mTreeImagep)
481 { 481 {
diff --git a/linden/indra/newview/llvotree.h b/linden/indra/newview/llvotree.h
index 748fc14..df0b5a9 100644
--- a/linden/indra/newview/llvotree.h
+++ b/linden/indra/newview/llvotree.h
@@ -69,7 +69,7 @@ public:
69 // Graphical stuff for objects - maybe broken out into render class later? 69 // Graphical stuff for objects - maybe broken out into render class later?
70 /*virtual*/ void render(LLAgent &agent); 70 /*virtual*/ void render(LLAgent &agent);
71 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); 71 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
72 /*virtual*/ void updateTextures(LLAgent &agent); 72 /*virtual*/ void updateTextures();
73 73
74 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); 74 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
75 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 75 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/linden/indra/newview/llvotreenew.h b/linden/indra/newview/llvotreenew.h
index 02f6d3a..4960d90 100644
--- a/linden/indra/newview/llvotreenew.h
+++ b/linden/indra/newview/llvotreenew.h
@@ -156,7 +156,7 @@ public:
156 /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); 156 /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
157 157
158 /*virtual*/ void render(LLAgent &agent); 158 /*virtual*/ void render(LLAgent &agent);
159 /*virtual*/ void updateTextures(LLAgent &agent); 159 /*virtual*/ void updateTextures();
160 160
161 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); 161 /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
162 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 162 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/linden/indra/newview/llvovolume.cpp b/linden/indra/newview/llvovolume.cpp
index 607bb42..5f7327d 100644
--- a/linden/indra/newview/llvovolume.cpp
+++ b/linden/indra/newview/llvovolume.cpp
@@ -52,12 +52,10 @@
52#include "lldrawpoolbump.h" 52#include "lldrawpoolbump.h"
53#include "llface.h" 53#include "llface.h"
54#include "llspatialpartition.h" 54#include "llspatialpartition.h"
55
56// TEMP HACK ventrella
57#include "llhudmanager.h" 55#include "llhudmanager.h"
58#include "llflexibleobject.h" 56#include "llflexibleobject.h"
59
60#include "llsky.h" 57#include "llsky.h"
58#include "lltexturefetch.h"
61#include "llviewercamera.h" 59#include "llviewercamera.h"
62#include "llviewerimagelist.h" 60#include "llviewerimagelist.h"
63#include "llviewerregion.h" 61#include "llviewerregion.h"
@@ -69,7 +67,6 @@
69const S32 MIN_QUIET_FRAMES_COALESCE = 30; 67const S32 MIN_QUIET_FRAMES_COALESCE = 30;
70const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; 68const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
71const F32 FORCE_CULL_AREA = 8.f; 69const F32 FORCE_CULL_AREA = 8.f;
72const S32 MAX_SCULPT_REZ = 128;
73 70
74BOOL gAnimateTextures = TRUE; 71BOOL gAnimateTextures = TRUE;
75extern BOOL gHideSelectedObjects; 72extern BOOL gHideSelectedObjects;
@@ -406,28 +403,30 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
406 return TRUE; 403 return TRUE;
407} 404}
408 405
409void LLVOVolume::updateTextures(LLAgent &agent) 406void LLVOVolume::updateTextures()
410{ 407{
411 const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds 408 const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
412 if (mDrawable.notNull() && mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME) 409 if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
413 { 410 {
414 if (mDrawable->isVisible()) 411 updateTextureVirtualSize();
415 {
416 updateTextures();
417 }
418 } 412 }
419} 413}
420 414
421void LLVOVolume::updateTextures() 415void LLVOVolume::updateTextureVirtualSize()
422{ 416{
423 // Update the pixel area of all faces 417 // Update the pixel area of all faces
424 418
419 if(mDrawable.isNull() || !mDrawable->isVisible())
420 {
421 return ;
422 }
423
425 if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) 424 if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
426 { 425 {
427 return; 426 return;
428 } 427 }
429 428
430 if (LLViewerImage::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible()) 429 if (LLViewerImage::sDontLoadVolumeTextures || LLAppViewer::getTextureFetch()->mDebugPause)
431 { 430 {
432 return; 431 return;
433 } 432 }
@@ -444,53 +443,51 @@ void LLVOVolume::updateTextures()
444 LLFace* face = mDrawable->getFace(i); 443 LLFace* face = mDrawable->getFace(i);
445 const LLTextureEntry *te = face->getTextureEntry(); 444 const LLTextureEntry *te = face->getTextureEntry();
446 LLViewerImage *imagep = face->getTexture(); 445 LLViewerImage *imagep = face->getTexture();
447 if (!imagep || !te || 446 if (!imagep || !te ||
448 face->mExtents[0] == face->mExtents[1]) 447 face->mExtents[0] == face->mExtents[1])
449 { 448 {
450 continue; 449 continue;
451 } 450 }
452 451
453 F32 vsize; 452 F32 vsize;
454 453 F32 old_size = face->getVirtualSize();
454
455 if (isHUDAttachment()) 455 if (isHUDAttachment())
456 { 456 {
457 F32 area = (F32) LLViewerCamera::getInstance()->getScreenPixelArea(); 457 F32 area = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
458 vsize = area; 458 vsize = area;
459 imagep->setBoostLevel(LLViewerImage::BOOST_HUD); 459 imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_HUD);
460 face->setPixelArea(area); // treat as full screen 460 face->setPixelArea(area); // treat as full screen
461 } 461 }
462 else 462 else
463 { 463 {
464 vsize = getTextureVirtualSize(face); 464 vsize = face->getTextureVirtualSize();
465 } 465 }
466 466
467 mPixelArea = llmax(mPixelArea, face->getPixelArea()); 467 mPixelArea = llmax(mPixelArea, face->getPixelArea());
468
469 F32 old_size = face->getVirtualSize();
470 468
471 if (face->mTextureMatrix != NULL) 469 if (face->mTextureMatrix != NULL)
472 { 470 {
473 if (vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE || 471 if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) ||
474 vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE) 472 (vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE))
475 { 473 {
476 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE); 474 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE);
477 } 475 }
478 } 476 }
479 477
480 face->setVirtualSize(vsize); 478 face->setVirtualSize(vsize);
481 imagep->addTextureStats(vsize);
482 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) 479 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
483 { 480 {
484 if (vsize < min_vsize) min_vsize = vsize; 481 if (vsize < min_vsize) min_vsize = vsize;
485 if (vsize > max_vsize) max_vsize = vsize; 482 if (vsize > max_vsize) max_vsize = vsize;
486 } 483 }
487 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) 484// else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
488 { 485// {
489 F32 pri = imagep->getDecodePriority(); 486// F32 pri = imagep->getDecodePriority();
490 pri = llmax(pri, 0.0f); 487// pri = llmax(pri, 0.0f);
491 if (pri < min_vsize) min_vsize = pri; 488// if (pri < min_vsize) min_vsize = pri;
492 if (pri > max_vsize) max_vsize = pri; 489// if (pri > max_vsize) max_vsize = pri;
493 } 490// }
494 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) 491 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
495 { 492 {
496 F32 pri = mPixelArea; 493 F32 pri = mPixelArea;
@@ -506,31 +503,44 @@ void LLVOVolume::updateTextures()
506 mSculptTexture = gImageList.getImage(id); 503 mSculptTexture = gImageList.getImage(id);
507 if (mSculptTexture.notNull()) 504 if (mSculptTexture.notNull())
508 { 505 {
509 S32 lod = llmin(mLOD, 3);
510 F32 lodf = ((F32)(lod + 1.0f)/4.f);
511 F32 tex_size = lodf * MAX_SCULPT_REZ;
512 mSculptTexture->addTextureStats(2.f * tex_size * tex_size);
513 mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), 506 mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
514 (S32)LLViewerImage::BOOST_SCULPTED)); 507 (S32)LLViewerImageBoostLevel::BOOST_SCULPTED));
515 } 508 mSculptTexture->setForSculpt() ;
516 509
517 S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture 510 if(!mSculptTexture->isCachedRawImageReady())
518 S32 current_discard = mSculptLevel; 511 {
512 S32 lod = llmin(mLOD, 3);
513 F32 lodf = ((F32)(lod + 1.0f)/4.f);
514 F32 tex_size = lodf * LLViewerImage::sMaxSculptRez ;
515 mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE);
516
517 //if the sculpty very close to the view point, load first
518 {
519 LLVector3 lookAt = getPositionAgent() - LLViewerCamera::getInstance()->getOrigin();
520 F32 dist = lookAt.normVec() ;
521 F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;
522 mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ;
523 }
524 }
525
526 S32 texture_discard = mSculptTexture->getCachedRawImageLevel(); //try to match the texture
527 S32 current_discard = mSculptLevel;
519 528
520 if (texture_discard >= 0 && //texture has some data available 529 if (texture_discard >= 0 && //texture has some data available
521 (texture_discard < current_discard || //texture has more data than last rebuild 530 (texture_discard < current_discard || //texture has more data than last rebuild
522 current_discard < 0)) //no previous rebuild 531 current_discard < 0)) //no previous rebuild
523 { 532 {
524 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); 533 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
525 mSculptChanged = TRUE; 534 mSculptChanged = TRUE;
526 } 535 }
527 536
528 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED)) 537 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
529 { 538 {
530 setDebugText(llformat("T%d C%d V%d\n%dx%d", 539 setDebugText(llformat("T%d C%d V%d\n%dx%d",
531 texture_discard, current_discard, getVolume()->getSculptLevel(), 540 texture_discard, current_discard, getVolume()->getSculptLevel(),
532 mSculptTexture->getHeight(), mSculptTexture->getWidth())); 541 mSculptTexture->getHeight(), mSculptTexture->getWidth()));
533 } 542 }
543 }
534 } 544 }
535 545
536 546
@@ -538,10 +548,10 @@ void LLVOVolume::updateTextures()
538 { 548 {
539 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); 549 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
540 } 550 }
541 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) 551// else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
542 { 552// {
543 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); 553// setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
544 } 554// }
545 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) 555 else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
546 { 556 {
547 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize))); 557 setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
@@ -553,36 +563,6 @@ void LLVOVolume::updateTextures()
553 } 563 }
554} 564}
555 565
556F32 LLVOVolume::getTextureVirtualSize(LLFace* face)
557{
558 //get area of circle around face
559 LLVector3 center = face->getPositionAgent();
560 LLVector3 size = (face->mExtents[1] - face->mExtents[0]) * 0.5f;
561
562 F32 face_area = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
563
564 face->setPixelArea(face_area);
565
566 if (face_area <= 0)
567 {
568 return 0.f;
569 }
570
571 //get area of circle in texture space
572 LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0];
573 F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f;
574 if (texel_area <= 0)
575 {
576 // Probably animated, use default
577 texel_area = 1.f;
578 }
579
580 //apply texel area to face area to get accurate ratio
581 face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
582
583 return face_area;
584}
585
586BOOL LLVOVolume::isActive() const 566BOOL LLVOVolume::isActive() const
587{ 567{
588 return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()); 568 return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
@@ -719,31 +699,21 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
719 699
720// sculpt replaces generate() for sculpted surfaces 700// sculpt replaces generate() for sculpted surfaces
721void LLVOVolume::sculpt() 701void LLVOVolume::sculpt()
722{ 702{
723 U16 sculpt_height = 0;
724 U16 sculpt_width = 0;
725 S8 sculpt_components = 0;
726 const U8* sculpt_data = NULL;
727
728 if (mSculptTexture.notNull()) 703 if (mSculptTexture.notNull())
729 { 704 {
730 S32 discard_level; 705 U16 sculpt_height = 0;
731 S32 desired_discard = 0; // lower discard levels have MUCH less resolution 706 U16 sculpt_width = 0;
732 707 S8 sculpt_components = 0;
733 discard_level = desired_discard; 708 const U8* sculpt_data = NULL;
709
710 S32 discard_level = mSculptTexture->getCachedRawImageLevel() ;
711 LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ;
734 712
735 S32 max_discard = mSculptTexture->getMaxDiscardLevel(); 713 S32 max_discard = mSculptTexture->getMaxDiscardLevel();
736 if (discard_level > max_discard) 714 if (discard_level > max_discard)
737 discard_level = max_discard; // clamp to the best we can do 715 discard_level = max_discard; // clamp to the best we can do
738 716
739 S32 best_discard = mSculptTexture->getDiscardLevel();
740 if (discard_level < best_discard)
741 discard_level = best_discard; // clamp to what we have
742
743 if (best_discard == -1)
744 discard_level = -1; // and if we have nothing, set to nothing
745
746
747 S32 current_discard = getVolume()->getSculptLevel(); 717 S32 current_discard = getVolume()->getSculptLevel();
748 if(current_discard < -2) 718 if(current_discard < -2)
749 { 719 {
@@ -765,28 +735,17 @@ void LLVOVolume::sculpt()
765 if (current_discard == discard_level) // no work to do here 735 if (current_discard == discard_level) // no work to do here
766 return; 736 return;
767 737
768 LLPointer<LLImageRaw> raw_image = new LLImageRaw(); 738 if(!raw_image)
769 BOOL is_valid = mSculptTexture->readBackRaw(discard_level, raw_image, FALSE);
770
771 sculpt_height = raw_image->getHeight();
772 sculpt_width = raw_image->getWidth();
773 sculpt_components = raw_image->getComponents();
774
775 if(is_valid)
776 {
777 is_valid = mSculptTexture->isValidForSculpt(discard_level, sculpt_width, sculpt_height, sculpt_components) ;
778 }
779 if(!is_valid)
780 { 739 {
781 sculpt_width = 0; 740 sculpt_width = 0;
782 sculpt_height = 0; 741 sculpt_height = 0;
783 sculpt_data = NULL ; 742 sculpt_data = NULL ;
784 } 743 }
785 else 744 else
786 { 745 {
787 if (raw_image->getDataSize() < sculpt_height * sculpt_width * sculpt_components) 746 sculpt_height = raw_image->getHeight();
788 llerrs << "Sculpt: image data size = " << raw_image->getDataSize() 747 sculpt_width = raw_image->getWidth();
789 << " < " << sculpt_height << " x " << sculpt_width << " x " <<sculpt_components << llendl; 748 sculpt_components = raw_image->getComponents();
790 749
791 sculpt_data = raw_image->getData(); 750 sculpt_data = raw_image->getData();
792 } 751 }
@@ -818,7 +777,7 @@ BOOL LLVOVolume::calcLOD()
818 } 777 }
819 778
820 //update face texture sizes on lod calculation 779 //update face texture sizes on lod calculation
821 updateTextures(); 780 updateTextureVirtualSize();
822 781
823 S32 cur_detail = 0; 782 S32 cur_detail = 0;
824 783
@@ -2295,7 +2254,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
2295 2254
2296 LLVOVolume* vobj = drawablep->getVOVolume(); 2255 LLVOVolume* vobj = drawablep->getVOVolume();
2297 llassert_always(vobj); 2256 llassert_always(vobj);
2298 vobj->updateTextures(); 2257 vobj->updateTextureVirtualSize();
2299 vobj->preRebuild(); 2258 vobj->preRebuild();
2300 2259
2301 //for each face 2260 //for each face
@@ -2399,7 +2358,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
2399 { //needs normal + binormal 2358 { //needs normal + binormal
2400 bump_faces.push_back(facep); 2359 bump_faces.push_back(facep);
2401 } 2360 }
2402 else if (te->getShiny() && LLPipeline::sRenderBump || 2361 else if ((te->getShiny() && LLPipeline::sRenderBump) ||
2403 !te->getFullbright()) 2362 !te->getFullbright())
2404 { //needs normal 2363 { //needs normal
2405 simple_faces.push_back(facep); 2364 simple_faces.push_back(facep);
diff --git a/linden/indra/newview/llvovolume.h b/linden/indra/newview/llvovolume.h
index 9b4e715..960f6da 100644
--- a/linden/indra/newview/llvovolume.h
+++ b/linden/indra/newview/llvovolume.h
@@ -130,7 +130,7 @@ public:
130 130
131 131
132 BOOL getVolumeChanged() const { return mVolumeChanged; } 132 BOOL getVolumeChanged() const { return mVolumeChanged; }
133 F32 getTextureVirtualSize(LLFace* face); 133
134 /*virtual*/ F32 getRadius() const { return mVObjRadius; }; 134 /*virtual*/ F32 getRadius() const { return mVObjRadius; };
135 const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; 135 const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
136 136
@@ -177,8 +177,8 @@ public:
177 /*virtual*/ void updateFaceSize(S32 idx); 177 /*virtual*/ void updateFaceSize(S32 idx);
178 /*virtual*/ BOOL updateLOD(); 178 /*virtual*/ BOOL updateLOD();
179 void updateRadius(); 179 void updateRadius();
180 /*virtual*/ void updateTextures(LLAgent &agent); 180 /*virtual*/ void updateTextures();
181 void updateTextures(); 181 void updateTextureVirtualSize();
182 182
183 void updateFaceFlags(); 183 void updateFaceFlags();
184 void regenFaces(); 184 void regenFaces();
diff --git a/linden/indra/newview/llvowater.cpp b/linden/indra/newview/llvowater.cpp
index d23c746..5b6a949 100644
--- a/linden/indra/newview/llvowater.cpp
+++ b/linden/indra/newview/llvowater.cpp
@@ -101,7 +101,7 @@ void LLVOWater::setPixelAreaAndAngle(LLAgent &agent)
101 101
102 102
103// virtual 103// virtual
104void LLVOWater::updateTextures(LLAgent &agent) 104void LLVOWater::updateTextures()
105{ 105{
106} 106}
107 107
diff --git a/linden/indra/newview/llvowater.h b/linden/indra/newview/llvowater.h
index cdda48f..9c33e74 100644
--- a/linden/indra/newview/llvowater.h
+++ b/linden/indra/newview/llvowater.h
@@ -68,7 +68,7 @@ public:
68 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); 68 /*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
69 /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax); 69 /*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
70 70
71 /*virtual*/ void updateTextures(LLAgent &agent); 71 /*virtual*/ void updateTextures();
72 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area 72 /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
73 73
74 virtual U32 getPartitionType() const; 74 virtual U32 getPartitionType() const;
diff --git a/linden/indra/newview/llworldmapview.cpp b/linden/indra/newview/llworldmapview.cpp
index 64e84c5..c10faa5 100644
--- a/linden/indra/newview/llworldmapview.cpp
+++ b/linden/indra/newview/llworldmapview.cpp
@@ -378,7 +378,7 @@ void LLWorldMapView::draw()
378 continue; 378 continue;
379 } 379 }
380 380
381 current_image->setBoostLevel(LLViewerImage::BOOST_MAP_LAYER); 381 current_image->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP_VISIBLE);
382 current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY])); 382 current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY]));
383 383
384 if (!current_image->getHasGLTexture()) 384 if (!current_image->getHasGLTexture())
@@ -557,13 +557,13 @@ void LLWorldMapView::draw()
557 S32 draw_size = llround(gMapScale); 557 S32 draw_size = llround(gMapScale);
558 if (simimage != NULL) 558 if (simimage != NULL)
559 { 559 {
560 simimage->setBoostLevel(LLViewerImage::BOOST_MAP); 560 simimage->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP);
561 simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); 561 simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
562 } 562 }
563 563
564 if (overlayimage != NULL) 564 if (overlayimage != NULL)
565 { 565 {
566 overlayimage->setBoostLevel(LLViewerImage::BOOST_MAP); 566 overlayimage->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP);
567 overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); 567 overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
568 } 568 }
569 569
diff --git a/linden/indra/newview/primbackup.cpp b/linden/indra/newview/primbackup.cpp
index 4f93ddf..a9a8af7 100644
--- a/linden/indra/newview/primbackup.cpp
+++ b/linden/indra/newview/primbackup.cpp
@@ -590,8 +590,8 @@ void primbackup::export_next_texture()
590 S32 cur_discard = imagep->getDiscardLevel(); 590 S32 cur_discard = imagep->getDiscardLevel();
591 if(cur_discard>0) 591 if(cur_discard>0)
592 { 592 {
593 if(imagep->getBoostLevel()!=LLViewerImage::BOOST_PREVIEW) 593 if(imagep->getBoostLevel()!=LLViewerImageBoostLevel::BOOST_PREVIEW)
594 imagep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); //we want to force discard 0 this one does this. 594 imagep->setBoostLevel(LLViewerImageBoostLevel::BOOST_PREVIEW); //we want to force discard 0 this one does this.
595 } 595 }
596 else 596 else
597 { 597 {