aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerimage.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerimage.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llviewerimage.cpp2045
1 files changed, 2045 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerimage.cpp b/linden/indra/newview/llviewerimage.cpp
new file mode 100644
index 0000000..ad1604e
--- /dev/null
+++ b/linden/indra/newview/llviewerimage.cpp
@@ -0,0 +1,2045 @@
1/**
2 * @file llviewerimage.cpp
3 * @brief Object which handles a received image (and associated texture(s))
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llviewerimage.h"
31
32// Library includes
33#include "imageids.h"
34#include "llmath.h"
35#include "llerror.h"
36#include "llgl.h"
37#include "llhost.h"
38#include "llimage.h"
39#include "llimagebmp.h"
40#include "llimagej2c.h"
41#include "llimagetga.h"
42#include "llstl.h"
43#include "lltexturetable.h"
44#include "llvfile.h"
45#include "llvfs.h"
46#include "message.h"
47#include "lltimer.h"
48//#include "vmath.h" // For frand
49
50// viewer includes
51#include "llviewerimagelist.h"
52#include "llviewercontrol.h"
53#include "viewer.h"
54#include "llglheaders.h"
55#include "pipeline.h"
56#include "lldrawpool.h"
57
58const S32 IMAGE_HEADER_SIZE = 27;
59const S32 PACKET_HEADER_SIZE = 4;
60
61///////////////////////////////////////////////////////////////////////////////
62
63class LLViewerImagePacket
64{
65public:
66 LLViewerImagePacket(U8 *data, U16 data_size, U16 packet_num, BOOL wrote_to_disk)
67 {
68 mData = data;
69 mDataSize = data_size;
70 mPacketNum = packet_num;
71 mWroteToDisk = wrote_to_disk;
72 }
73
74 ~LLViewerImagePacket()
75 {
76 delete[] mData;
77 }
78
79public:
80 U8 *mData;
81 U16 mDataSize;
82 U16 mPacketNum;
83 BOOL mWroteToDisk;
84};
85
86
87///////////////////////////////////////////////////////////////////////////////
88
89// statics
90LLPointer<LLViewerImage> LLViewerImage::sMissingAssetImagep = NULL;
91LLPointer<LLViewerImage> LLViewerImage::sWhiteImagep = NULL;
92LLPointer<LLImageGL> LLViewerImage::sDefaultImagep = NULL;
93LLPointer<LLViewerImage> LLViewerImage::sSmokeImagep = NULL;
94LLPointer<LLImageGL> LLViewerImage::sNullImagep = NULL;
95
96S32 LLViewerImage::sImageCount = 0;
97LLTimer LLViewerImage::sEvaluationTimer;
98F32 LLViewerImage::sDesiredDiscardBias = 0.f;
99F32 LLViewerImage::sDesiredDiscardScale = 1.1f;
100S32 LLViewerImage::sBoundTextureMemory = 0;
101S32 LLViewerImage::sTotalTextureMemory = 0;
102S32 LLViewerImage::sMaxBoundTextureMem = 0;
103S32 LLViewerImage::sMaxTotalTextureMem = 0;
104BOOL LLViewerImage::sDontLoadVolumeTextures = FALSE;
105
106// static
107void LLViewerImage::initClass()
108{
109 sNullImagep = new LLImageGL(1,1,3,TRUE);
110 LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,3);
111 raw->clear(0x77, 0x77, 0x77, 0xFF);
112 sNullImagep->createGLTexture(0, raw);
113}
114
115// static
116void LLViewerImage::cleanupClass()
117{
118 stop_glerror();
119 sNullImagep = NULL;
120 sDefaultImagep = NULL;
121 sSmokeImagep = NULL;
122 sMissingAssetImagep = NULL;
123 sWhiteImagep = NULL;
124}
125
126// tuning params
127const F32 discard_bias_delta = .05f;
128const F32 discard_delta_time = 0.5f;
129const S32 min_non_tex_system_mem = (128<<20); // 128 MB
130// non-const (used externally
131F32 texmem_lower_bound_scale = 0.85f;
132F32 texmem_middle_bound_scale = 0.925f;
133
134//static
135void LLViewerImage::updateClass(const F32 velocity, const F32 angular_velocity)
136{
137 sBoundTextureMemory = LLImageGL::sBoundTextureMemory;
138 sTotalTextureMemory = LLImageGL::sGlobalTextureMemory;
139 sMaxBoundTextureMem = gImageList.getMaxResidentTexMem();
140
141 sMaxTotalTextureMem = sMaxBoundTextureMem * 2;
142 if (sMaxBoundTextureMem > 64000000)
143 {
144 sMaxTotalTextureMem -= sMaxBoundTextureMem/4;
145 }
146
147 if (sMaxTotalTextureMem > (S32)gSysMemory.getPhysicalMemory() - min_non_tex_system_mem)
148 {
149 sMaxTotalTextureMem = (S32)gSysMemory.getPhysicalMemory() - min_non_tex_system_mem;
150 }
151
152 if (sBoundTextureMemory >= sMaxBoundTextureMem ||
153 sTotalTextureMemory >= sMaxTotalTextureMem)
154 {
155 // If we are using more texture memory than we should,
156 // scale up the desired discard level
157 if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time)
158 {
159 sDesiredDiscardBias += discard_bias_delta;
160 sEvaluationTimer.reset();
161 }
162 }
163 else if (sDesiredDiscardBias > 0.0f &&
164 sBoundTextureMemory < sMaxBoundTextureMem*texmem_lower_bound_scale &&
165 sTotalTextureMemory < sMaxTotalTextureMem*texmem_lower_bound_scale)
166 {
167 // If we are using less texture memory than we should,
168 // scale down the desired discard level
169 if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time)
170 {
171 sDesiredDiscardBias -= discard_bias_delta;
172 sEvaluationTimer.reset();
173 }
174 }
175}
176
177//----------------------------------------------------------------------------
178
179const U32 LLViewerImage::sCurrentFileVersion = 1;
180
181LLViewerImage::LLViewerImage(const LLUUID& id, BOOL usemipmaps)
182 : LLImageGL(usemipmaps),
183 mID(id)
184{
185 init(true);
186 sImageCount++;
187}
188
189LLViewerImage::LLViewerImage(const U32 width, const U32 height, const U8 components, BOOL usemipmaps)
190 : LLImageGL(width, height, components, usemipmaps)
191{
192 init(true);
193 mNeedsAux = FALSE;
194 // Create an empty image of the specified size and width
195 mID.generate();
196 mFullyLoaded = TRUE;
197 sImageCount++;
198}
199
200LLViewerImage::LLViewerImage(const LLImageRaw* raw, BOOL usemipmaps)
201 : LLImageGL(raw, usemipmaps)
202{
203 init(true);
204 mNeedsAux = FALSE;
205 // Create an empty image of the specified size and width
206 mID.generate();
207 mFullyLoaded = TRUE;
208 sImageCount++;
209}
210
211void LLViewerImage::init(bool firstinit)
212{
213 mDataCodec = 0;
214 mFullWidth = 0;
215 mFullHeight = 0;
216 mFormattedImagep = NULL;
217 mNeedsAux = FALSE;
218 mRequested = FALSE;
219 mNeedsDecode = FALSE;
220 mTexelsPerImage = 64.f*64.f;
221 mMaxVirtualSize = 0.f;
222 mMaxCosAngle = -1.f;
223 mRequestedDiscardLevel = -1;
224 mRequestedDownloadPriority = 0.f;
225 mPackets = 0;
226 mGotFirstPacket = FALSE;
227 mPacketsReceived = 0;
228 mFullyLoaded = FALSE;
229 mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
230 mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
231 mStreamFile = NULL;
232 mCachedData = NULL;
233 mCachedSize = 0;
234 mFormattedFlushed = FALSE;
235 mTotalBytes = 0;
236
237 resetPacketData();
238
239 mLastPacketProcessed = -1;
240 mLastBytesProcessed = 0;
241 mLastPacket = -1;
242 mDecodingAux = FALSE;
243
244 mKnownDrawWidth = 0;
245 mKnownDrawHeight = 0;
246
247 if (firstinit)
248 {
249 mDecodePriority = 0.f;
250 mInImageList = 0;
251 mInStaticVFS = FALSE;
252 }
253 mIsMediaTexture = FALSE;
254
255 mBoostLevel = LLViewerImage::BOOST_NONE;
256
257 // Only set mIsMissingAsset true when we know for certain that the database
258 // does not contain this image.
259 mIsMissingAsset = FALSE;
260
261 mNeedsCreateTexture = FALSE;
262
263 mIsRawImageValid = FALSE;
264 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
265 mRawImage = NULL;
266
267 mTargetHost = LLHost::invalid;
268}
269
270// virtual
271void LLViewerImage::dump()
272{
273 LLImageGL::dump();
274
275 llinfos << "LLViewerImage"
276 << " mID " << mID
277 << " mIsMissingAsset " << (S32)mIsMissingAsset
278 << " mFullWidth " << mFullWidth
279 << " mFullHeight " << mFullHeight
280 << llendl;
281}
282
283///////////////////////////////////////////////////////////////////////////////
284
285LLViewerImage::~LLViewerImage()
286{
287 // Explicitly call LLViewerImage::cleanup since we're in a destructor and cleanup is virtual
288 LLViewerImage::cleanup();
289 sImageCount--;
290}
291
292
293///////////////////////////////////////////////////////////////////////////////
294
295void LLViewerImage::cleanup()
296{
297 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
298 iter != mLoadedCallbackList.end(); )
299 {
300 LLLoadedCallbackEntry *entryp = *iter++;
301 // We never finished loading the image. Indicate failure.
302 // Note: this allows mLoadedCallbackUserData to be cleaned up.
303 entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData );
304 delete entryp;
305 }
306 mLoadedCallbackList.clear();
307
308 // Clean up any remaining packet data.
309 std::for_each(mReceivedPacketMap.begin(), mReceivedPacketMap.end(), DeletePairedPointer());
310 mReceivedPacketMap.clear();
311
312 // Clean up the streaming file
313 if (mStreamFile && !mStreamFile->isReadComplete())
314 {
315// llwarns << "Destroying LLViewerImage stream file while still reading data!" << llendl;
316 }
317 delete mStreamFile;
318 mStreamFile = NULL;
319
320 // Clean up image data
321 setFormattedImage(NULL);
322 mRawImage = NULL;
323 mIsRawImageValid = FALSE;
324 mAuxRawImage = NULL;
325
326 delete[] mCachedData;
327 mCachedData = NULL;
328
329 // LLImageGL::cleanup will get called more than once when this is used in the destructor.
330 LLImageGL::cleanup();
331}
332
333void LLViewerImage::reinit(BOOL usemipmaps /* = TRUE */)
334{
335 LLViewerImage::cleanup();
336 LLImageGL::init(usemipmaps);
337 init(false);
338 setSize(0,0,0);
339 if (mInStaticVFS)
340 {
341 mFormattedFlushed = TRUE;
342 }
343}
344
345///////////////////////////////////////////////////////////////////////////////
346
347void LLViewerImage::setFormattedImage(LLImageFormatted* imagep)
348{
349 mFormattedImagep = NULL; // deletes image
350 mFormattedImagep = imagep;
351 if (mFormattedImagep.notNull())
352 {
353 mFormattedImagep->mMemType = LLMemType::MTYPE_APPFMTIMAGE;
354 mFormattedFlushed = FALSE;
355 }
356 else
357 {
358 setNeedsDecode(FALSE);
359 }
360}
361
362BOOL LLViewerImage::loadLocalImage(const LLUUID &image_id)
363{
364 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
365
366 // first look for this image in the static VFS
367 LLAssetType::EType asset_type = LLAssetType::AT_NONE;
368 // Try TGA first
369 if (gStaticVFS->getExists(image_id, LLAssetType::AT_TEXTURE_TGA))
370 {
371 asset_type = LLAssetType::AT_TEXTURE_TGA;
372 //RN: force disable discards for TGA files because they can't decode at different quality levels
373 dontDiscard();
374 mDataCodec = IMG_CODEC_TGA;
375 }
376 else if (gStaticVFS->getExists(image_id, LLAssetType::AT_TEXTURE))
377 {
378 // then try for a J2C version
379 asset_type = LLAssetType::AT_TEXTURE;
380 mDataCodec = IMG_CODEC_J2C;
381 LLImageJ2C* imagej2c = new LLImageJ2C();
382 setFormattedImage(imagej2c);
383 }
384
385 if (asset_type != LLAssetType::AT_NONE)
386 {
387 S32 size = gStaticVFS->getSize(image_id, asset_type);
388 U8* buffer = new U8[size];
389 BOOL success = LLVFSThread::sLocal->readImmediate(gStaticVFS, image_id, asset_type, buffer, 0, size);
390
391 if (!success)
392 {
393 llwarns << "loadLocalImage() - vfs read failed" << llendl;
394 return FALSE;
395 }
396
397 mInStaticVFS = TRUE;
398 mFullyLoaded = TRUE;
399 setNeedsDecode(TRUE); // Loading a local image
400 mID = image_id;
401 setDecodeData(buffer, size);
402 mTotalBytes = size;
403 mLastBytesProcessed = size;
404 return TRUE;
405 }
406
407 return FALSE;
408}
409
410BOOL LLViewerImage::startVFSLoad()
411{
412 // We're no longer considered "flushed" no matter what happens after here.
413 mFormattedFlushed = FALSE;
414 if (!mStreamFile && mFormattedImagep.isNull())
415 {
416 // Start load from VFS if it's there
417 if (gVFS->getExists(mID, LLAssetType::AT_TEXTURE))
418 {
419// llinfos << "Reading image from disk " << getID() << llendl;
420
421 //llinfos << mID << ": starting VFS load" << llendl;
422 mStreamFile = new LLVFile(gVFS, mID, LLAssetType::AT_TEXTURE, LLVFile::READ_WRITE);
423 mCachedSize = 0;
424 gImageList.mLoadingStreamList.push_back(this);
425 }
426 else
427 {
428 return loadLocalImage(mID);
429 }
430 }
431 return TRUE;
432}
433
434void LLViewerImage::startImageDecode()
435{
436 // We need to load and/or decode the image
437 if (mFormattedImagep.isNull())
438 {
439 startVFSLoad(); // Start the VFS loading
440 }
441 else
442 {
443 setNeedsDecode(TRUE); // Force a new decode of this texture
444 }
445}
446
447
448BOOL LLViewerImage::createTexture(S32 usename/*= 0*/)
449{
450 if (mFormattedImagep.notNull() && mFormattedImagep->isDecoding())
451 {
452 llerrs << "Trying to create texture on an image that is currently being decoded: " << mID << llendl;
453 }
454 mNeedsCreateTexture = FALSE;
455 if (mRawImage.isNull())
456 {
457 llerrs << "LLViewerImage trying to create texture with no Raw Image" << llendl;
458 }
459// llinfos << llformat("IMAGE Creating (%d,%d) [%d x %d] Bytes: %d ",
460// mRawDiscardLevel, mFormattedImagep ? mFormattedImagep->getDiscardLevel() : -1,
461// mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize())
462// << mID.getString() << llendl;
463 BOOL res = TRUE;
464 if (!gNoRender)
465 {
466 if (LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
467 {
468 res = LLImageGL::createGLTexture(mRawDiscardLevel, mRawImage, usename);
469 }
470 else
471 {
472 // A non power-of-two image was uploaded (through a non standard client)
473 // We treat these images as missing assets which causes them to
474 // be renderd as 'missing image' and to stop requesting data
475 setIsMissingAsset(TRUE);
476 destroyRawImage();
477 return FALSE;
478 }
479 }
480
481 //
482 // Iterate through the list of image loading callbacks to see
483 // what sort of data they need.
484 //
485 BOOL imageraw_callbacks = FALSE;
486 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
487 iter != mLoadedCallbackList.end(); )
488 {
489 LLLoadedCallbackEntry *entryp = *iter++;
490 if (entryp->mNeedsImageRaw)
491 {
492 imageraw_callbacks = TRUE;
493 break;
494 }
495 }
496
497 if (!imageraw_callbacks)
498 {
499 destroyRawImage();
500 }
501 return res;
502}
503
504BOOL LLViewerImage::destroyTexture()
505{
506 LLImageGL::destroyGLTexture();
507 return TRUE;
508}
509
510void LLViewerImage::resetPacketData()
511{
512 //llinfos << "resetting packet data for " << getID() << llendl;
513 mPackets = 0;
514 mLastPacket = -1;
515 mPacketsReceived = 0;
516 mGotFirstPacket = FALSE;
517 mRequested = FALSE;
518
519 std::for_each(mReceivedPacketMap.begin(), mReceivedPacketMap.end(), DeletePairedPointer());
520 mReceivedPacketMap.clear();
521 mLastPacketProcessed = -1;
522}
523
524////////////////////////////////////////////////////////////////////////////////
525// This sets up a new formatted image at the requested size, and sets the decode flag
526void LLViewerImage::setDecodeData(U8 * data, U32 size)
527{
528 if (size == mTotalBytes)
529 {
530 mFullyLoaded = TRUE;
531 }
532 if (mDataCodec == IMG_CODEC_J2C)
533 {
534 //Codec 2 = compressed with JPEG2000 (Wavelet)
535 // Create formatted image first, then use it to generate the
536 // raw image.
537 if (mFormattedImagep.isNull())
538 {
539 LLPointer<LLImageJ2C> j2cp = new LLImageJ2C();
540 setFormattedImage(j2cp);
541 }
542 BOOL res = mFormattedImagep->setData(data, size);
543 if (mFullyLoaded)
544 {
545 mFormattedImagep->setDiscardLevel(0); // Force full res if all data is loaded
546 }
547 if ((mFormattedImagep->getWidth() > MAX_IMAGE_SIZE_DEFAULT ||
548 mFormattedImagep->getHeight() > MAX_IMAGE_SIZE_DEFAULT) &&
549 (mFormattedImagep->getDiscardLevel() == 0))
550 {
551 mFormattedImagep->setDiscardLevel(1); // Force x2048 images to x1024
552 }
553
554 if( res )
555 {
556 if (mFormattedImagep->getComponents() > 4)
557 {
558 mNeedsAux = TRUE;
559 }
560 else
561 {
562 mNeedsAux = FALSE;
563 }
564 mFullWidth = mFormattedImagep->getWidth();
565 mFullHeight = mFormattedImagep->getHeight();
566 if ((mFullWidth == 0) || (mFullHeight == 0))
567 {
568 llwarns << "Zero size width/height!" << llendl;
569 }
570 setNeedsDecode(TRUE); // Setting new formatted data
571 }
572 else
573 {
574 llwarns << "Unable to setData() for image " << mID << " Aborting." << llendl;
575 abortDecode();
576 }
577 }
578 else if (mDataCodec == IMG_CODEC_TGA)
579 {
580 //Codec 4 = compressed with TGA
581 // Create formatted image first, then use it to generate the
582 // raw image.
583 if (mFormattedImagep.isNull())
584 {
585 LLPointer<LLImageTGA> tgap = new LLImageTGA();
586 setFormattedImage(tgap);
587 }
588 BOOL res = mFormattedImagep->setData(data, size);
589
590 if( res )
591 {
592 mFullWidth = mFormattedImagep->getWidth();
593 mFullHeight = mFormattedImagep->getHeight();
594 if ((mFullWidth == 0) || (mFullHeight == 0))
595 {
596 llwarns << "Zero size width/height!" << llendl;
597 }
598 setNeedsDecode(TRUE); // Setting new formatted data
599 }
600 else
601 {
602 llwarns << "Unable to setData() for image " << mID << " Aborting." << llendl;
603 abortDecode();
604 }
605 }
606 else
607 {
608 llerrs << "Image " << mID << ": Unknown codec " << (int)mDataCodec << llendl;
609 setNeedsDecode(FALSE); // Unknown codec
610 }
611}
612
613void LLViewerImage::decodeImage(const F32 decode_time)
614{
615 if (!needsDecode())
616 {
617 return;
618 }
619
620 if (mFormattedImagep.isNull())
621 {
622 llerrs << "Decoding image without formatted data!" << llendl;
623 return;
624 }
625
626 //
627 // Only do a decode if we don't already have an image for this resolution.
628 //
629 if (getTexName() != 0 && getDiscardLevel() <= mFormattedImagep->getDiscardLevel()
630 && !mNeedsAux)
631 {
632 // We already have an image this size or larger
633 setNeedsDecode(FALSE);
634 return;
635 }
636
637 // Partial Decode of J2C images:
638 // If this is the first time we are decoding an image,
639 // make sure we limit the amount of data we decode in order not to stall other decodes
640 if (!mFormattedImagep->isDecoding() && mFormattedImagep->getCodec() == IMG_CODEC_J2C)
641 {
642 LLImageJ2C* j2cp = (LLImageJ2C*)((LLImageFormatted*)mFormattedImagep);
643 const S32 INITIAL_DECODE_SIZE = 2048;
644 if (!mDontDiscard &&
645 getUseMipMaps() &&
646 !mNeedsAux &&
647 getDiscardLevel() < 0 &&
648 mFormattedImagep->getDataSize() > INITIAL_DECODE_SIZE * 2)
649 {
650 j2cp->setMaxBytes(INITIAL_DECODE_SIZE);
651 }
652 else
653 {
654 j2cp->setMaxBytes(0); // In case we set it on a previous decode
655 }
656 }
657
658 //
659 // Decode Image
660 //
661 mLastDecodeTime.reset();
662
663 if (mFormattedImagep->getCodec() == 0)
664 {
665 llerrs << "LLViewerImage::decodeImage: mFormattedImagep->getCodec() == 0" << llendl;
666 }
667
668 //
669 // Decode first 4 channels
670 //
671 // Skip over this if we're already in the process of decoding the aux channel,
672 // that means that we've alredy decoded the base channels of this texture.
673 if (!mDecodingAux)
674 {
675 if (!mFormattedImagep->isDecoding())
676 {
677 mNeedsCreateTexture = FALSE; // Raw is no longer valid
678 destroyRawImage();
679 createRawImage(mFormattedImagep->getDiscardLevel());
680 //llinfos << "starting decode at " << (S32)mFormattedImagep->getDiscardLevel() << " for " << getID() << llendl;
681 }
682 else
683 {
684 llassert(mRawImage.notNull());
685 }
686 if (!mFormattedImagep->decode(mRawImage, decode_time, 0, 4))
687 {
688 if (!mFormattedImagep->isDecoding())
689 {
690 // bogus data, delete and try again
691 llwarns << "Failed to decode " << mID << ":" << gTextureTable.getName(mID) << llendl;
692 abortDecode();
693 destroyRawImage();
694 return;
695 }
696 }
697// llinfos << llformat("IMAGE Decode (%d) ", mFormattedImagep->getDiscardLevel()) << mID << llendl;
698
699 // Get the discard level of the decoded raw image,
700 // which may not match the formatted image discard level if a partial decode was done
701 mRawDiscardLevel = mFormattedImagep->getRawDiscardLevel();
702
703 if (mFormattedImagep->isDecoding())
704 {
705 return; // Not done decoding.
706 }
707 }
708
709 //
710 // If we've finished with the main channels and need to decode the aux, do it now.
711 // Aux buffers contain extra data (e.g. cloth maps)
712 //
713 if (mNeedsAux)
714 {
715 mDecodingAux = TRUE;
716
717 // Create the target raw image for the aux channels
718 if (mAuxRawImage.isNull())
719 {
720 S32 discard = mFormattedImagep->getDiscardLevel();
721 mAuxRawImage = new LLImageRaw(getWidth(discard), getHeight(discard), 1);
722 mAuxRawImage->mMemType = LLMemType::MTYPE_APPAUXRAWIMAGE;
723 }
724
725 if (!mFormattedImagep->decode(mAuxRawImage, decode_time, 4, 4))
726 {
727 if (!mFormattedImagep->isDecoding())
728 {
729 llwarns << "Failed to decode high components " << mID << ":" << gTextureTable.getName(mID) << llendl;
730 abortDecode();
731 destroyRawImage();
732 return; // decode failed; re-request
733 }
734 }
735
736 if (mFormattedImagep->isDecoding())
737 {
738 return; // Not done decoding.
739 }
740
741 mDecodingAux = FALSE;
742 }
743
744 if (mRawImage.notNull() && getComponents() != mRawImage->getComponents())
745 {
746 //
747 // We've changed the number of components (presumably this is after
748 // decoding the first packet of an image), so we need to move any
749 // objects using this pool to a different pool.
750 //
751 mComponents = mRawImage->getComponents();
752 gPipeline.dirtyPoolObjectTextures(this);
753 }
754
755 //
756 // We've decoded this image, and no longer need to.
757 //
758 setNeedsDecode(FALSE); // Done decoding image
759 mIsRawImageValid = TRUE;
760
761 //
762 // We have a raw image, and now we need to push the data
763 // from the raw image into the GL image
764 //
765 llassert(mRawImage.notNull());
766 mNeedsCreateTexture = TRUE;
767
768 // Everything's OK...
769#if LL_DEBUG
770 lldebugst(LLERR_IMAGE) << "Img: ";
771 std::string tex_name = gTextureTable.getName(mID);
772 if (!tex_name.empty())
773 {
774 llcont << tex_name;
775 }
776 else
777 {
778 llcont << mID;
779 }
780 llcont << " Discard level " << (S32)getDiscardLevel();
781 llcont << llendl;
782#endif
783}
784
785bool LLViewerImage::isDecoding()
786{
787 return (mFormattedImagep.notNull() && mFormattedImagep->isDecoding());
788}
789
790//============================================================================
791
792void LLViewerImage::addTextureStats(F32 pixel_area,
793 F32 texel_area_ratio, // = 1.0
794 F32 cos_center_angle) const // = 1.0
795{
796 F32 virtual_size = pixel_area / texel_area_ratio;
797 if (virtual_size > mMaxVirtualSize)
798 {
799 mMaxVirtualSize = virtual_size;
800 }
801 cos_center_angle = llclamp(cos_center_angle, -1.f, 1.f);
802 if (cos_center_angle > mMaxCosAngle)
803 {
804 mMaxCosAngle = cos_center_angle;
805 }
806}
807
808void LLViewerImage::resetTextureStats(BOOL zero)
809{
810 if (zero)
811 {
812 mMaxVirtualSize = 0.0f;
813 mMaxCosAngle = -1.0f;
814 }
815 else
816 {
817 mMaxVirtualSize -= mMaxVirtualSize * .10f; // decay by 5%/update
818 mMaxCosAngle = -1.0f;
819 }
820}
821
822// This is gauranteed to get called periodically for every texture
823void LLViewerImage::processTextureStats()
824{
825 // Generate the request priority and render priority
826 if (mDontDiscard || !getUseMipMaps())
827 {
828 mDesiredDiscardLevel = 0;
829 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
830 mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
831 }
832 else if (mBoostLevel < LLViewerImage::BOOST_HIGH && mMaxVirtualSize <= 10.f)
833 {
834 // If the image has not been significantly visible in a while, we don't want it
835 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1));
836 }
837 else if ((!mFullWidth && !mWidth) || (!mFullHeight && !mHeight))
838 {
839 mDesiredDiscardLevel = mMaxDiscardLevel;
840 }
841 else
842 {
843 //static const F64 log_2 = log(2.0);
844 static const F64 log_4 = log(4.0);
845
846 S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT);
847 S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT);
848 mTexelsPerImage = (F32)fullwidth * fullheight;
849
850 F32 discard_level = 0.f;
851
852 // If we know the output width and height, we can force the discard
853 // level to the correct value, and thus not decode more texture
854 // data than we need to.
855 if (mBoostLevel == LLViewerImage::BOOST_UI ||
856 mBoostLevel == LLViewerImage::BOOST_PREVIEW ||
857 mBoostLevel == LLViewerImage::BOOST_AVATAR_SELF) // JAMESDEBUG what about AVATAR_BAKED_SELF?
858 {
859 discard_level = 0; // full res
860 }
861 else if (mKnownDrawWidth && mKnownDrawHeight)
862 {
863 S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight;
864
865 // Use log_4 because we're in square-pixel space, so an image
866 // with twice the width and twice the height will have mTexelsPerImage
867 // 4 * draw_size
868 discard_level = (F32)(log(mTexelsPerImage/draw_texels) / log_4);
869 }
870 else
871 {
872 // Guess the required scale factor of the image using pixels per texel..
873 // Right now, use a safe 1:1 for the tradeoff - we can adjust this later.
874 // Actually, it might be nice to generate a float, so we can prioritize which
875 // ones we can discard quality levels from.
876 discard_level = (F32)(log(mTexelsPerImage/mMaxVirtualSize) / log_4);
877 }
878 if (mBoostLevel < LLViewerImage::BOOST_HIGH)
879 {
880 static const F32 discard_bias = 0.5f; // Must be < 1 or highest discard will never load!
881 discard_level += discard_bias;
882 discard_level += sDesiredDiscardBias;
883 discard_level *= sDesiredDiscardScale; // scale
884 }
885 discard_level = floorf(discard_level);
886// discard_level -= (gImageList.mVideoMemorySetting>>1); // more video ram = higher detail
887
888 F32 min_discard = 0.f;
889 if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
890 min_discard = 1.f; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
891
892 discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL);
893
894 // Can't go higher than the max discard level
895 mDesiredDiscardLevel = llmin((S32)mMaxDiscardLevel+1, (S32)discard_level);
896 // Clamp to min desired discard
897 mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel);
898
899 //
900 // At this point we've calculated the quality level that we want,
901 // if possible. Now we check to see if we have it, and take the
902 // proper action if we don't.
903 //
904
905 //
906 // Only need to do an actual decode if we don't have the right GL level,
907 // or we don't have raw data and need raw data.
908 //
909 BOOL increase_discard = FALSE;
910 if (getDiscardLevel() < 0 || mDesiredDiscardLevel < getDiscardLevel())
911 {
912 // We need to do a decode of that discard level to get more data.
913 if (mFormattedImagep.notNull() && !needsDecode())
914 {
915 if (mFormattedImagep->getDiscardLevel() <= mDesiredDiscardLevel)
916 {
917 setNeedsDecode(TRUE); // processTextureStats - Changing discard level of texture
918 }
919 // else let the llviewerimagelist logic do its thing
920 }
921 else if (mFormattedFlushed)
922 {
923 //llinfos << "Attempting vfs reload (a) of " << mID << llendl;
924 startVFSLoad();
925 }
926 }
927 else if (sDesiredDiscardBias > 0.0f && sBoundTextureMemory > sMaxBoundTextureMem*texmem_middle_bound_scale)
928 {
929 // Limit the amount of GL memory bound each frame
930 if (mDesiredDiscardLevel > getDiscardLevel())
931 {
932 increase_discard = TRUE;
933 }
934 }
935 else if (sDesiredDiscardBias > 0.0f && sTotalTextureMemory > sTotalTextureMemory*texmem_middle_bound_scale)
936 {
937 // Only allow GL to have 2x the video card memory
938 if (!getBoundRecently())
939 {
940 increase_discard = TRUE;
941 }
942 }
943 if (increase_discard)
944 {
945 sBoundTextureMemory -= mTextureMemory;
946 sTotalTextureMemory -= mTextureMemory;
947 // Increase the discard level (reduce the texture res)
948 S32 new_discard = getDiscardLevel()+1;
949 setDiscardLevel(new_discard);
950 sBoundTextureMemory += mTextureMemory;
951 sTotalTextureMemory += mTextureMemory;
952 }
953 }
954
955 //
956 // Flush the formatted data for this image if it hasn't been used in a while.
957 //
958#if 1
959 const F32 FLUSH_TIME = 30.f;
960 if (mFormattedImagep.notNull())
961 {
962 if ((mLastDecodeTime.getElapsedTimeF32() > FLUSH_TIME)
963 && !mStreamFile
964 && (this->mLastPacketTimer.getElapsedTimeF32() > FLUSH_TIME)
965 && !mNeedsDecode
966 && !mFormattedImagep->isDecoding()
967 && (mDesiredDiscardLevel == getDiscardLevel()))
968 {
969 //llinfos << mID << ": flushing formatted image, last processed packet " << mLastPacketProcessed << llendl;
970 // Treat this very similarly to like we haven't gotten any data
971 // Flush all received packets that haven't been processed, they will be readded on reload.
972 resetPacketData();
973
974 setFormattedImage(NULL);
975 mFullyLoaded = FALSE;
976
977 // This flag says that we may have VFS data if we want to reload this texture
978 // (or get network traffic for this texture)
979 mFormattedFlushed = TRUE;
980 }
981 }
982#endif
983}
984
985//============================================================================
986
987F32 LLViewerImage::calcDecodePriority()
988{
989 F32 priority;
990 S32 gldiscard = getDiscardLevel();
991 S32 ddiscard = gldiscard - mDesiredDiscardLevel;
992
993 if (mIsMissingAsset)
994 {
995 priority = 0.0f;
996 }
997 else if (mDesiredDiscardLevel > mMaxDiscardLevel)
998 {
999 // Don't decode anything we don't need
1000 priority = 0.0f;
1001 }
1002 else if (gldiscard < 0 && mDesiredDiscardLevel >= 0)
1003 {
1004 // We don't have any data yet, we need something immideately
1005 priority = 200000.f;
1006 }
1007 else if (getDiscardLevel() < 0 && mDesiredDiscardLevel < MAX_DISCARD_LEVEL+1)
1008 {
1009 // We have data, but haven't decoded any of it yet, but it on top
1010 priority = 300000.f;
1011 }
1012 else if (gldiscard <= mDesiredDiscardLevel)
1013 {
1014 priority = 0.0f;
1015 }
1016 else
1017 {
1018 // priority range = 0 - 10000 (10 ^ 4)
1019 if (getDontDiscard())
1020 {
1021 ddiscard+=2;
1022 }
1023 else if (!getBoundRecently())
1024 {
1025 ddiscard-=2;
1026 }
1027 else
1028 {
1029 ddiscard-=1;
1030 }
1031 ddiscard = llclamp(ddiscard, 0, 4);
1032
1033 priority = powf(10.f,(F32)ddiscard);
1034 }
1035 if (priority > 0.0f)
1036 {
1037 F32 pixel_priority = llmin(mMaxVirtualSize * (1.5f + mMaxCosAngle) * (100.f / (1024.f*1024.f)), 100.f);
1038 pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f);
1039 priority += pixel_priority;
1040 if ( mBoostLevel > 0)
1041 {
1042 priority += 1000000.f + 1000.f * mBoostLevel;
1043 }
1044 }
1045 return priority;
1046}
1047
1048// A value >= max value calculated above for normalization
1049//static
1050F32 LLViewerImage::maxDecodePriority()
1051{
1052 return 1400000.f;
1053}
1054
1055void LLViewerImage::setDecodePriority(F32 priority)
1056{
1057 llassert(!mInImageList);
1058 if (priority < 0.0f)
1059 {
1060 mDecodePriority = calcDecodePriority();
1061 }
1062 else
1063 {
1064 mDecodePriority = priority;
1065 }
1066 if (mStreamFile)
1067 {
1068 mStreamFile->setReadPriority(priority);
1069 }
1070}
1071
1072void LLViewerImage::setBoostLevel(S32 level)
1073{
1074 mBoostLevel = level;
1075 if (level >= LLViewerImage::BOOST_HIGH)
1076 {
1077 processTextureStats();
1078 }
1079}
1080
1081//============================================================================
1082
1083void LLViewerImage::abortDecode()
1084{
1085 // Don't try to recover, just don't set a formatted image.
1086 // Recovery makes the code MUCH more complex
1087 //llinfos << "Reset on abort decode" << llendl;
1088 resetPacketData();
1089
1090 setFormattedImage(NULL);
1091 mFullyLoaded = FALSE;
1092 // Make sure mNeedsAux is false, otherwise it'll try to decode the 5th channel
1093 mNeedsAux = FALSE;
1094 mFullWidth = 0;
1095 mFullHeight = 0;
1096 setNeedsDecode(FALSE); // Aborting setDecodeData
1097 mDecodingAux = FALSE;
1098 if (mStreamFile)
1099 {
1100 llwarns << "Removing bad texture: " << mID << llendl;
1101 hoseStreamFile();
1102 }
1103 else
1104 {
1105 llwarns << "Removing bad texture: " << mID << llendl;
1106 LLVFile vf(gVFS, mID, LLAssetType::AT_TEXTURE, LLVFile::READ_WRITE);
1107 vf.remove();
1108 }
1109 mRequestedDiscardLevel = -1; // make sure we re-request the data
1110}
1111
1112void LLViewerImage::hoseStreamFile()
1113{
1114 mStreamFile->remove();
1115
1116 delete mStreamFile;
1117 mStreamFile = NULL;
1118
1119 delete[] mCachedData;
1120 mCachedData = NULL;
1121 mCachedSize = 0;
1122}
1123
1124
1125// Sets mStreamFile to NULL when finishes loading.
1126BOOL LLViewerImage::loadStreamFile()
1127{
1128 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1129 // load as much data as possible from the stream cache file
1130 // TODO: unify stream cache with load local
1131
1132 // are we waiting on a file read?
1133 if (mStreamFile)
1134 {
1135 if (mCachedSize == 0)
1136 {
1137 if (mStreamFile->isLocked(VFSLOCK_APPEND))
1138 {
1139 // avoid stalling if we are still writing to the file
1140 return FALSE;
1141 }
1142 mCachedSize = mStreamFile->getSize();
1143 if (mCachedSize >= 27)
1144 {
1145 mCachedData = new U8[mCachedSize];
1146 mStreamFile->read(mCachedData, mCachedSize, TRUE, 100 + mDecodePriority);
1147 }
1148 else
1149 {
1150 llwarns << "Cached image " << mID << " has length " << mCachedSize << " not loading" << llendl;
1151
1152 mStreamFile->remove();
1153
1154 delete mStreamFile;
1155 mStreamFile = NULL;
1156 mCachedSize = 0;
1157 return FALSE;
1158 }
1159 }
1160
1161 // is it finished?
1162 if (mStreamFile->isReadComplete())
1163 {
1164 //llinfos << mID << ": loading from stream file " << llendl;
1165 U16 packet;
1166 U32 file_version;
1167 LLUUID file_id;
1168
1169 U8 *tmp = mCachedData;
1170 memcpy(&file_version, tmp, 4);
1171 tmp += 4;
1172 memcpy(file_id.mData, tmp, 16);
1173 tmp += 16;
1174
1175 if (file_version != sCurrentFileVersion ||
1176 file_id != mID)
1177 {
1178 // this file is from an old version, failed to open, or is invalid
1179 hoseStreamFile();
1180
1181 return TRUE; // done
1182 }
1183
1184 mGotFirstPacket = TRUE;
1185
1186 memcpy(&mDataCodec, tmp, 1);
1187 tmp += 1;
1188 memcpy(&mPackets, tmp, 2);
1189 tmp += 2;
1190
1191 memcpy(&mTotalBytes, tmp, 4);
1192 tmp += 4;
1193
1194 while (tmp - mCachedData < mCachedSize)
1195 {
1196 memcpy(&packet, tmp, 2);
1197 tmp += 2;
1198
1199 if (packet >= mPackets)
1200 {
1201 llwarns << "Cached image " << mID << " has bogus packet " << packet << " of " << mPackets << llendl;
1202
1203 hoseStreamFile();
1204 return TRUE; // done
1205 }
1206
1207 U16 data_size;
1208 memcpy((U8*)&(data_size), tmp, 2);
1209 tmp += 2;
1210
1211 if (tmp + data_size > mCachedData + mCachedSize)
1212 {
1213 llwarns << "Cached image " << mID << " has bad length " << mCachedSize << ", should be " << (S32)(tmp + data_size - mCachedData) << llendl;
1214
1215 hoseStreamFile();
1216 return TRUE; // done
1217 }
1218
1219 if (mReceivedPacketMap.find(packet) == mReceivedPacketMap.end())
1220 {
1221 U8 *buf = new U8[data_size];
1222 memcpy(buf, tmp, data_size);
1223 mReceivedPacketMap[packet] = new LLViewerImagePacket(buf, data_size, packet, TRUE);
1224 }
1225 else
1226 {
1227 // Technically this assertion is correct, but there may be bogus VFS files out there which invalidate this
1228 // condition.
1229 //llassert(!mReceivedPacketMap[packet]->mWroteToDisk);
1230 mReceivedPacketMap[packet]->mWroteToDisk = TRUE;
1231 }
1232
1233 tmp += data_size;
1234
1235 mPacketsReceived++;
1236 }
1237
1238 delete mStreamFile;
1239 mStreamFile = NULL;
1240
1241 delete[] mCachedData;
1242 mCachedData = NULL;
1243 mCachedSize = 0;
1244
1245 // Make sure we process all of the packet data associated with this texture.
1246 mLastPacketProcessed = -1;
1247 mLastPacket = -1;
1248 mLastPacketTimer.reset();
1249
1250 // Process the packets and write to disk any that have not been written
1251 checkPacketData();
1252
1253 return TRUE; // done
1254 }
1255 else
1256 {
1257 return FALSE; // still loading
1258 }
1259 }
1260 else
1261 {
1262 return TRUE; // not loading
1263 }
1264}
1265
1266//============================================================================
1267
1268void LLViewerImage::setLoadedCallback( loaded_callback_func loaded_callback, S32 discard_level, BOOL keep_imageraw, void* userdata)
1269{
1270 //
1271 // Don't do ANYTHING here, just add it to the global callback list
1272 //
1273 if (mLoadedCallbackList.empty())
1274 {
1275 // Put in list to call this->doLoadedCallbacks() periodically
1276 gImageList.mCallbackList.insert(this);
1277 }
1278 LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata);
1279 mLoadedCallbackList.push_back(entryp);
1280}
1281
1282void LLViewerImage::doLoadedCallbacks()
1283{
1284 // Need to make sure we don't do these during the process of a decode or something?
1285 if ((mFormattedImagep.notNull() && mFormattedImagep->isDecoding()) || mNeedsCreateTexture)
1286 {
1287 return;
1288 }
1289
1290 if (isMissingAsset())
1291 {
1292 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
1293 iter != mLoadedCallbackList.end(); )
1294 {
1295 LLLoadedCallbackEntry *entryp = *iter++;
1296 // We never finished loading the image. Indicate failure.
1297 // Note: this allows mLoadedCallbackUserData to be cleaned up.
1298 entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData);
1299 delete entryp;
1300 }
1301 mLoadedCallbackList.clear();
1302
1303 // Remove ourself from the global list of textures with callbacks
1304 gImageList.mCallbackList.erase(this);
1305 }
1306
1307 S32 gl_discard = getDiscardLevel();
1308
1309 // If we don't have a legit GL image, set it to be lower than the worst discard level
1310 if (gl_discard == -1)
1311 {
1312 gl_discard = MAX_DISCARD_LEVEL + 1;
1313 }
1314
1315 // assert: We should either have a valid raw image, be decoding one, or not have one at all
1316 llassert(mIsRawImageValid || needsDecode() || mRawImage.isNull());
1317 // assert: We should either not have a raw image, or it's discard level should be <= gl_discard
1318 llassert(!mIsRawImageValid || mRawDiscardLevel <= gl_discard);
1319
1320
1321 //
1322 // Determine the quality levels of textures that we can provide to callbacks
1323 // and whether we need to do decompression/readback to get it
1324 //
1325 S32 current_raw_discard = MAX_DISCARD_LEVEL + 1; // We can always do a readback to get a raw discard
1326 S32 best_raw_discard = gl_discard; // Current GL quality level
1327 S32 current_aux_discard = MAX_DISCARD_LEVEL + 1;
1328 S32 best_aux_discard = MAX_DISCARD_LEVEL + 1;
1329
1330 if (mIsRawImageValid)
1331 {
1332 // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels.
1333 best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel);
1334 best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw
1335 current_aux_discard = llmin(current_aux_discard, best_aux_discard);
1336 }
1337 else
1338 {
1339 if (mFormattedImagep.notNull())
1340 {
1341 // If we don't have a raw image or a GL image, we need to decode from a formatted image
1342 best_aux_discard = llmin(best_aux_discard,
1343 mFormattedImagep->calcDiscardLevelBytes(mFormattedImagep->getDataSize()));
1344 }
1345 else
1346 {
1347 // We have no data at all, we need to get the formatted image.
1348 // Do this by forcing the best aux discard to be 0.
1349 best_aux_discard = 0;
1350 }
1351 }
1352
1353
1354 //
1355 // See if any of the callbacks would actually run using the data that we can provide,
1356 // and also determine if we need to perform any readbacks or decodes.
1357 //
1358 bool run_gl_callbacks = false;
1359 bool run_raw_callbacks = false;
1360 bool need_readback = false;
1361 bool need_decompress = false;
1362
1363 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
1364 iter != mLoadedCallbackList.end(); )
1365 {
1366 LLLoadedCallbackEntry *entryp = *iter++;
1367 if (entryp->mNeedsImageRaw)
1368 {
1369 if (mNeedsAux)
1370 {
1371 //
1372 // Need raw and auxiliary channels
1373 //
1374 if (entryp->mLastUsedDiscard > current_aux_discard)
1375 {
1376 // We have useful data, run the callbacks
1377 run_raw_callbacks = true;
1378 }
1379 else if (entryp->mLastUsedDiscard > best_aux_discard)
1380 {
1381 // We need to decompress data, but don't need
1382 // to run the callbacks
1383 need_decompress = true;
1384 }
1385 }
1386 else
1387 {
1388 if (entryp->mLastUsedDiscard > current_raw_discard)
1389 {
1390 // We have useful data, just run the callbacks
1391 run_raw_callbacks = true;
1392 }
1393 else if (entryp->mLastUsedDiscard > best_raw_discard)
1394 {
1395 // We can readback data, and then run the callbacks
1396 need_readback = true;
1397 run_raw_callbacks = true;
1398 }
1399 }
1400 }
1401 else
1402 {
1403 // Needs just GL
1404 if (entryp->mLastUsedDiscard > gl_discard)
1405 {
1406 // We have enough data, run this callback requiring GL data
1407 run_gl_callbacks = true;
1408 }
1409 }
1410 }
1411
1412 //
1413 // Do a readback if required, OR start off a texture decode
1414 //
1415 if (need_readback && (mMaxDiscardLevel > gl_discard))
1416 {
1417 // Do a readback to get the GL data into the raw image
1418 // We have GL data.
1419
1420 destroyRawImage();
1421 createRawImage(gl_discard, TRUE);
1422 readBackRaw(gl_discard, mRawImage);
1423 mIsRawImageValid = TRUE;
1424 }
1425 if (need_decompress)
1426 {
1427 startImageDecode();
1428 }
1429
1430 //
1431 // Run raw/auxiliary data callbacks
1432 //
1433 if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= mMaxDiscardLevel))
1434 {
1435 // Do callbacks which require raw image data.
1436 //llinfos << "doLoadedCallbacks raw for " << getID() << llendl;
1437
1438 LLImageRaw* raw_image = mRawImage;
1439 LLImageRaw* raw_image_aux = mAuxRawImage;
1440 llassert(!mNeedsAux || mAuxRawImage.notNull());
1441
1442 // Call each party interested in the raw data.
1443 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
1444 iter != mLoadedCallbackList.end(); )
1445 {
1446 callback_list_t::iterator curiter = iter++;
1447 LLLoadedCallbackEntry *entryp = *curiter;
1448 if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel))
1449 {
1450 // If we've loaded all the data there is to load or we've loaded enough
1451 // to satisfy the interested party, then this is the last time that
1452 // we're going to call them.
1453
1454
1455 BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE;
1456 //llinfos << "Running callback for " << getID() << llendl;
1457 //llinfos << raw_image->getWidth() << "x" << raw_image->getHeight() << llendl;
1458 if (final)
1459 {
1460 //llinfos << "Final!" << llendl;
1461 }
1462 entryp->mLastUsedDiscard = mRawDiscardLevel;
1463 entryp->mCallback(TRUE, this, raw_image, raw_image_aux, mRawDiscardLevel, final, entryp->mUserData);
1464 if (final)
1465 {
1466 iter = mLoadedCallbackList.erase(curiter);
1467 delete entryp;
1468 }
1469 }
1470 }
1471
1472 //
1473 // If you want to keep a copy of the raw image, you better copy it off yourself
1474 //
1475 destroyRawImage();
1476 }
1477
1478 //
1479 // Run GL callbacks
1480 //
1481 if (run_gl_callbacks && (gl_discard <= mMaxDiscardLevel))
1482 {
1483 //llinfos << "doLoadedCallbacks GL for " << getID() << llendl;
1484
1485 // Call the callbacks interested in GL data.
1486 for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
1487 iter != mLoadedCallbackList.end(); )
1488 {
1489 callback_list_t::iterator curiter = iter++;
1490 LLLoadedCallbackEntry *entryp = *curiter;
1491 if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard))
1492 {
1493 BOOL final = gl_discard <= entryp->mDesiredDiscard ? TRUE : FALSE;
1494 entryp->mLastUsedDiscard = gl_discard;
1495 entryp->mCallback(TRUE, this, NULL, NULL, gl_discard, final, entryp->mUserData);
1496 if (final)
1497 {
1498 iter = mLoadedCallbackList.erase(curiter);
1499 delete entryp;
1500 }
1501 }
1502 }
1503 }
1504
1505 //
1506 // If we have no callbacks, take us off of the image callback list.
1507 //
1508 if (mLoadedCallbackList.empty())
1509 {
1510 gImageList.mCallbackList.erase(this);
1511 }
1512}
1513
1514//============================================================================
1515
1516// static
1517void LLViewerImage::receiveImage(LLMessageSystem *msg, void **user_data)
1518{
1519 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1520
1521 // Receive image header, copy into image object and decompresses
1522 // if this is a one-packet image.
1523
1524 LLUUID id;
1525
1526 char ip_string[256];
1527 u32_to_ip_string(msg->getSenderIP(),ip_string);
1528
1529 if (msg->getReceiveCompressedSize())
1530 {
1531 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
1532 }
1533 else
1534 {
1535 gImageList.sTextureBits += msg->getReceiveSize() * 8;
1536 }
1537 gImageList.sTexturePackets++;
1538
1539 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
1540
1541 char id_string[UUID_STR_LENGTH];
1542 id.toString(id_string);
1543
1544 LLViewerImage *image = gImageList.getImage(id); // Look up the correct image
1545
1546 image->mLastPacketTimer.reset();
1547
1548 if (image->mFullyLoaded)
1549 {
1550// llinfos << id << ":" << " Packet 0 for already loaded image!" << llendl;
1551 return;
1552 }
1553
1554 // check to see if we've gotten this packet before
1555 if (image->mGotFirstPacket)
1556 {
1557 //llinfos << id << ":" << " Duplicate Packet 0" << llendl;
1558 return;
1559 }
1560 if (!image->mRequested)
1561 {
1562// llinfos << id << ":" << " Packet 0 for unrequested image!" << llendl;
1563 return;
1564 }
1565
1566 image->mGotFirstPacket = TRUE;
1567
1568 // Copy header data into image object
1569 msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, image->mDataCodec);
1570 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, image->mPackets);
1571 msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, image->mTotalBytes);
1572
1573 if (0 == image->mPackets)
1574 {
1575 llwarns << "Img: " << (gTextureTable.getName(id).empty() ? id_string : gTextureTable.getName(id)) << ":" << " Number of packets is 0" << llendl;
1576 return;
1577 }
1578
1579 lldebugst(LLERR_IMAGE) << "Img: " << (gTextureTable.getName(id).empty() ? id_string : gTextureTable.getName(id)) << ":" << " Packet 0:" << image->mPackets - 1 << llendl;
1580
1581 U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
1582
1583 // Got a packet, reset the counter.
1584 image->mRequestTime.reset();
1585 image->mPacketsReceived++;
1586
1587 if (data_size)
1588 {
1589 if (gVFS->getExists(image->mID, LLAssetType::AT_TEXTURE))
1590 {
1591 // We have data in the VFS, but it's not loaded.
1592 // We should start the VFS load on the assumption that we're going to use this data shortly.
1593 image->startVFSLoad();
1594 // We can throw out this data, because we have at least ONE packet on the disk
1595 //llinfos << "Throwing out first packet for " << image->mID << " which we already have a VFS file for!" << llendl;
1596 return;
1597 }
1598
1599 // this buffer gets saved off in the packet list
1600 U8 *data = new U8[data_size];
1601 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
1602
1603 // output this image data to cache file
1604 // only do this if we don't have old data
1605 LLVFile file(gVFS, image->mID, LLAssetType::AT_TEXTURE, LLVFile::APPEND);
1606 if (! file.getSize())
1607 {
1608 BOOL write_to_vfs = FALSE;
1609 if (image->mPackets == 0)
1610 {
1611 // Uh oh, we don't have packet data size
1612 // This must be something from a local cache
1613 llwarns << "Creating VFS file even though we don't know the number of packets!" << llendl;
1614 }
1615 else
1616 {
1617 write_to_vfs = file.setMaxSize(image->mTotalBytes + IMAGE_HEADER_SIZE + image->mPackets * PACKET_HEADER_SIZE);
1618 }
1619
1620 // to avoid another dynamic allocation, just assume we won't be gettimg image packets > 1 MTU
1621 if (data_size > MTUBYTES)
1622 {
1623 llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
1624 }
1625
1626 if (write_to_vfs)
1627 {
1628 const S32 WRITE_BUF_SIZE = IMAGE_HEADER_SIZE + PACKET_HEADER_SIZE + MTUBYTES;
1629 U8 buffer[WRITE_BUF_SIZE];
1630 U8 *tmp = buffer;
1631
1632 // write current version byte to file, so we can change the format and detect old files later
1633 memcpy(tmp, &LLViewerImage::sCurrentFileVersion, 4);
1634 tmp += 4;
1635 memcpy(tmp, id.mData, 16);
1636 tmp += 16;
1637 memcpy(tmp, (U8*)&(image->mDataCodec), 1);
1638 tmp += 1;
1639 memcpy(tmp, (U8*)&(image->mPackets), 2);
1640 tmp += 2;
1641 memcpy(tmp, (U8*)&(image->mTotalBytes), 4);
1642 tmp += 4;
1643 U16 zero = 0;
1644 memcpy(tmp, (U8*)&zero, 2);
1645 tmp += 2;
1646 memcpy(tmp, (U8*)&(data_size), 2);
1647 tmp += 2;
1648
1649 // now copy in the image data
1650 // it's a shame we can't use the original data buffer
1651 // but this needs to be a single, atomic write
1652 memcpy(tmp, data, data_size);
1653
1654// llinfos << "Writing packet 0 to disk for " << image->getID() << llendl;
1655 file.write(buffer, IMAGE_HEADER_SIZE + PACKET_HEADER_SIZE + data_size);
1656 }
1657 // do this AFTER writing to the VFS since LLViewerImagePacket may delete 'data'
1658 llassert( image->mReceivedPacketMap.find(0) == image->mReceivedPacketMap.end() );
1659 image->mReceivedPacketMap[0] = new LLViewerImagePacket(data, data_size, 0, TRUE);
1660 }
1661
1662 image->checkPacketData();
1663 }
1664}
1665
1666
1667///////////////////////////////////////////////////////////////////////////////
1668// TODO: lastbytes vs. texturebits?
1669// TODO: is mRequested already used?
1670
1671// static
1672void LLViewerImage::receiveImagePacket(LLMessageSystem *msg, void **user_data)
1673{
1674 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1675 LLFastTimer t(LLFastTimer::FTM_PROCESS_IMAGES);
1676
1677 // Receives image packet, copy into image object,
1678 // checks if all packets received, decompresses if so.
1679
1680 LLUUID id;
1681 U16 packet_num;
1682 char id_string[UUID_STR_LENGTH];
1683
1684 char ip_string[256];
1685 u32_to_ip_string(msg->getSenderIP(),ip_string);
1686
1687 if (msg->getReceiveCompressedSize())
1688 {
1689 gImageList.sTextureBits += msg->getReceiveCompressedSize() * 8;
1690 }
1691 else
1692 {
1693 gImageList.sTextureBits += msg->getReceiveSize() * 8;
1694 }
1695 gImageList.sTexturePackets++;
1696
1697 //llprintline("Start decode, image header...");
1698 msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
1699 msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num);
1700
1701 id.toString(id_string);
1702
1703 LLViewerImage *image = gImageList.hasImage(id); // Look up the correct image
1704 if (!image ||!(image->mRequested))
1705 {
1706 // Getting a packet for an unrequested image.
1707 lldebugst(LLERR_IMAGE) << "Img: " << (gTextureTable.getName(id).empty() ? id_string : gTextureTable.getName(id)) << " Packet ";
1708 llcont << packet_num << " for unrequested from " << ip_string << llendl;
1709
1710 // don't cancel the request - this might just be an out of order packet
1711 return;
1712 }
1713
1714 image->mLastPacketTimer.reset();
1715
1716 if (image->mReceivedPacketMap.find(packet_num) != image->mReceivedPacketMap.end())
1717 {
1718 return;
1719 }
1720
1721 // check to see if we already got this packet
1722 BOOL duplicate = FALSE;
1723 if (packet_num <= image->mLastPacketProcessed)
1724 {
1725 duplicate = TRUE;
1726 }
1727 else if (image->mReceivedPacketMap.find(packet_num) != image->mReceivedPacketMap.end())
1728 {
1729 duplicate = TRUE;
1730 }
1731
1732 if (duplicate)
1733 {
1734 //llinfos << image->mID << ": duplicate packet " << packet_num << " last " << image->mLastPacketProcessed << llendl;
1735 return;
1736 }
1737
1738 // Got a packet, reset the counter.
1739 image->mRequestTime.reset();
1740 image->mPacketsReceived++;
1741
1742 std::string tex_name = gTextureTable.getName(id);
1743 if (image->mPackets == 0)
1744 {
1745 lldebugst(LLERR_IMAGE) << "Img: " << (tex_name.empty() ? id_string : tex_name) << " Packet " << packet_num << " out of order " << llendl;
1746 }
1747 else
1748 {
1749 lldebugst(LLERR_IMAGE) << "Img: " << (tex_name.empty() ? id_string : tex_name) << " Packet " << packet_num << ":" << image->mPackets - 1 << llendl;
1750 }
1751
1752
1753 U16 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data);
1754 if (data_size)
1755 {
1756
1757 U8 *data = new U8[data_size];
1758 msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size);
1759
1760 // as above assume we won't be gettimg image packets > 1 MTU
1761 if (data_size > MTUBYTES)
1762 {
1763 llerrs << "image data chunk too large: " << data_size << " bytes" << llendl;
1764 }
1765
1766 // We don't want to write it to disk yet, just put it on the queue.
1767 image->mReceivedPacketMap[packet_num] = new LLViewerImagePacket(data, data_size, packet_num, FALSE);
1768 // Process this packet.
1769 image->checkPacketData();
1770 }
1771}
1772
1773
1774BOOL LLViewerImage::checkPacketData()
1775{
1776 LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE);
1777
1778 S32 cur_size = 0;
1779 S32 next_size = 0;
1780 S32 next_discard = llmax(getDiscardLevel()-1,0);
1781
1782 // 1. Check if we already have formatted data to decode
1783 if (mFormattedImagep.notNull())
1784 {
1785 if ((mFormattedImagep->isDecoding()) || mStreamFile)
1786 {
1787 return TRUE; // we're busy decoding, don't request more data yet
1788 }
1789
1790 cur_size = mFormattedImagep->getDataSize();
1791 next_size = mFormattedImagep->calcDataSize(next_discard);
1792 next_size = llmin(next_size, (S32)mTotalBytes);
1793
1794 if (cur_size >= next_size)
1795 {
1796 setDecodeData(mFormattedImagep->getData(), cur_size);
1797 return TRUE;
1798 }
1799 }
1800
1801 if (mFullyLoaded)
1802 {
1803 // Somehow we think we have new packet data but are flagged as fully loaded
1804 resetPacketData();
1805 return TRUE;
1806 }
1807
1808 // 2. Check if we already have new packets
1809 if (!mPackets || !mGotFirstPacket)
1810 {
1811 return FALSE;
1812 }
1813 if (mReceivedPacketMap.empty() || mReceivedPacketMap.find(mLastPacketProcessed + 1) == mReceivedPacketMap.end())
1814 {
1815 return FALSE;
1816 }
1817
1818 // 3. Decide if we have enough new data to decode
1819 S32 new_size = cur_size;
1820 U16 next_packet_num = mLastPacketProcessed;
1821 for (vip_map_t::iterator iter = mReceivedPacketMap.begin();
1822 iter != mReceivedPacketMap.end() && iter->second->mPacketNum == ++next_packet_num;
1823 iter++)
1824 {
1825 new_size += iter->second->mDataSize;
1826 mLastPacket = iter->second->mPacketNum;
1827 }
1828 mLastBytesProcessed = new_size;
1829
1830 if (new_size < next_size)
1831 {
1832 return FALSE;
1833 }
1834
1835 if (!gVFS->getExists(mID, LLAssetType::AT_TEXTURE))
1836 {
1837 // We must have removed the file, probably because it was corrupted. Abort!
1838 //llinfos << "Reset on no VFS file!" << llendl;
1839 abortDecode();
1840 return FALSE;
1841 }
1842
1843 if (mLastPacketProcessed == -1 && cur_size != 0)
1844 {
1845 llerrs << "LLViewerImage: duplicate first packet!" << llendl;
1846 }
1847
1848 // 4. Append new data to existing data and decode
1849
1850 // 4a. Write the packets to disk
1851 LLVFile file(gVFS, mID, LLAssetType::AT_TEXTURE, LLVFile::APPEND);
1852 vip_map_t::iterator first_iter = mReceivedPacketMap.begin();
1853 S32 first_idx = 0;
1854 while (first_iter != mReceivedPacketMap.end())
1855 {
1856 S32 packet_data_size = 0;
1857 vip_map_t::iterator end_iter = first_iter;
1858 S32 end_idx = first_idx;
1859 while(end_iter != mReceivedPacketMap.end())
1860 {
1861 LLViewerImagePacket *vip = end_iter->second;
1862 if (!vip->mWroteToDisk)
1863 {
1864 packet_data_size += (PACKET_HEADER_SIZE + vip->mDataSize);
1865 }
1866 else
1867 {
1868 break;
1869 }
1870 ++end_iter;
1871 ++end_idx;
1872 }
1873 if (packet_data_size > 0)
1874 {
1875 U8* packet_data_buffer = new U8[packet_data_size];
1876 U8* packet_data = packet_data_buffer;
1877 for (vip_map_t::iterator iter = first_iter; iter != end_iter; ++iter)
1878 {
1879 LLViewerImagePacket *vip = iter->second;
1880
1881 memcpy(packet_data, &vip->mPacketNum, 2);
1882 memcpy(packet_data + 2, &(vip->mDataSize), 2);
1883 memcpy(packet_data + PACKET_HEADER_SIZE, vip->mData, vip->mDataSize);
1884 packet_data += (PACKET_HEADER_SIZE + vip->mDataSize);
1885
1886 vip->mWroteToDisk = TRUE;
1887 }
1888 if (packet_data - packet_data_buffer != packet_data_size) llerrs << "wtf?" << llendl;
1889
1890 // llinfos << mID << " Writing packets " << first_idx << "-" << end_idx << " to file." << llendl;
1891 file.write(packet_data_buffer, packet_data_size);
1892
1893 delete[] packet_data_buffer;
1894 }
1895 if (end_iter == first_iter)
1896 {
1897 ++end_iter;
1898 ++end_idx;
1899 }
1900 first_iter = end_iter;
1901 first_idx = end_idx;
1902 }
1903
1904 // 4b. Append the data
1905 U8* data = new U8[new_size];
1906 if (cur_size > 0)
1907 {
1908 memcpy(data, mFormattedImagep->getData(), cur_size);
1909 }
1910 LLViewerImagePacket *pkt = mReceivedPacketMap.begin()->second;
1911 while (pkt && pkt->mPacketNum == mLastPacketProcessed + 1)
1912 {
1913 memcpy((U8*)(data + cur_size), pkt->mData, pkt->mDataSize);
1914 cur_size += pkt->mDataSize;
1915 mLastPacketProcessed = pkt->mPacketNum;
1916 delete mReceivedPacketMap.begin()->second;
1917 mReceivedPacketMap.erase(mReceivedPacketMap.begin());
1918 pkt = NULL;
1919 if (!mReceivedPacketMap.empty())
1920 {
1921 pkt = mReceivedPacketMap.begin()->second;
1922 }
1923 }
1924
1925 llassert(cur_size == new_size);
1926 lldebugst(LLERR_IMAGE) << "IMAGE RECEIVED: " << mID.getString() << " Bytes: " << cur_size << "/" << mTotalBytes << llendl;
1927
1928 // 4c. Set the data to be decoded, and the number of bytes to use.
1929 setDecodeData(data, new_size);
1930
1931 // 5. Recalculate the image priority
1932 gImageList.removeImageFromList(this);
1933 F32 decode_priority = calcDecodePriority();
1934 setDecodePriority(decode_priority);
1935 gImageList.addImageToList(this);
1936
1937 return TRUE;
1938}
1939
1940F32 LLViewerImage::getDecodeProgress(F32 *data_progress_p)
1941{
1942 F32 decode_progress = 0.0f;
1943 F32 data_progress = 0.0f;
1944
1945 if (mLastPacket >= 0)
1946 {
1947 S32 max_bytes = mTotalBytes;
1948 S32 data_bytes = mLastBytesProcessed;
1949 S32 decode_bytes = mFormattedImagep.notNull() ? mFormattedImagep->getDataSize() : data_bytes;
1950 data_progress = (F32)data_bytes / (F32)max_bytes;
1951 decode_progress = (F32)decode_bytes / (F32)max_bytes;
1952 }
1953 if (data_progress_p) *data_progress_p = data_progress;
1954 return decode_progress;
1955}
1956
1957// Call with 0,0 to turn this feature off.
1958void LLViewerImage::setKnownDrawSize(S32 width, S32 height)
1959{
1960 mKnownDrawWidth = width;
1961 mKnownDrawHeight = height;
1962 addTextureStats((F32)(width * height));
1963}
1964
1965// virtual
1966BOOL LLViewerImage::bind(S32 stage) const
1967{
1968 if (stage == -1)
1969 {
1970 return TRUE;
1971 }
1972
1973 if (gNoRender)
1974 {
1975 return true;
1976 }
1977 BOOL res = bindTextureInternal(stage);
1978 if (res)
1979 {
1980 if (mIsMissingAsset)
1981 {
1982 // If we can bind, clearly we have an asset.
1983 // If mIsMissingAsset was true and we get here, it's likely
1984 // that the asset server was messed up and then it recovered.
1985 mIsMissingAsset = FALSE;
1986 }
1987 }
1988 else
1989 {
1990 // On failure to bind, what should we set the currently bound texture to?
1991 if (mIsMissingAsset && !sMissingAssetImagep.isNull() && (this != (LLImageGL *)sMissingAssetImagep))
1992 {
1993 res = sMissingAssetImagep->bind( stage );
1994 }
1995 if (!res && !sDefaultImagep.isNull() && (this != (LLImageGL *)sDefaultImagep))
1996 {
1997 // use default if we've got it
1998 res = sDefaultImagep->bind(stage);
1999 }
2000 if (!res && !sNullImagep.isNull() && (this != (LLImageGL *)sNullImagep))
2001 {
2002 res = sNullImagep->bind(stage);
2003 }
2004 if (!res)
2005 {
2006 llwarns << "LLViewerImage::bindTexture failed." << llendl;
2007 }
2008 stop_glerror();
2009 }
2010 return res;
2011}
2012
2013// Was in LLImageGL
2014LLImageRaw* LLViewerImage::createRawImage(S8 discard_level, BOOL allocate)
2015{
2016 llassert(discard_level >= 0);
2017 llassert(mFormattedImagep.isNull() || !mFormattedImagep->isDecoding());
2018 if (mRawImage.notNull())
2019 {
2020 llerrs << "createRawImage() called with existing mRawImage" << llendl;
2021 mRawImage = NULL;
2022 mAuxRawImage = NULL;
2023 }
2024 if (allocate && mComponents)
2025 {
2026 mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), mComponents);
2027 mIsRawImageValid = TRUE;
2028 }
2029 else
2030 {
2031 mRawImage = new LLImageRaw;
2032 mIsRawImageValid = FALSE;
2033 }
2034 mRawDiscardLevel = discard_level;
2035
2036 return mRawImage;
2037}
2038
2039void LLViewerImage::destroyRawImage()
2040{
2041 mRawImage = NULL;
2042 mAuxRawImage = NULL;
2043 mIsRawImageValid = FALSE;
2044 mRawDiscardLevel = INVALID_DISCARD_LEVEL;
2045}