summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorXiaohong Bao <bao@lindenlab.com>2009-11-06 06:52:24 +0000
committerXiaohong Bao <bao@lindenlab.com>2009-11-06 06:52:24 +0000
commit35e200881c38eb6c1bfd1f14ef440d4bc4da8c74 (patch)
tree8fceb759ef8f8259fd574c398ac02965566a05ff /indra
parent2f2bdd83d6e078fb6cdcbb0ba0a9eaa38d45cc90 (diff)
merge QAR-1829: texture pipeline branch in viewer-2.0.0.3
Diffstat (limited to 'indra')
-rw-r--r--indra/llcharacter/llheadrotmotion.cpp11
-rw-r--r--indra/llcommon/llapr.cpp161
-rw-r--r--indra/llcommon/llapr.h34
-rw-r--r--indra/llcommon/llqueuedthread.cpp70
-rw-r--r--indra/llcommon/llqueuedthread.h4
-rw-r--r--indra/llcommon/llthread.h2
-rw-r--r--indra/llcommon/llworkerthread.cpp1
-rw-r--r--indra/llcommon/llworkerthread.h6
-rw-r--r--indra/llimage/CMakeLists.txt4
-rw-r--r--indra/llimage/llimage.cpp67
-rw-r--r--indra/llimage/llimage.h13
-rw-r--r--indra/llimage/llimagedxt.cpp19
-rw-r--r--indra/llimage/llimagej2c.cpp5
-rw-r--r--indra/llimage/llimagejpeg.cpp9
-rw-r--r--indra/llimage/llimageworker.cpp202
-rw-r--r--indra/llimage/llimageworker.h95
-rw-r--r--indra/llimage/tests/llimageworker_test.cpp260
-rw-r--r--indra/llmath/llvolume.cpp2
-rw-r--r--indra/llmessage/llassetstorage.cpp3
-rw-r--r--indra/llmessage/llassetstorage.h11
-rw-r--r--indra/llmessage/llcurl.cpp36
-rw-r--r--indra/llmessage/llcurl.h7
-rw-r--r--indra/llmessage/tests/llcurl_stub.cpp3
-rw-r--r--indra/llmessage/tests/llhttpclientadapter_test.cpp2
-rw-r--r--indra/llrender/llimagegl.cpp395
-rw-r--r--indra/llrender/llimagegl.h85
-rw-r--r--indra/llrender/llrender.cpp15
-rw-r--r--indra/llrender/llrender.h4
-rw-r--r--indra/llrender/lltexture.h2
-rw-r--r--indra/llvfs/lllfsthread.cpp4
-rw-r--r--indra/newview/CMakeLists.txt20
-rw-r--r--indra/newview/app_settings/settings.xml83
-rw-r--r--indra/newview/llagent.cpp16
-rw-r--r--indra/newview/llappviewer.cpp29
-rw-r--r--indra/newview/llappviewer.h13
-rw-r--r--indra/newview/llassetuploadresponders.cpp10
-rw-r--r--indra/newview/llassetuploadresponders.h1
-rw-r--r--indra/newview/llcolorswatch.cpp2
-rw-r--r--indra/newview/lldebugview.cpp35
-rw-r--r--indra/newview/lldrawable.cpp2
-rw-r--r--indra/newview/lldrawpool.cpp8
-rw-r--r--indra/newview/lldrawpoolalpha.cpp2
-rw-r--r--indra/newview/lldrawpooltree.cpp2
-rw-r--r--indra/newview/lldynamictexture.cpp2
-rw-r--r--indra/newview/llface.cpp157
-rw-r--r--indra/newview/llface.h20
-rw-r--r--indra/newview/llfloatermap.cpp48
-rw-r--r--indra/newview/llfloatermap.h2
-rw-r--r--indra/newview/llfloaterreporter.cpp2
-rw-r--r--indra/newview/llfloaterworldmap.cpp182
-rw-r--r--indra/newview/llfloaterworldmap.h10
-rw-r--r--indra/newview/lllandmarkactions.cpp15
-rw-r--r--indra/newview/llnavigationbar.cpp7
-rw-r--r--indra/newview/llnetmap.cpp69
-rw-r--r--indra/newview/llnetmap.h12
-rw-r--r--indra/newview/llpanelteleporthistory.cpp2
-rw-r--r--indra/newview/llpreviewtexture.cpp6
-rw-r--r--indra/newview/llspatialpartition.cpp3
-rw-r--r--indra/newview/llstartup.cpp9
-rw-r--r--indra/newview/llsurface.cpp7
-rw-r--r--indra/newview/lltexlayer.cpp12
-rw-r--r--indra/newview/lltexturecache.cpp1286
-rw-r--r--indra/newview/lltexturecache.h65
-rw-r--r--indra/newview/lltexturefetch.cpp1056
-rw-r--r--indra/newview/lltexturefetch.h37
-rw-r--r--indra/newview/lltextureinfo.cpp290
-rw-r--r--indra/newview/lltextureinfo.h80
-rw-r--r--indra/newview/lltextureinfodetails.cpp40
-rw-r--r--indra/newview/lltextureinfodetails.h58
-rw-r--r--indra/newview/lltexturestats.cpp61
-rw-r--r--indra/newview/lltexturestats.h41
-rw-r--r--indra/newview/lltexturestatsuploader.cpp59
-rw-r--r--indra/newview/lltexturestatsuploader.h48
-rw-r--r--indra/newview/lltextureview.cpp332
-rw-r--r--indra/newview/lltextureview.h27
-rw-r--r--indra/newview/llurldispatcher.cpp8
-rw-r--r--indra/newview/llviewercamera.cpp16
-rw-r--r--indra/newview/llviewercamera.h14
-rw-r--r--indra/newview/llviewercontrol.cpp9
-rw-r--r--indra/newview/llviewerdisplay.cpp3
-rw-r--r--indra/newview/llviewermenu.cpp47
-rw-r--r--indra/newview/llviewerobject.cpp2
-rw-r--r--indra/newview/llviewerobject.h2
-rw-r--r--indra/newview/llviewerobjectlist.cpp8
-rw-r--r--indra/newview/llviewerregion.cpp4
-rw-r--r--indra/newview/llviewerstats.cpp28
-rw-r--r--indra/newview/llviewerstats.h4
-rw-r--r--indra/newview/llviewertexture.cpp831
-rw-r--r--indra/newview/llviewertexture.h132
-rw-r--r--indra/newview/llviewertexturelist.cpp177
-rw-r--r--indra/newview/llviewertexturelist.h23
-rw-r--r--indra/newview/llviewerwindow.cpp15
-rw-r--r--indra/newview/llviewerwindow.h2
-rw-r--r--indra/newview/llvlcomposition.cpp13
-rw-r--r--indra/newview/llvoavatar.cpp6
-rw-r--r--indra/newview/llvoavatar.h2
-rw-r--r--indra/newview/llvoavatarself.cpp83
-rw-r--r--indra/newview/llvoavatarself.h2
-rw-r--r--indra/newview/llvoclouds.cpp2
-rw-r--r--indra/newview/llvoclouds.h2
-rw-r--r--indra/newview/llvograss.cpp2
-rw-r--r--indra/newview/llvograss.h2
-rw-r--r--indra/newview/llvoground.cpp2
-rw-r--r--indra/newview/llvoground.h2
-rw-r--r--indra/newview/llvopartgroup.cpp2
-rw-r--r--indra/newview/llvopartgroup.h2
-rw-r--r--indra/newview/llvosky.cpp4
-rw-r--r--indra/newview/llvosky.h2
-rw-r--r--indra/newview/llvosurfacepatch.cpp2
-rw-r--r--indra/newview/llvosurfacepatch.h2
-rw-r--r--indra/newview/llvotextbubble.cpp2
-rw-r--r--indra/newview/llvotextbubble.h2
-rw-r--r--indra/newview/llvotree.cpp2
-rw-r--r--indra/newview/llvotree.h2
-rw-r--r--indra/newview/llvotreenew.h2
-rw-r--r--indra/newview/llvovolume.cpp193
-rw-r--r--indra/newview/llvovolume.h7
-rw-r--r--indra/newview/llvowater.cpp2
-rw-r--r--indra/newview/llvowater.h2
-rw-r--r--indra/newview/llwearablelist.cpp5
-rw-r--r--indra/newview/llwearablelist.h1
-rw-r--r--indra/newview/llworldmap.cpp1174
-rw-r--r--indra/newview/llworldmap.h332
-rw-r--r--indra/newview/llworldmapmessage.cpp261
-rw-r--r--indra/newview/llworldmapmessage.h83
-rw-r--r--indra/newview/llworldmapview.cpp1242
-rw-r--r--indra/newview/llworldmapview.h51
-rw-r--r--indra/newview/llworldmipmap.cpp275
-rw-r--r--indra/newview/llworldmipmap.h100
-rw-r--r--indra/newview/pipeline.cpp10
-rw-r--r--indra/newview/skins/default/textures/map_avatar_32.tgabin0 -> 2894 bytes
-rw-r--r--indra/newview/skins/default/textures/map_avatar_above_32.tgabin0 -> 2909 bytes
-rw-r--r--indra/newview/skins/default/textures/map_avatar_below_32.tgabin0 -> 3037 bytes
-rw-r--r--indra/newview/skins/default/textures/map_avatar_you_32.tgabin0 -> 3395 bytes
-rw-r--r--indra/newview/skins/default/xui/en/floater_world_map.xml33
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml70
-rw-r--r--indra/newview/tests/lltextureinfo_test.cpp284
-rw-r--r--indra/newview/tests/lltextureinfodetails_test.cpp98
-rw-r--r--indra/newview/tests/lltexturestatsuploader_test.cpp156
-rw-r--r--indra/newview/tests/llworldmap_test.cpp523
-rw-r--r--indra/newview/tests/llworldmipmap_test.cpp176
141 files changed, 8326 insertions, 4019 deletions
diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp
index 88cd77f7af..0ee378f3b8 100644
--- a/indra/llcharacter/llheadrotmotion.cpp
+++ b/indra/llcharacter/llheadrotmotion.cpp
@@ -251,10 +251,13 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
mLastHeadRot = head_rot_local;
// Set the head rotation.
- LLQuaternion torsoRotLocal = mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
- head_rot_local = head_rot_local * ~torsoRotLocal;
- mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
- mHeadState->setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local));
+ if(mNeckState->getJoint() && mNeckState->getJoint()->getParent())
+ {
+ LLQuaternion torsoRotLocal = mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
+ head_rot_local = head_rot_local * ~torsoRotLocal;
+ mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
+ mHeadState->setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local));
+ }
return TRUE;
}
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 669afc5330..ed70b1d9f2 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -57,7 +57,7 @@ void ll_init_apr()
if(!LLAPRFile::sAPRFilePoolp)
{
- LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool() ;
+ LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
}
}
@@ -99,13 +99,12 @@ void ll_cleanup_apr()
//
//LLAPRPool
//
-LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
-{
- mParent = parent ;
- mReleasePoolFlag = releasePoolFlag ;
- mMaxSize = size ;
- mPool = NULL ;
-
+LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
+ : mParent(parent),
+ mReleasePoolFlag(releasePoolFlag),
+ mMaxSize(size),
+ mPool(NULL)
+{
createAPRPool() ;
}
@@ -148,31 +147,65 @@ void LLAPRPool::releaseAPRPool()
}
}
+//virtual
apr_pool_t* LLAPRPool::getAPRPool()
+{
+ return mPool ;
+}
+
+LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
+ : LLAPRPool(parent, size, releasePoolFlag),
+ mNumActiveRef(0),
+ mNumTotalRef(0),
+ mMutexPool(NULL),
+ mMutexp(NULL)
{
- if(!mPool)
+ //create mutex
+ if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
{
- createAPRPool() ;
+ apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
+ apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
}
-
- return mPool ;
}
-LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)
- : LLAPRPool(parent, size, releasePoolFlag)
+
+LLVolatileAPRPool::~LLVolatileAPRPool()
{
- mNumActiveRef = 0 ;
- mNumTotalRef = 0 ;
+ //delete mutex
+ if(mMutexp)
+ {
+ apr_thread_mutex_destroy(mMutexp);
+ apr_pool_destroy(mMutexPool);
+ }
}
-apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
+//
+//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+//
+//virtual
+apr_pool_t* LLVolatileAPRPool::getAPRPool()
{
+ return LLVolatileAPRPool::getVolatileAPRPool() ;
+}
+
+apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()
+{
+ LLScopedLock lock(mMutexp) ;
+
mNumTotalRef++ ;
mNumActiveRef++ ;
- return getAPRPool() ;
+
+ if(!mPool)
+ {
+ createAPRPool() ;
+ }
+
+ return mPool ;
}
void LLVolatileAPRPool::clearVolatileAPRPool()
{
+ LLScopedLock lock(mMutexp) ;
+
if(mNumActiveRef > 0)
{
mNumActiveRef--;
@@ -251,10 +284,9 @@ void LLScopedLock::unlock()
bool ll_apr_warn_status(apr_status_t status)
{
if(APR_SUCCESS == status) return false;
-#ifndef LL_WINDOWS
char buf[MAX_STRING]; /* Flawfinder: ignore */
- LL_WARNS_ONCE("APR") << "APR: " << apr_strerror(status, buf, MAX_STRING) << LL_ENDL;
-#endif
+ apr_strerror(status, buf, MAX_STRING);
+ LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
return true;
}
@@ -268,10 +300,18 @@ void ll_apr_assert_status(apr_status_t status)
// LLAPRFile functions
//
LLAPRFile::LLAPRFile()
+ : mFile(NULL),
+ mCurrentFilePoolp(NULL)
+{
+}
+
+LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
+ : mFile(NULL),
+ mCurrentFilePoolp(NULL)
{
- mFile = NULL ;
- mCurrentFilePoolp = NULL ;
+ open(filename, flags, pool);
}
+
LLAPRFile::~LLAPRFile()
{
close() ;
@@ -295,11 +335,40 @@ apr_status_t LLAPRFile::close()
return ret ;
}
-apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep)
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
{
apr_status_t s ;
- s = open(filename, flags, pool ? pool->getVolatileAPRPool() : NULL, sizep) ;
+
+ //check if already open some file
+ llassert_always(!mFile) ;
+ llassert_always(!mCurrentFilePoolp) ;
+ apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
+ s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
+
+ if (s != APR_SUCCESS || !mFile)
+ {
+ mFile = NULL ;
+
+ if (sizep)
+ {
+ *sizep = 0;
+ }
+ }
+ else if (sizep)
+ {
+ S32 file_size = 0;
+ apr_off_t offset = 0;
+ if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
+ {
+ llassert_always(offset <= 0x7fffffff);
+ file_size = (S32)offset;
+ offset = 0;
+ apr_file_seek(mFile, APR_SET, &offset);
+ }
+ *sizep = file_size;
+ }
+
if(!mCurrentFilePoolp)
{
mCurrentFilePoolp = pool ;
@@ -312,40 +381,25 @@ apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filenam
return s ;
}
-apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool, S32* sizep)
+
+//use gAPRPoolp.
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
{
apr_status_t s;
//check if already open some file
llassert_always(!mFile) ;
llassert_always(!mCurrentFilePoolp) ;
+ llassert_always(use_global_pool) ; //be aware of using gAPRPoolp.
- s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(pool));
+ s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);
if (s != APR_SUCCESS || !mFile)
{
mFile = NULL ;
close() ;
- if (sizep)
- {
- *sizep = 0;
- }
return s;
}
- if (sizep)
- {
- S32 file_size = 0;
- apr_off_t offset = 0;
- if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
- {
- llassert_always(offset <= 0x7fffffff);
- file_size = (S32)offset;
- offset = 0;
- apr_file_seek(mFile, APR_SET, &offset);
- }
- *sizep = file_size;
- }
-
return s;
}
@@ -369,6 +423,7 @@ S32 LLAPRFile::read(void *buf, S32 nbytes)
apr_status_t s = apr_file_read(mFile, buf, &sz);
if (s != APR_SUCCESS)
{
+ ll_apr_warn_status(s);
return 0;
}
else
@@ -386,6 +441,7 @@ S32 LLAPRFile::write(const void *buf, S32 nbytes)
apr_status_t s = apr_file_write(mFile, buf, &sz);
if (s != APR_SUCCESS)
{
+ ll_apr_warn_status(s);
return 0;
}
else
@@ -434,6 +490,8 @@ apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool
s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
if (s != APR_SUCCESS || !file_handle)
{
+ ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
file_handle = NULL ;
close(file_handle, pool) ;
return NULL;
@@ -464,6 +522,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
}
if (s != APR_SUCCESS)
{
+ ll_apr_warn_status(s);
return -1;
}
else
@@ -501,6 +560,8 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
apr_status_t s = apr_file_read(file_handle, buf, &bytes_read);
if (s != APR_SUCCESS)
{
+ LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL;
+ ll_apr_warn_status(s);
bytes_read = 0;
}
else
@@ -549,6 +610,8 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);
if (s != APR_SUCCESS)
{
+ LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL;
+ ll_apr_warn_status(s);
bytes_written = 0;
}
else
@@ -575,8 +638,8 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
if (s != APR_SUCCESS)
{
- LL_DEBUGS("APR") << "LLAPRFile::remove failed on file: " << filename << LL_ENDL;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL;
return false;
}
return true;
@@ -593,8 +656,8 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname,
if (s != APR_SUCCESS)
{
- LL_DEBUGS("APR") << "LLAPRFile::rename failed on file: " << filename << LL_ENDL;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL;
return false;
}
return true;
@@ -667,8 +730,8 @@ bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
if (s != APR_SUCCESS)
{
- LL_DEBUGS("APR") << "LLAPRFile::makeDir failed on file: " << dirname << LL_ENDL;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
return false;
}
return true;
@@ -685,8 +748,8 @@ bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
if (s != APR_SUCCESS)
{
- LL_DEBUGS("APR") << "LLAPRFile::removeDir failed on file: " << dirname << LL_ENDL;
ll_apr_warn_status(s);
+ LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL;
return false;
}
return true;
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 63130a89fc..a1a4c6db4a 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -70,9 +70,9 @@ class LLAPRPool
{
public:
LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
- ~LLAPRPool() ;
+ virtual ~LLAPRPool() ;
- apr_pool_t* getAPRPool() ;
+ virtual apr_pool_t* getAPRPool() ;
apr_status_t getStatus() {return mStatus ; }
protected:
@@ -95,18 +95,21 @@ protected:
class LLVolatileAPRPool : public LLAPRPool
{
public:
- LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
- ~LLVolatileAPRPool(){}
+ LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+ virtual ~LLVolatileAPRPool();
- apr_pool_t* getVolatileAPRPool() ;
-
+ /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+ apr_pool_t* getVolatileAPRPool() ;
void clearVolatileAPRPool() ;
BOOL isFull() ;
- BOOL isEmpty() {return !mNumActiveRef ;}
+
private:
S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
- S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
+ S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating.
+
+ apr_thread_mutex_t *mMutexp;
+ apr_pool_t *mMutexPool;
} ;
/**
@@ -192,18 +195,21 @@ typedef LLAtomic32<S32> LLAtomicS32;
// 1, a temperary pool passed to an APRFile function, which is used within this function and only once.
// 2, a global pool.
//
-class LLAPRFile
+
+class LLAPRFile : boost::noncopyable
{
+ // make this non copyable since a copy closes the file
private:
apr_file_t* mFile ;
LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.
public:
LLAPRFile() ;
+ LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL);
~LLAPRFile() ;
-
- apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
- apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
+
+ apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL);
+ apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp.
apr_status_t close() ;
// Returns actual offset, -1 if seek fails
@@ -217,8 +223,8 @@ public:
apr_file_t* getFileHandle() {return mFile;}
private:
- apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
-
+ apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
+
//
//*******************************************************************************************************************************
//static components
diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index 3db5c36545..395d298887 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -42,7 +42,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
LLThread(name),
mThreaded(threaded),
mIdleThread(TRUE),
- mNextHandle(0)
+ mNextHandle(0),
+ mStarted(FALSE)
{
if (mThreaded)
{
@@ -53,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
// MAIN THREAD
LLQueuedThread::~LLQueuedThread()
{
+ if (!mThreaded)
+ {
+ endThread();
+ }
shutdown();
// ~LLThread() will be called here
}
@@ -106,6 +111,11 @@ void LLQueuedThread::shutdown()
// virtual
S32 LLQueuedThread::update(U32 max_time_ms)
{
+ if (!mStarted)
+ {
+ startThread();
+ mStarted = TRUE;
+ }
return updateQueue(max_time_ms);
}
@@ -452,26 +462,12 @@ S32 LLQueuedThread::processNextRequest()
}
}
- S32 res;
S32 pending = getPending();
- if (pending == 0)
- {
- if (isQuitting())
- {
- res = -1; // exit thread
- }
- else
- {
- res = 0;
- }
- }
- else
- {
- res = pending;
- }
- return res;
+
+ return pending;
}
+// virtual
bool LLQueuedThread::runCondition()
{
// mRunCondition must be locked here
@@ -481,35 +477,53 @@ bool LLQueuedThread::runCondition()
return true;
}
+// virtual
void LLQueuedThread::run()
{
+ // call checPause() immediately so we don't try to do anything before the class is fully constructed
+ checkPause();
+ startThread();
+ mStarted = TRUE;
+
while (1)
{
// this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
checkPause();
- if(isQuitting())
+ if (isQuitting())
+ {
+ endThread();
break;
-
- //llinfos << "QUEUED THREAD RUNNING, queue size = " << mRequestQueue.size() << llendl;
+ }
mIdleThread = FALSE;
+
+ threadedUpdate();
int res = processNextRequest();
if (res == 0)
{
mIdleThread = TRUE;
+ ms_sleep(1);
}
-
- if (res < 0) // finished working and want to exit
- {
- break;
- }
-
//LLThread::yield(); // thread should yield after each request
}
+ llinfos << "LLQueuedThread " << mName << " EXITING." << llendl;
+}
- llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl;
+// virtual
+void LLQueuedThread::startThread()
+{
+}
+
+// virtual
+void LLQueuedThread::endThread()
+{
+}
+
+// virtual
+void LLQueuedThread::threadedUpdate()
+{
}
//============================================================================
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index 3ba43e1e07..bcd154da0b 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -165,6 +165,9 @@ private:
virtual bool runCondition(void);
virtual void run(void);
+ virtual void startThread(void);
+ virtual void endThread(void);
+ virtual void threadedUpdate(void);
protected:
handle_t generateHandle();
@@ -199,6 +202,7 @@ public:
protected:
BOOL mThreaded; // if false, run on main thread and do updates during update()
+ BOOL mStarted; // required when mThreaded is false to call startThread() from update()
LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f25339f48d..1470dca14c 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -33,9 +33,7 @@
#ifndef LL_LLTHREAD_H
#define LL_LLTHREAD_H
-#include "llapr.h"
#include "llapp.h"
-
#include "apr_thread_cond.h"
class LLThread;
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 5dda600755..82c736266d 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -201,6 +201,7 @@ LLWorkerClass::~LLWorkerClass()
{
llassert_always(!(mWorkFlags & WCF_WORKING));
llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
+ llassert_always(!mMutex.isLocked());
if (mRequestHandle != LLWorkerThread::nullHandle())
{
LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 19407f4463..4a4cd6c85f 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -52,6 +52,7 @@ class LLWorkerClass;
class LLWorkerThread : public LLQueuedThread
{
+ friend class LLWorkerClass;
public:
class WorkRequest : public LLQueuedThread::QueuedRequest
{
@@ -92,8 +93,11 @@ public:
handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
- void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug
+
+private:
+ void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
+
};
//============================================================================
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 0635ddd5f5..22be4078a1 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -3,6 +3,7 @@
project(llimage)
include(00-Common)
+include(LLAddBuildTest)
include(LLCommon)
include(LLImage)
include(LLMath)
@@ -59,3 +60,6 @@ target_link_libraries(llimage
${PNG_LIBRARIES}
${ZLIB_LIBRARIES}
)
+
+# Add tests
+#ADD_BUILD_TEST(llimageworker llimage)
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 9bbc55509d..9cb005898d 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -55,13 +55,9 @@ std::string LLImage::sLastErrorMessage;
LLMutex* LLImage::sMutex = NULL;
//static
-void LLImage::initClass(LLWorkerThread* workerthread)
+void LLImage::initClass()
{
sMutex = new LLMutex(NULL);
- if (workerthread)
- {
- LLImageWorker::initImageWorker(workerthread);
- }
LLImageJ2C::openDSO();
}
@@ -69,7 +65,6 @@ void LLImage::initClass(LLWorkerThread* workerthread)
void LLImage::cleanupClass()
{
LLImageJ2C::closeDSO();
- LLImageWorker::cleanupImageWorker();
delete sMutex;
sMutex = NULL;
}
@@ -316,6 +311,21 @@ void LLImageRaw::deleteData()
LLImageBase::deleteData();
}
+void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
+{
+ if(data == getData())
+ {
+ return ;
+ }
+
+ deleteData();
+
+ LLImageBase::setSize(width, height, components) ;
+ LLImageBase::setDataAndSize(data, width * height * components) ;
+
+ sGlobalRawMemory += getDataSize();
+}
+
BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
{
if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
@@ -816,6 +826,51 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
}
}
+//scale down image by not blending a pixel with its neighbors.
+BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
+{
+ LLMemType mt1(mMemType);
+
+ S8 c = getComponents() ;
+ llassert((1 == c) || (3 == c) || (4 == c) );
+
+ S32 old_width = getWidth();
+ S32 old_height = getHeight();
+
+ S32 new_data_size = old_width * new_height * c ;
+ llassert_always(new_data_size > 0);
+
+ F32 ratio_x = (F32)old_width / new_width ;
+ F32 ratio_y = (F32)old_height / new_height ;
+ if( ratio_x < 1.0f || ratio_y < 1.0f )
+ {
+ return TRUE; // Nothing to do.
+ }
+ ratio_x -= 1.0f ;
+ ratio_y -= 1.0f ;
+
+ U8* new_data = new U8[new_data_size] ;
+ llassert_always(new_data != NULL) ;
+
+ U8* old_data = getData() ;
+ S32 i, j, k, s, t;
+ for(i = 0, s = 0, t = 0 ; i < new_height ; i++)
+ {
+ for(j = 0 ; j < new_width ; j++)
+ {
+ for(k = 0 ; k < c ; k++)
+ {
+ new_data[s++] = old_data[t++] ;
+ }
+ t += (S32)(ratio_x * c + 0.1f) ;
+ }
+ t += (S32)(ratio_y * old_width * c + 0.1f) ;
+ }
+
+ setDataAndSize(new_data, new_width, new_height, c) ;
+
+ return TRUE ;
+}
BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
{
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 8108553107..686f583886 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -50,7 +50,8 @@ const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE;
const S32 MAX_IMAGE_COMPONENTS = 8;
const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS;
-// Note! These CANNOT be changed without invalidating the viewer VFS files, I think?
+// Note! These CANNOT be changed without modifying simulator code
+// *TODO: change both to 1024 when SIM texture fetching is deprecated
const S32 FIRST_PACKET_SIZE = 600;
const S32 MAX_IMG_PACKET_SIZE = 1000;
@@ -61,7 +62,6 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;
class LLImageFormatted;
class LLImageRaw;
class LLColor4U;
-class LLWorkerThread;
typedef enum e_image_codec
{
@@ -82,7 +82,7 @@ typedef enum e_image_codec
class LLImage
{
public:
- static void initClass(LLWorkerThread* workerthread);
+ static void initClass();
static void cleanupClass();
static const std::string& getLastError();
@@ -131,7 +131,7 @@ public:
protected:
// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
- void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; };
+ void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }
public:
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
@@ -192,6 +192,7 @@ public:
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
+ BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
// Fill the buffer with a constant color
void fill( const LLColor4U& color );
@@ -240,6 +241,8 @@ protected:
U8 fastFractionalMult(U8 a,U8 b);
+ void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
+
public:
static S32 sGlobalRawMemory;
static S32 sRawImageCount;
@@ -310,7 +313,7 @@ protected:
protected:
S8 mCodec;
S8 mDecoding;
- S8 mDecoded;
+ S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC
S8 mDiscardLevel;
public:
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp
index 1ce4517a0d..0aa6840ff6 100644
--- a/indra/llimage/llimagedxt.cpp
+++ b/indra/llimage/llimagedxt.cpp
@@ -264,6 +264,8 @@ void LLImageDXT::setFormat()
// virtual
BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
{
+ // *TODO: Test! This has been tweaked since its intial inception,
+ // but we don't use it any more!
llassert_always(raw_image);
if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
@@ -274,8 +276,17 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
S32 width = getWidth(), height = getHeight();
S32 ncomponents = getComponents();
+ U8* data = NULL;
+ if (mDiscardLevel >= 0)
+ {
+ data = getData() + getMipOffset(mDiscardLevel);
+ calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
+ }
+ else
+ {
+ data = getData() + getMipOffset(0);
+ }
S32 image_size = formatBytes(mFileFormat, width, height);
- U8* data = getData() + getMipOffset(0);
if ((!getData()) || (data + image_size > getData() + getDataSize()))
{
@@ -300,10 +311,8 @@ BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
llerrs << "Request for invalid discard level" << llendl;
}
U8* data = getData() + getMipOffset(discard);
- // I'm not sure these are the correct initial values for height and width,
- // but previously they were being used uninitialized. JC
- S32 width = raw->getWidth();
- S32 height = raw->getHeight();
+ S32 width = 0;
+ S32 height = 0;
calcDiscardWidthHeight(discard, mFileFormat, width, height);
raw = new LLImageRaw(data, width, height, getComponents());
return TRUE;
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 363486fb9c..49017cc508 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -277,6 +277,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
}
+// Returns TRUE to mean done, whether successful or not.
BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
{
LLMemType mt1(mMemType);
@@ -289,7 +290,7 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
if (!getData() || (getDataSize() < 16))
{
setLastError("LLImageJ2C uninitialized");
- res = FALSE;
+ res = TRUE; // done
}
else
{
@@ -342,7 +343,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text,
//static
S32 LLImageJ2C::calcHeaderSizeJ2C()
{
- return 600; //2048; // ??? hack... just needs to be >= actual header size...
+ return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size...
}
//static
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index fa0dd3ff05..79ea79cc07 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -188,6 +188,7 @@ void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo)
}
+// Returns true when done, whether or not decode was successful.
BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
{
llassert_always(raw_image);
@@ -198,7 +199,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImageJPEG trying to decode an image with no data!");
- return FALSE;
+ return TRUE; // done
}
S32 row_stride = 0;
@@ -226,7 +227,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
if(setjmp(sSetjmpBuffer))
{
jpeg_destroy_decompress(&cinfo);
- return FALSE;
+ return TRUE; // done
}
try
{
@@ -320,7 +321,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
catch (int)
{
jpeg_destroy_decompress(&cinfo);
- return FALSE;
+ return TRUE; // done
}
// Check to see whether any corrupt-data warnings occurred
@@ -328,7 +329,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
{
// TODO: extract the warning to find out what went wrong.
setLastError( "Unable to decode JPEG image.");
- return FALSE;
+ return TRUE; // done
}
return TRUE;
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 532e996188..86d41515e7 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -37,152 +37,138 @@
//----------------------------------------------------------------------------
-//static
-LLWorkerThread* LLImageWorker::sWorkerThread = NULL;
-S32 LLImageWorker::sCount = 0;
+// MAIN THREAD
+LLImageDecodeThread::LLImageDecodeThread(bool threaded)
+ : LLQueuedThread("imagedecode", threaded)
+{
+ mCreationMutex = new LLMutex(getAPRPool());
+}
-//static
-void LLImageWorker::initImageWorker(LLWorkerThread* workerthread)
+// MAIN THREAD
+// virtual
+S32 LLImageDecodeThread::update(U32 max_time_ms)
{
- sWorkerThread = workerthread;
+ LLMutexLock lock(mCreationMutex);
+ for (creation_list_t::iterator iter = mCreationList.begin();
+ iter != mCreationList.end(); ++iter)
+ {
+ creation_info& info = *iter;
+ ImageRequest* req = new ImageRequest(info.handle, info.image,
+ info.priority, info.discard, info.needs_aux,
+ info.responder);
+ addRequest(req);
+ }
+ mCreationList.clear();
+ S32 res = LLQueuedThread::update(max_time_ms);
+ return res;
}
-//static
-void LLImageWorker::cleanupImageWorker()
+LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
+{
+ LLMutexLock lock(mCreationMutex);
+ handle_t handle = generateHandle();
+ mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
+ return handle;
+}
+
+// Used by unit test only
+// Returns the size of the mutex guarded list as an indication of sanity
+S32 LLImageDecodeThread::tut_size()
+{
+ LLMutexLock lock(mCreationMutex);
+ S32 res = mCreationList.size();
+ return res;
+}
+
+LLImageDecodeThread::Responder::~Responder()
{
}
//----------------------------------------------------------------------------
-LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority,
- S32 discard,
- LLPointer<LLResponder> responder)
- : LLWorkerClass(sWorkerThread, "Image"),
+LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux,
+ LLImageDecodeThread::Responder* responder)
+ : LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
mFormattedImage(image),
- mDecodedType(-1),
mDiscardLevel(discard),
- mPriority(priority),
+ mNeedsAux(needs_aux),
+ mDecodedRaw(FALSE),
+ mDecodedAux(FALSE),
mResponder(responder)
{
- ++sCount;
}
-LLImageWorker::~LLImageWorker()
+LLImageDecodeThread::ImageRequest::~ImageRequest()
{
- mDecodedImage = NULL;
+ mDecodedImageRaw = NULL;
+ mDecodedImageAux = NULL;
mFormattedImage = NULL;
- --sCount;
}
//----------------------------------------------------------------------------
-//virtual, main thread
-void LLImageWorker::startWork(S32 param)
-{
- llassert_always(mDecodedImage.isNull());
- mDecodedType = -1;
-}
-bool LLImageWorker::doWork(S32 param)
+// Returns true when done, whether or not decode was successful.
+bool LLImageDecodeThread::ImageRequest::processRequest()
{
- bool decoded = false;
- if(mDecodedImage.isNull())
+ const F32 decode_time_slice = .1f;
+ bool done = true;
+ if (!mDecodedRaw && mFormattedImage.notNull())
{
- if (!mFormattedImage->updateData())
- {
- mDecodedType = -2; // failed
- return true;
- }
- if (mDiscardLevel >= 0)
+ // Decode primary channels
+ if (mDecodedImageRaw.isNull())
{
- mFormattedImage->setDiscardLevel(mDiscardLevel);
- }
- if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
- {
- decoded = true; // failed
- }
- else
- {
- mDecodedImage = new LLImageRaw(); // allow possibly smaller size set during decoding
+ // parse formatted header
+ if (!mFormattedImage->updateData())
+ {
+ return true; // done (failed)
+ }
+ if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
+ {
+ return true; // done (failed)
+ }
+ if (mDiscardLevel >= 0)
+ {
+ mFormattedImage->setDiscardLevel(mDiscardLevel);
+ }
+ mDecodedImageRaw = new LLImageRaw(mFormattedImage->getWidth(),
+ mFormattedImage->getHeight(),
+ mFormattedImage->getComponents());
}
+ done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms
+ mDecodedRaw = done;
}
- if (!decoded)
+ if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull())
{
- if (param == 0)
- {
- // Decode primary channels
- decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
- }
- else
+ // Decode aux channel
+ if (!mDecodedImageAux)
{
- // Decode aux channel
- decoded = mFormattedImage->decodeChannels(mDecodedImage, .1f, param, param); // 1ms
+ mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(),
+ mFormattedImage->getHeight(),
+ 1);
}
+ done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms
+ mDecodedAux = done;
}
- if (decoded)
- {
- // Call the callback immediately; endWork doesn't get called until ckeckWork
- if (mResponder.notNull())
- {
- bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
- mResponder->completed(success);
- }
- }
- return decoded;
-}
-void LLImageWorker::endWork(S32 param, bool aborted)
-{
- if (mDecodedType != -2)
- {
- mDecodedType = aborted ? -2 : param;
- }
+ return done;
}
-//----------------------------------------------------------------------------
-
-
-BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
+void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
{
- // For most codecs, only mDiscardLevel data is available.
- // (see LLImageDXT for exception)
- if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
- {
- llerrs << "Request for invalid discard level" << llendl;
- }
- checkWork();
- if (mDecodedType == -2)
+ if (mResponder.notNull())
{
- return TRUE; // aborted, done
- }
- if (mDecodedType != channel)
- {
- if (!haveWork())
- {
- addWork(channel, mPriority);
- }
- return FALSE;
- }
- else
- {
- llassert_always(!haveWork());
- llassert_always(mDecodedType == channel);
- raw = mDecodedImage; // smart pointer acquires ownership of data
- mDecodedImage = NULL;
- return TRUE;
+ bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
+ mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux);
}
+ // Will automatically be deleted
}
-BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard)
+// Used by unit test only
+// Checks that a responder exists for this instance so that something can happen when completion is reached
+bool LLImageDecodeThread::ImageRequest::tut_isOK()
{
- if (mFormattedImage->getCodec() == IMG_CODEC_DXT)
- {
- // special case
- LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
- return imagedxt->getMipData(raw, discard);
- }
- else
- {
- return requestDecodedAuxData(raw, 0, discard);
- }
+ return mResponder.notNull();
}
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index 0d66695d6e..6a5b86a277 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -37,49 +37,72 @@
#include "llpointer.h"
#include "llworkerthread.h"
-class LLImageWorker : public LLWorkerClass
+class LLImageDecodeThread : public LLQueuedThread
{
public:
- static void initImageWorker(LLWorkerThread* workerthread);
- static void cleanupImageWorker();
-
-public:
- static LLWorkerThread* getWorkerThread() { return sWorkerThread; }
-
- // LLWorkerThread
-public:
- LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard,
- LLPointer<LLResponder> responder);
- ~LLImageWorker();
-
- // called from WORKER THREAD, returns TRUE if done
- /*virtual*/ bool doWork(S32 param);
-
- BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
- BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
- void releaseDecodedData();
- void cancelDecode();
+ class Responder : public LLThreadSafeRefCount
+ {
+ protected:
+ virtual ~Responder();
+ public:
+ virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
+ };
-private:
- // called from MAIN THREAD
- /*virtual*/ void startWork(S32 param); // called from addWork()
- /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork()
+ class ImageRequest : public LLQueuedThread::QueuedRequest
+ {
+ protected:
+ virtual ~ImageRequest(); // use deleteRequest()
+
+ public:
+ ImageRequest(handle_t handle, LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux,
+ LLImageDecodeThread::Responder* responder);
-protected:
- LLPointer<LLImageFormatted> mFormattedImage;
- LLPointer<LLImageRaw> mDecodedImage;
- S32 mDecodedType;
- S32 mDiscardLevel;
+ /*virtual*/ bool processRequest();
+ /*virtual*/ void finishRequest(bool completed);
-private:
- U32 mPriority;
- LLPointer<LLResponder> mResponder;
+ // Used by unit tests to check the consitency of the request instance
+ bool tut_isOK();
+
+ private:
+ // input
+ LLPointer<LLImageFormatted> mFormattedImage;
+ S32 mDiscardLevel;
+ BOOL mNeedsAux;
+ // output
+ LLPointer<LLImageRaw> mDecodedImageRaw;
+ LLPointer<LLImageRaw> mDecodedImageAux;
+ BOOL mDecodedRaw;
+ BOOL mDecodedAux;
+ LLPointer<LLImageDecodeThread::Responder> mResponder;
+ };
-protected:
- static LLWorkerThread* sWorkerThread;
-
public:
- static S32 sCount;
+ LLImageDecodeThread(bool threaded = true);
+ handle_t decodeImage(LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux,
+ Responder* responder);
+ S32 update(U32 max_time_ms);
+
+ // Used by unit tests to check the consistency of the thread instance
+ S32 tut_size();
+
+private:
+ struct creation_info
+ {
+ handle_t handle;
+ LLPointer<LLImageFormatted> image;
+ U32 priority;
+ S32 discard;
+ BOOL needs_aux;
+ LLPointer<Responder> responder;
+ creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r)
+ : handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r)
+ {}
+ };
+ typedef std::list<creation_info> creation_list_t;
+ creation_list_t mCreationList;
+ LLMutex* mCreationMutex;
};
#endif
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
new file mode 100644
index 0000000000..cc44696a45
--- /dev/null
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -0,0 +1,260 @@
+/**
+ * @file llimageworker_test.cpp
+ * @author Merov Linden
+ * @date 2009-04-28
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include <list>
+#include <map>
+#include <algorithm>
+// Class to test
+#include "../llimageworker.h"
+// For timer class
+#include "../llcommon/lltimer.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+LLImageBase::LLImageBase() {}
+LLImageBase::~LLImageBase() {}
+void LLImageBase::dump() { }
+void LLImageBase::sanityCheck() { }
+void LLImageBase::deleteData() { }
+U8* LLImageBase::allocateData(S32 size) { return NULL; }
+U8* LLImageBase::reallocateData(S32 size) { return NULL; }
+
+LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) { }
+LLImageRaw::~LLImageRaw() { }
+void LLImageRaw::deleteData() { }
+U8* LLImageRaw::allocateData(S32 size) { return NULL; }
+U8* LLImageRaw::reallocateData(S32 size) { return NULL; }
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+
+ // Note: We derive the responder class for 2 reasons:
+ // 1. It's a pure virtual class and we can't compile without completed() being implemented
+ // 2. We actually need a responder to test that the thread work test completed
+ // We implement this making no assumption on what's done in the thread or worker
+ // though, just that the responder's completed() method is called in the end.
+ // Note on responders: responders are ref counted and *will* be deleted by the request they are
+ // attached to when the queued request is deleted. The recommended way of using them is to
+ // create them when creating a request, put a callback method in completed() and not rely on
+ // anything to survive in the responder object once completed() has been called. Let the request
+ // do the deletion and clean up itself.
+ class responder_test : public LLImageDecodeThread::Responder
+ {
+ public:
+ responder_test(bool* res)
+ {
+ done = res;
+ *done = false;
+ }
+ virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
+ {
+ *done = true;
+ }
+ private:
+ // This is what can be thought of as the minimal implementation of a responder
+ // Done will be switched to true when completed() is called and can be tested
+ // outside the responder. A better way of doing this is to store a callback here.
+ bool* done;
+ };
+
+ // Test wrapper declaration : decode thread
+ struct imagedecodethread_test
+ {
+ // Instance to be tested
+ LLImageDecodeThread* mThread;
+
+ // Constructor and destructor of the test wrapper
+ imagedecodethread_test()
+ {
+ mThread = NULL;
+ }
+ ~imagedecodethread_test()
+ {
+ delete mThread;
+ }
+ };
+
+ // Test wrapper declaration : image worker
+ // Note: this class is not meant to be instantiated outside an LLImageDecodeThread instance
+ // but it's not a bad idea to get its public API a good shake as part of a thorough unit test set.
+ // Some gotcha with the destructor though (see below).
+ struct imagerequest_test
+ {
+ // Instance to be tested
+ LLImageDecodeThread::ImageRequest* mRequest;
+ bool done;
+
+ // Constructor and destructor of the test wrapper
+ imagerequest_test()
+ {
+ done = false;
+ mRequest = new LLImageDecodeThread::ImageRequest(0, 0,
+ LLQueuedThread::PRIORITY_NORMAL, 0, FALSE,
+ new responder_test(&done));
+ }
+ ~imagerequest_test()
+ {
+ // We should delete the object *but*, because its destructor is protected, that cannot be
+ // done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...
+ //delete mRequest;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<imagedecodethread_test> imagedecodethread_t;
+ typedef imagedecodethread_t::object imagedecodethread_object_t;
+ tut::imagedecodethread_t tut_imagedecodethread("imagedecodethread");
+
+ typedef test_group<imagerequest_test> imagerequest_t;
+ typedef imagerequest_t::object imagerequest_object_t;
+ tut::imagerequest_t tut_imagerequest("imagerequest");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLImageDecodeThread interface
+ // ---------------------------------------------------------------------------------------
+ //
+ // Note on Unit Testing Queued Thread Classes
+ //
+ // Since methods on such a class are called on a separate loop and that we can't insert tut
+ // ensure() calls in there, we exercise the class with 2 sets of tests:
+ // - 1: Test as a single threaded instance: We declare the class but ask for no thread
+ // to be spawned (easy with LLThreads since there's a boolean argument on the constructor
+ // just for that). We can then unit test each public method like we do on a normal class.
+ // - 2: Test as a threaded instance: We let the thread launch and check that its external
+ // behavior is as expected (i.e. it runs, can accept a work order and processes
+ // it). Typically though there's no guarantee that this exercises all the methods of the
+ // class which is why we also need the previous "non threaded" set of unit tests for
+ // complete coverage.
+ //
+ // ---------------------------------------------------------------------------------------
+
+ template<> template<>
+ void imagedecodethread_object_t::test<1>()
+ {
+ // Test a *non threaded* instance of the class
+ mThread = new LLImageDecodeThread(false);
+ ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL);
+ // Test that we start with an empty list right at creation
+ ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0);
+ // Insert something in the queue
+ bool done = false;
+ LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
+ // Verifies we got a valid handle
+ ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0);
+ // Verifies that we do now have something in the queued list
+ ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1);
+ // Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop)
+ S32 res = mThread->update(0);
+ // Verifies that we successfully handled the list
+ ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0);
+ // Verifies that the list is now empty
+ ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0);
+ }
+
+ template<> template<>
+ void imagedecodethread_object_t::test<2>()
+ {
+ // Test a *threaded* instance of the class
+ mThread = new LLImageDecodeThread(true);
+ ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
+ // Test that we start with an empty list right at creation
+ ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0);
+ // Insert something in the queue
+ bool done = false;
+ LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
+ // Verifies we get back a valid handle
+ ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0);
+ // Wait a little so to simulate the main thread doing something on its main loop...
+ ms_sleep(500); // 500 milliseconds
+ // Verifies that the responder has *not* been called yet in the meantime
+ ensure("LLImageDecodeThread: responder creation failed", done == false);
+ // Ask the thread to update: that means tells the queue to check itself and creates work requests
+ mThread->update(1);
+ // Wait till the thread has time to handle the work order (though it doesn't do much per work order...)
+ const U32 INCREMENT_TIME = 500; // 500 milliseconds
+ const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more
+ U32 total_time = 0;
+ while ((done == false) && (total_time < MAX_TIME))
+ {
+ ms_sleep(INCREMENT_TIME);
+ total_time += INCREMENT_TIME;
+ }
+ // Verifies that the responder has now been called
+ ensure("LLImageDecodeThread: threaded work unit not processed", done == true);
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLImageDecodeThread::ImageRequest interface
+ // ---------------------------------------------------------------------------------------
+
+ template<> template<>
+ void imagerequest_object_t::test<1>()
+ {
+ // Test that we start with a correct request at creation
+ ensure("LLImageDecodeThread::ImageRequest::ImageRequest() constructor test failed", mRequest->tut_isOK());
+ bool res = mRequest->processRequest();
+ // Verifies that we processed the request successfully
+ ensure("LLImageDecodeThread::ImageRequest::processRequest() processing request test failed", res == true);
+ // Check that we can call the finishing call safely
+ try {
+ mRequest->finishRequest(false);
+ } catch (...) {
+ fail("LLImageDecodeThread::ImageRequest::finishRequest() test failed");
+ }
+ }
+}
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index b8ef92f9a9..df4c618ac1 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -3582,7 +3582,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
if (face == -1) // ALL_SIDES
{
start_face = 0;
- end_face = getNumFaces() - 1;
+ end_face = getNumVolumeFaces() - 1;
}
else
{
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index b3087bcc3f..0ab1081200 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -64,6 +64,9 @@ const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-0
const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds
+LLTempAssetStorage::~LLTempAssetStorage()
+{
+}
///----------------------------------------------------------------------------
/// LLAssetInfo
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 56adbd5ccf..83cfdf6110 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -204,7 +204,16 @@ typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id,
LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status);
-class LLAssetStorage
+class LLTempAssetStorage
+{
+public:
+ virtual ~LLTempAssetStorage() =0;
+ virtual void addTempAssetData(const LLUUID& asset_id,
+ const LLUUID& agent_id,
+ const std::string& host_name) = 0;
+};
+
+class LLAssetStorage : public LLTempAssetStorage
{
public:
// VFS member is public because static child methods need it :(
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index a4af8e989b..14771ef6dd 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -220,7 +220,7 @@ public:
U32 report(CURLcode);
void getTransferInfo(LLCurl::TransferInfo* info);
- void prepRequest(const std::string& url, ResponderPtr, bool post = false);
+ void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, bool post = false);
const char* getErrorBuffer();
@@ -432,7 +432,9 @@ size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data
return n;
}
-void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, bool post)
+void LLCurl::Easy::prepRequest(const std::string& url,
+ const std::vector<std::string>& headers,
+ ResponderPtr responder, bool post)
{
resetState();
@@ -465,8 +467,13 @@ void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, b
{
slist_append("Connection: keep-alive");
slist_append("Keep-alive: 300");
+ // Accept and other headers
+ for (std::vector<std::string>::const_iterator iter = headers.begin();
+ iter != headers.end(); ++iter)
+ {
+ slist_append((*iter).c_str());
+ }
}
- // *FIX: should have ACCEPT headers
}
////////////////////////////////////////////////////////////////////////////
@@ -676,15 +683,18 @@ LLCurlRequest::LLCurlRequest() :
mActiveMulti(NULL),
mActiveRequestCount(0)
{
+ mThreadID = LLThread::currentID();
}
LLCurlRequest::~LLCurlRequest()
{
+ llassert_always(mThreadID == LLThread::currentID());
for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
}
void LLCurlRequest::addMulti()
{
+ llassert_always(mThreadID == LLThread::currentID());
LLCurl::Multi* multi = new LLCurl::Multi();
mMultiSet.insert(multi);
mActiveMulti = multi;
@@ -714,17 +724,20 @@ bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
{
- getByteRange(url, 0, -1, responder);
+ getByteRange(url, headers_t(), 0, -1, responder);
}
-bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length, LLCurl::ResponderPtr responder)
+bool LLCurlRequest::getByteRange(const std::string& url,
+ const headers_t& headers,
+ S32 offset, S32 length,
+ LLCurl::ResponderPtr responder)
{
LLCurl::Easy* easy = allocEasy();
if (!easy)
{
return false;
}
- easy->prepRequest(url, responder);
+ easy->prepRequest(url, headers, responder);
easy->setopt(CURLOPT_HTTPGET, 1);
if (length > 0)
{
@@ -736,14 +749,17 @@ bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length,
return res;
}
-bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::ResponderPtr responder)
+bool LLCurlRequest::post(const std::string& url,
+ const headers_t& headers,
+ const LLSD& data,
+ LLCurl::ResponderPtr responder)
{
LLCurl::Easy* easy = allocEasy();
if (!easy)
{
return false;
}
- easy->prepRequest(url, responder);
+ easy->prepRequest(url, headers, responder);
LLSDSerialize::toXML(data, easy->getInput());
S32 bytes = easy->getInput().str().length();
@@ -763,6 +779,7 @@ bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::Respo
// Note: call once per frame
S32 LLCurlRequest::process()
{
+ llassert_always(mThreadID == LLThread::currentID());
S32 res = 0;
for (curlmulti_set_t::iterator iter = mMultiSet.begin();
iter != mMultiSet.end(); )
@@ -782,6 +799,7 @@ S32 LLCurlRequest::process()
S32 LLCurlRequest::getQueued()
{
+ llassert_always(mThreadID == LLThread::currentID());
S32 queued = 0;
for (curlmulti_set_t::iterator iter = mMultiSet.begin();
iter != mMultiSet.end(); )
@@ -1002,7 +1020,7 @@ void LLCurl::initClass()
S32 mutex_count = CRYPTO_num_locks();
for (S32 i=0; i<mutex_count; i++)
{
- sSSLMutex.push_back(new LLMutex(gAPRPoolp));
+ sSSLMutex.push_back(new LLMutex(NULL));
}
CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index fbd3077cbf..32637b200e 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -188,12 +188,14 @@ namespace boost
class LLCurlRequest
{
public:
+ typedef std::vector<std::string> headers_t;
+
LLCurlRequest();
~LLCurlRequest();
void get(const std::string& url, LLCurl::ResponderPtr responder);
- bool getByteRange(const std::string& url, S32 offset, S32 length, LLCurl::ResponderPtr responder);
- bool post(const std::string& url, const LLSD& data, LLCurl::ResponderPtr responder);
+ bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
+ bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder);
S32 process();
S32 getQueued();
@@ -207,6 +209,7 @@ private:
curlmulti_set_t mMultiSet;
LLCurl::Multi* mActiveMulti;
S32 mActiveRequestCount;
+ U32 mThreadID; // debug
};
class LLCurlEasyRequest
diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp
index 5dc5932fde..db5ffaf3ee 100644
--- a/indra/llmessage/tests/llcurl_stub.cpp
+++ b/indra/llmessage/tests/llcurl_stub.cpp
@@ -20,8 +20,9 @@
*/
#include "linden_common.h"
+#include "llcurl.h"
-LLCurl::Responder::Responder()
+LLCurl::Responder::Responder() : mReferenceCount(0)
{
}
diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp
index 250fa100b6..7065c9d7e4 100644
--- a/indra/llmessage/tests/llhttpclientadapter_test.cpp
+++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp
@@ -50,7 +50,7 @@ std::vector<std::string> put_urls;
std::vector<LLSD> put_body;
std::vector<boost::intrusive_ptr<LLCurl::Responder> > put_responders;
-void LLHTTPClient::put(std::string const &url, LLSD const &body, boost::intrusive_ptr<LLCurl::Responder> responder,float)
+void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout)
{
put_urls.push_back(url);
put_responders.push_back(responder);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index e5fea5b995..f8d7ea00e0 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -43,7 +43,6 @@
#include "llmath.h"
#include "llgl.h"
#include "llrender.h"
-
//----------------------------------------------------------------------------
const F32 MIN_TEXTURE_LIFETIME = 10.f;
@@ -60,21 +59,34 @@ std::list<U32> LLImageGL::sDeadTextureList;
BOOL LLImageGL::sGlobalUseAnisotropic = FALSE;
F32 LLImageGL::sLastFrameTime = 0.f;
+BOOL LLImageGL::sAllowReadBackRaw = FALSE ;
LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
+
std::set<LLImageGL*> LLImageGL::sImageList;
-#if !LL_RELEASE_FOR_DOWNLOAD
+//****************************************************************************************************
+//The below for texture auditing use only
+//****************************************************************************************************
//-----------------------
//debug use
+BOOL gAuditTexture = FALSE ;
#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048
std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
S32 LLImageGL::sCurTexSizeBar = -1 ;
S32 LLImageGL::sCurTexPickSize = -1 ;
-LLPointer<LLImageGL> LLImageGL::sDefaultTexturep = NULL;
+LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL;
+S32 LLImageGL::sMaxCatagories = 1 ;
+
+std::vector<S32> LLImageGL::sTextureMemByCategory;
+std::vector<S32> LLImageGL::sTextureMemByCategoryBound ;
+std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ;
//------------------------
-#endif
+//****************************************************************************************************
+//End for texture auditing use only
+//****************************************************************************************************
+
//**************************************************************************************
//below are functions for debug use
//do not delete them even though they are not currently being used.
@@ -144,6 +156,60 @@ void LLImageGL::checkTexSize() const
//**************************************************************************************
//----------------------------------------------------------------------------
+BOOL is_little_endian()
+{
+ S32 a = 0x12345678;
+ U8 *c = (U8*)(&a);
+
+ return (*c == 0x78) ;
+}
+//static
+void LLImageGL::initClass(S32 num_catagories)
+{
+ sMaxCatagories = num_catagories ;
+
+ sTextureMemByCategory.resize(sMaxCatagories);
+ sTextureMemByCategoryBound.resize(sMaxCatagories) ;
+ sTextureCurMemByCategoryBound.resize(sMaxCatagories) ;
+}
+
+//static
+void LLImageGL::cleanupClass()
+{
+ sTextureMemByCategory.clear() ;
+ sTextureMemByCategoryBound.clear() ;
+ sTextureCurMemByCategoryBound.clear() ;
+}
+
+//static
+void LLImageGL::setHighlightTexture(S32 category)
+{
+ const S32 dim = 128;
+ sHighlightTexturep = new LLImageGL() ;
+ LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
+ U8* data = image_raw->getData();
+ for (S32 i = 0; i<dim; i++)
+ {
+ for (S32 j = 0; j<dim; j++)
+ {
+ const S32 border = 2;
+ if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
+ {
+ *data++ = 0xff;
+ *data++ = 0xff;
+ *data++ = 0xff;
+ }
+ else
+ {
+ *data++ = 0xff;
+ *data++ = 0xff;
+ *data++ = 0x00;
+ }
+ }
+ }
+ sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category);
+ image_raw = NULL;
+}
//static
S32 LLImageGL::dataFormatBits(S32 dataformat)
@@ -211,19 +277,31 @@ void LLImageGL::updateStats(F32 current_time)
sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
sCurBoundTextureMemory = 0;
-#if !LL_RELEASE_FOR_DOWNLOAD
- for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
+ if(gAuditTexture)
{
- sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
- sTextureCurBoundCounter[i] = 0 ;
+ for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
+ {
+ sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
+ sTextureCurBoundCounter[i] = 0 ;
+ }
+ for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++)
+ {
+ sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ;
+ sTextureCurMemByCategoryBound[i] = 0 ;
+ }
}
-#endif
}
//static
-S32 LLImageGL::updateBoundTexMem(const S32 delta)
+S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category)
{
- LLImageGL::sCurBoundTextureMemory += delta;
+ if(gAuditTexture && ncomponents > 0 && category > -1)
+ {
+ sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ;
+ sTextureCurMemByCategoryBound[category] += mem ;
+ }
+
+ LLImageGL::sCurBoundTextureMemory += mem ;
return LLImageGL::sCurBoundTextureMemory;
}
@@ -237,6 +315,7 @@ void LLImageGL::destroyGL(BOOL save_state)
gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE);
}
+ sAllowReadBackRaw = true ;
for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
iter != sImageList.end(); iter++)
{
@@ -246,7 +325,7 @@ void LLImageGL::destroyGL(BOOL save_state)
if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
{
glimage->mSaveData = new LLImageRaw;
- if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false))
+ if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
{
glimage->mSaveData = NULL ;
}
@@ -256,6 +335,7 @@ void LLImageGL::destroyGL(BOOL save_state)
stop_glerror();
}
}
+ sAllowReadBackRaw = false ;
}
//static
@@ -273,7 +353,7 @@ void LLImageGL::restoreGL()
{
if (glimage->getComponents() && glimage->mSaveData->getComponents())
{
- glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData);
+ glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory());
stop_glerror();
}
glimage->mSaveData = NULL; // deletes data
@@ -355,7 +435,7 @@ void LLImageGL::init(BOOL usemipmaps)
mPickMask = NULL;
mTextureMemory = 0;
mLastBindTime = 0.f;
-
+
mTarget = GL_TEXTURE_2D;
mBindTarget = LLTexUnit::TT_TEXTURE;
mUseMipMaps = usemipmaps;
@@ -381,7 +461,11 @@ void LLImageGL::init(BOOL usemipmaps)
mHasExplicitFormat = FALSE;
mGLTextureCreated = FALSE ;
+
mIsMask = FALSE;
+ mCategory = -1 ;
+ mAlphaStride = 0 ;
+ mAlphaOffset = 0 ;
mNeedsAlphaAndPickMask = TRUE ;
mDiscardLevelInAtlas = -1 ;
@@ -486,6 +570,10 @@ void LLImageGL::dump()
}
//----------------------------------------------------------------------------
+void LLImageGL::forceUpdateBindStats(void) const
+{
+ mLastBindTime = sLastFrameTime;
+}
BOOL LLImageGL::updateBindStats(S32 tex_mem) const
{
@@ -499,7 +587,7 @@ BOOL LLImageGL::updateBindStats(S32 tex_mem) const
{
// we haven't accounted for this texture yet this frame
sUniqueCount++;
- updateBoundTexMem(tex_mem);
+ updateBoundTexMem(tex_mem, mComponents, mCategory);
mLastBindTime = sLastFrameTime;
return TRUE ;
@@ -525,6 +613,8 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for
else
mFormatType = type_format;
mFormatSwapBytes = swap_bytes;
+
+ calcAlphaChannelOffsetAndStride() ;
}
//----------------------------------------------------------------------------
@@ -540,7 +630,6 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
{
- llpushcallstacks ;
bool is_compressed = false;
if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
{
@@ -749,7 +838,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
}
stop_glerror();
mGLTextureCreated = true;
- llpushcallstacks ;
}
BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
@@ -840,7 +928,6 @@ void LLImageGL::postAddToAtlas()
BOOL 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)
{
- llpushcallstacks ;
if (!width || !height)
{
return TRUE;
@@ -930,7 +1017,6 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
stop_glerror();
mGLTextureCreated = true;
}
- llpushcallstacks ;
return TRUE;
}
@@ -942,8 +1028,9 @@ BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S3
// Copy sub image from frame buffer
BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
{
- if (gGL.getTexUnit(0)->bind(this))
+ if (gGL.getTexUnit(0)->bind(this, false, true))
{
+ //checkTexSize() ;
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
mGLTextureCreated = true;
stop_glerror();
@@ -1007,7 +1094,7 @@ BOOL LLImageGL::createGLTexture()
return TRUE ;
}
-BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/)
+BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
{
if (gGLManager.mIsDisabled)
{
@@ -1027,8 +1114,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
// Actual image width/height = raw image width/height * 2^discard_level
- S32 w = imageraw->getWidth() << discard_level;
- S32 h = imageraw->getHeight() << discard_level;
+ S32 raw_w = imageraw->getWidth() ;
+ S32 raw_h = imageraw->getHeight() ;
+ S32 w = raw_w << discard_level;
+ S32 h = raw_h << discard_level;
// setSize may call destroyGLTexture if the size does not match
setSize(w, h, imageraw->getComponents());
@@ -1062,15 +1151,25 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
default:
llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
}
+
+ calcAlphaChannelOffsetAndStride() ;
}
+ if(!to_create) //not create a gl texture
+ {
+ destroyGLTexture();
+ mCurrentDiscardLevel = discard_level;
+ mLastBindTime = sLastFrameTime;
+ return TRUE ;
+ }
+
+ setCategory(category) ;
const U8* rawdata = imageraw->getData();
return createGLTexture(discard_level, rawdata, FALSE, usename);
}
BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
{
- llpushcallstacks ;
llassert(data_in);
if (discard_level < 0)
@@ -1137,11 +1236,14 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
if (old_name != 0)
{
sGlobalTextureMemoryInBytes -= mTextureMemory;
-#if !LL_RELEASE_FOR_DOWNLOAD
- decTextureCounter(mTextureMemory / mComponents) ;
-#endif
+
+ if(gAuditTexture)
+ {
+ decTextureCounter(mTextureMemory, mComponents, mCategory) ;
+ }
LLImageGL::deleteTextures(1, &old_name);
+
stop_glerror();
}
@@ -1149,82 +1251,20 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
sGlobalTextureMemoryInBytes += mTextureMemory;
mTexelsInGLTexture = getWidth() * getHeight() ;
-#if !LL_RELEASE_FOR_DOWNLOAD
- incTextureCounter(mTextureMemory / mComponents) ;
-#endif
-
+ if(gAuditTexture)
+ {
+ incTextureCounter(mTextureMemory, mComponents, mCategory) ;
+ }
// mark this as bound at this point, so we don't throw it out immediately
mLastBindTime = sLastFrameTime;
-
- llpushcallstacks ;
return TRUE;
}
-BOOL LLImageGL::setDiscardLevel(S32 discard_level)
-{
- llassert(discard_level >= 0);
- llassert(mCurrentDiscardLevel >= 0);
-
- discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
-
- if (discard_level == mCurrentDiscardLevel)
- {
- // nothing to do
- return FALSE;
- }
- else if (discard_level < mCurrentDiscardLevel)
- {
- // larger image
- dump();
- llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl;
- return FALSE;
- }
- else if (mUseMipMaps)
- {
- LLPointer<LLImageRaw> imageraw = new LLImageRaw;
- while(discard_level > mCurrentDiscardLevel)
- {
- if (readBackRaw(discard_level, imageraw, false))
- {
- break;
- }
- discard_level--;
- }
- if (discard_level == mCurrentDiscardLevel)
- {
- // unable to increase the discard level
- return FALSE;
- }
- return createGLTexture(discard_level, imageraw);
- }
- else
- {
-#if !LL_LINUX && !LL_SOLARIS
- // *FIX: This should not be skipped for the linux client.
- llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl;
-#endif
- return FALSE;
- }
-}
-
-BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents)
-{
- assert_glerror();
- S32 gl_discard = discard_level - mCurrentDiscardLevel;
- LLGLint glwidth = 0;
- glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
- LLGLint glheight = 0;
- glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_HEIGHT, (GLint*)&glheight);
- LLGLint glcomponents = 0 ;
- glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&glcomponents);
- assert_glerror();
-
- return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ;
-}
-
BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
{
- llpushcallstacks ;
+ llassert_always(sAllowReadBackRaw) ;
+ //llerrs << "should not call this function!" << llendl ;
+
if (discard_level < 0)
{
discard_level = mCurrentDiscardLevel;
@@ -1327,7 +1367,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
return FALSE ;
}
//-----------------------------------------------------------------------------------------------
- llpushcallstacks ;
+
return TRUE ;
}
@@ -1345,25 +1385,26 @@ void LLImageGL::deleteDeadTextures()
stop_glerror();
}
}
-
+
glDeleteTextures(1, &tex);
stop_glerror();
}
}
-
+
void LLImageGL::destroyGLTexture()
{
if (mTexName != 0)
{
if(mTextureMemory)
{
-#if !LL_RELEASE_FOR_DOWNLOAD
- decTextureCounter(mTextureMemory / mComponents) ;
-#endif
+ if(gAuditTexture)
+ {
+ decTextureCounter(mTextureMemory, mComponents, mCategory) ;
+ }
sGlobalTextureMemoryInBytes -= mTextureMemory;
mTextureMemory = 0;
}
-
+
LLImageGL::deleteTextures(1, &mTexName);
mTexName = 0;
mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
@@ -1479,6 +1520,11 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const
return res;
}
+BOOL LLImageGL::isJustBound() const
+{
+ return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f);
+}
+
BOOL LLImageGL::getBoundRecently() const
{
return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
@@ -1490,44 +1536,104 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b
mBindTarget = bind_target;
}
-void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+const S8 INVALID_OFFSET = -99 ;
+void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask)
{
- if(!mNeedsAlphaAndPickMask)
+ if(mNeedsAlphaAndPickMask != need_mask)
{
- return ;
+ mNeedsAlphaAndPickMask = need_mask;
+
+ if(mNeedsAlphaAndPickMask)
+ {
+ mAlphaOffset = 0 ;
+ }
+ else //do not need alpha mask
+ {
+ mAlphaOffset = INVALID_OFFSET ;
+ mIsMask = FALSE;
+ }
}
+}
- if (mFormatType != GL_UNSIGNED_BYTE)
+void LLImageGL::calcAlphaChannelOffsetAndStride()
+{
+ if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask
{
- llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl;
+ return ;
}
- U32 stride = 0;
+ mAlphaStride = -1 ;
switch (mFormatPrimary)
{
case GL_LUMINANCE:
case GL_ALPHA:
- stride = 1;
+ mAlphaStride = 1;
break;
case GL_LUMINANCE_ALPHA:
- stride = 2;
+ mAlphaStride = 2;
break;
case GL_RGB:
- //no alpha
+ mNeedsAlphaAndPickMask = FALSE ;
mIsMask = FALSE;
- return;
+ return ; //no alpha channel.
case GL_RGBA:
- stride = 4;
+ mAlphaStride = 4;
break;
case GL_BGRA_EXT:
- stride = 4;
+ mAlphaStride = 4;
break;
default:
- return;
+ break;
+ }
+
+ mAlphaOffset = -1 ;
+ if (mFormatType == GL_UNSIGNED_BYTE)
+ {
+ mAlphaOffset = mAlphaStride - 1 ;
+ }
+ else if(is_little_endian())
+ {
+ if (mFormatType == GL_UNSIGNED_INT_8_8_8_8)
+ {
+ mAlphaOffset = 0 ;
+ }
+ else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV)
+ {
+ mAlphaOffset = 3 ;
+ }
+ }
+ else //big endian
+ {
+ if (mFormatType == GL_UNSIGNED_INT_8_8_8_8)
+ {
+ mAlphaOffset = 3 ;
+ }
+ else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV)
+ {
+ mAlphaOffset = 0 ;
+ }
+ }
+
+ if( mAlphaStride < 1 || //unsupported format
+ mAlphaOffset < 0 || //unsupported type
+ (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation
+ {
+ llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl;
+
+ mNeedsAlphaAndPickMask = FALSE ;
+ mIsMask = FALSE;
+ }
+}
+
+void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+{
+ if(!mNeedsAlphaAndPickMask)
+ {
+ return ;
}
U32 length = w * h;
- const GLubyte* current = ((const GLubyte*) data_in)+stride-1;
+ const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset ;
S32 sample[16];
memset(sample, 0, sizeof(S32)*16);
@@ -1535,7 +1641,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
for (U32 i = 0; i < length; i++)
{
++sample[*current/16];
- current += stride;
+ current += mAlphaStride ;
}
U32 total = 0;
@@ -1638,8 +1744,30 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
return res;
}
-//----------------------------------------------------------------------------
-#if !LL_RELEASE_FOR_DOWNLOAD
+void LLImageGL::setCategory(S32 category)
+{
+ if(!gAuditTexture)
+ {
+ return ;
+ }
+ if(mCategory != category)
+ {
+ if(mCategory > -1)
+ {
+ sTextureMemByCategory[mCategory] -= mTextureMemory ;
+ }
+ if(category > -1 && category < sMaxCatagories)
+ {
+ sTextureMemByCategory[category] += mTextureMemory ;
+ mCategory = category;
+ }
+ else
+ {
+ mCategory = -1 ;
+ }
+ }
+}
+
//for debug use
//val is a "power of two" number
S32 LLImageGL::getTextureCounterIndex(U32 val)
@@ -1663,18 +1791,33 @@ S32 LLImageGL::getTextureCounterIndex(U32 val)
return ret ;
}
}
-void LLImageGL::incTextureCounter(U32 val)
+
+//static
+void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category)
{
sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
+ sTextureMemByCategory[category] += (S32)val * ncomponents ;
}
-void LLImageGL::decTextureCounter(U32 val)
+
+//static
+void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category)
{
sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
+ sTextureMemByCategory[category] += (S32)val * ncomponents ;
}
-void LLImageGL::setCurTexSizebar(S32 index)
+
+void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size)
{
sCurTexSizeBar = index ;
- sCurTexPickSize = (1 << index) ;
+
+ if(set_pick_size)
+ {
+ sCurTexPickSize = (1 << index) ;
+ }
+ else
+ {
+ sCurTexPickSize = -1 ;
+ }
}
void LLImageGL::resetCurTexSizebar()
{
@@ -1682,7 +1825,9 @@ void LLImageGL::resetCurTexSizebar()
sCurTexPickSize = -1 ;
}
//----------------------------------------------------------------------------
-#endif
+
+//----------------------------------------------------------------------------
+
// Manual Mip Generation
/*
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index a094605607..937065043c 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -47,7 +47,6 @@ class LLTextureAtlas ;
#define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
//============================================================================
-
class LLImageGL : public LLRefCount
{
friend class LLTexUnit;
@@ -63,6 +62,7 @@ public:
BOOL updateBindStats(S32 tex_mem) const ;
F32 getTimePassedSinceLastBound();
+ void forceUpdateBindStats(void) const;
// needs to be called every frame
static void updateStats(F32 current_time);
@@ -71,8 +71,9 @@ public:
static void destroyGL(BOOL save_state = TRUE);
static void restoreGL();
- // Sometimes called externally for textures not using LLImageGL (should go away...)
- static S32 updateBoundTexMem(const S32 delta);
+ // Sometimes called externally for textures not using LLImageGL (should go away...)
+ static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ;
+
static bool checkSize(S32 width, S32 height);
//for server side use only.
@@ -91,6 +92,7 @@ protected:
virtual ~LLImageGL();
void analyzeAlpha(const void* data_in, S32 w, S32 h);
+ void calcAlphaChannelOffsetAndStride();
public:
virtual void dump(); // debugging info to llinfos
@@ -105,14 +107,15 @@ public:
static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
BOOL createGLTexture() ;
- BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
+ BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
+ S32 category = sMaxCatagories - 1);
BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
void setImage(const LLImageRaw* imageraw);
void setImage(const U8* data_in, BOOL data_hasmips = FALSE);
BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
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);
BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
- BOOL setDiscardLevel(S32 discard_level);
+
// Read back a raw image for this discard level, if it exists
BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
void destroyGLTexture();
@@ -131,6 +134,7 @@ public:
S32 getBytes(S32 discard_level = -1) const;
S32 getMipBytes(S32 discard_level = -1) const;
BOOL getBoundRecently() const;
+ BOOL isJustBound() const;
LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
LLGLenum getFormatType() const { return mFormatType; }
@@ -150,8 +154,6 @@ public:
BOOL getUseMipMaps() const { return mUseMipMaps; }
void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; }
- BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ;
-
void updatePickMask(S32 width, S32 height, const U8* data_in);
BOOL getMask(const LLVector2 &tc);
@@ -178,7 +180,7 @@ public:
void init(BOOL usemipmaps);
virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors
- void setNeedsAlphaAndPickMask(BOOL need_mask) {mNeedsAlphaAndPickMask = need_mask;}
+ void setNeedsAlphaAndPickMask(BOOL need_mask);
BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
void postAddToAtlas() ;
@@ -187,7 +189,7 @@ public:
// Various GL/Rendering options
S32 mTextureMemory;
mutable F32 mLastBindTime; // last time this was bound, by discard level
-
+
private:
LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel
@@ -197,13 +199,15 @@ private:
BOOL mIsMask;
BOOL mNeedsAlphaAndPickMask;
-
+ S8 mAlphaStride ;
+ S8 mAlphaOffset ;
+
bool mGLTextureCreated ;
LLGLuint mTexName;
U16 mWidth;
U16 mHeight;
S8 mCurrentDiscardLevel;
-
+
S8 mDiscardLevelInAtlas;
U32 mTexelsInAtlas ;
U32 mTexelsInGLTexture;
@@ -233,7 +237,7 @@ public:
static S32 sCount;
static F32 sLastFrameTime;
-
+
static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID
// Global memory statistics
@@ -246,30 +250,61 @@ public:
static LLImageGL* sDefaultGLTexture ;
static BOOL sAutomatedTest;
-#if !LL_RELEASE_FOR_DOWNLOAD
+#if DEBUG_MISS
+ BOOL mMissed; // Missed on last bind?
+ BOOL getMissed() const { return mMissed; };
+#else
+ BOOL getMissed() const { return FALSE; };
+#endif
+
+public:
+ static void initClass(S32 num_catagories) ;
+ static void cleanupClass() ;
+private:
+ static S32 sMaxCatagories ;
+
+ //the flag to allow to call readBackRaw(...).
+ //can be removed if we do not use that function at all.
+ static BOOL sAllowReadBackRaw ;
+//
+//****************************************************************************************************
+//The below for texture auditing use only
+//****************************************************************************************************
+private:
+ S32 mCategory ;
+public:
+ void setCategory(S32 category) ;
+ S32 getCategory()const {return mCategory ;}
+
//for debug use: show texture size distribution
//----------------------------------------
- static LLPointer<LLImageGL> sDefaultTexturep; //default texture to replace normal textures
+ static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures
static std::vector<S32> sTextureLoadedCounter ;
static std::vector<S32> sTextureBoundCounter ;
static std::vector<S32> sTextureCurBoundCounter ;
static S32 sCurTexSizeBar ;
static S32 sCurTexPickSize ;
-
+
+ static void setHighlightTexture(S32 category) ;
static S32 getTextureCounterIndex(U32 val) ;
- static void incTextureCounter(U32 val) ;
- static void decTextureCounter(U32 val) ;
- static void setCurTexSizebar(S32 index) ;
+ static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ;
+ static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ;
+ static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ;
static void resetCurTexSizebar();
//----------------------------------------
-#endif
-#if DEBUG_MISS
- BOOL mMissed; // Missed on last bind?
- BOOL getMissed() const { return mMissed; };
-#else
- BOOL getMissed() const { return FALSE; };
-#endif
+ //for debug use: show texture category distribution
+ //----------------------------------------
+
+ static std::vector<S32> sTextureMemByCategory;
+ static std::vector<S32> sTextureMemByCategoryBound ;
+ static std::vector<S32> sTextureCurMemByCategoryBound ;
+ //----------------------------------------
+//****************************************************************************************************
+//End of definitions for texture auditing use only
+//****************************************************************************************************
+
};
+extern BOOL gAuditTexture;
#endif // LL_LLIMAGEGL_H
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index b74d824c9e..fc45df8153 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -179,7 +179,7 @@ void LLTexUnit::disable(void)
}
}
-bool LLTexUnit::bind(LLTexture* texture, bool forceBind)
+bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
{
stop_glerror();
if (mIndex < 0) return false;
@@ -198,9 +198,19 @@ bool LLTexUnit::bind(LLTexture* texture, bool forceBind)
//if deleted, will re-generate it immediately
texture->forceImmediateUpdate() ;
+ gl_tex->forceUpdateBindStats() ;
return texture->bindDefaultImage(mIndex);
}
+ //in audit, replace the selected texture by the default one.
+ if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0)
+ {
+ if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize)
+ {
+ gl_tex->updateBindStats(gl_tex->mTextureMemory);
+ return bind(LLImageGL::sHighlightTexturep.get());
+ }
+ }
if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
{
activate();
@@ -223,7 +233,7 @@ bool LLTexUnit::bind(LLTexture* texture, bool forceBind)
return true;
}
-bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
+bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
{
stop_glerror();
if (mIndex < 0) return false;
@@ -260,6 +270,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
setTextureFilteringOption(texture->mFilterOption);
}
}
+
return true;
}
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index cb2a4d4450..0121a190ee 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -149,8 +149,8 @@ public:
// Binds the LLImageGL to this texture unit
// (automatically enables the unit for the LLImageGL's texture type)
- bool bind(LLImageGL* texture, bool forceBind = false);
- bool bind(LLTexture* texture, bool forceBind = false);
+ bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
+ bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false);
// Binds a cubemap to this texture unit
// (automatically enables the texture unit for cubemaps)
diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h
index c18917b663..6495fb9859 100644
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -61,7 +61,7 @@ public:
//
//interfaces to access LLViewerTexture
//
- virtual bool bindDefaultImage(const S32 stage = 0) const = 0 ;
+ virtual bool bindDefaultImage(const S32 stage = 0) = 0 ;
virtual void forceImmediateUpdate() = 0 ;
virtual void setActive() = 0 ;
virtual S32 getWidth(S32 discard_level = -1) const = 0 ;
diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp
index 704e1ab142..e85cc437f4 100644
--- a/indra/llvfs/lllfsthread.cpp
+++ b/indra/llvfs/lllfsthread.cpp
@@ -189,7 +189,7 @@ bool LLLFSThread::Request::processRequest()
{
llassert(mOffset >= 0);
LLAPRFile infile ;
- infile.open(mThread->getLocalAPRFilePool(), mFileName, LL_APR_RB);
+ infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool());
if (!infile.getFileHandle())
{
llwarns << "LLLFS: Unable to read file: " << mFileName << llendl;
@@ -213,7 +213,7 @@ bool LLLFSThread::Request::processRequest()
if (mOffset < 0)
flags |= APR_APPEND;
LLAPRFile outfile ;
- outfile.open(mThread->getLocalAPRFilePool(), mFileName, flags);
+ outfile.open(mFileName, flags, mThread->getLocalAPRFilePool());
if (!outfile.getFileHandle())
{
llwarns << "LLLFS: Unable to write file: " << mFileName << llendl;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index f27d949faf..38622d206f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -265,7 +265,6 @@ set(viewer_SOURCE_FILES
llmaniprotate.cpp
llmanipscale.cpp
llmaniptranslate.cpp
- llmapresponders.cpp
llmediactrl.cpp
llmediadataclient.cpp
llmediaremotectrl.cpp
@@ -387,6 +386,10 @@ set(viewer_SOURCE_FILES
lltexturecache.cpp
lltexturectrl.cpp
lltexturefetch.cpp
+ lltextureinfo.cpp
+ lltextureinfodetails.cpp
+ lltexturestats.cpp
+ lltexturestatsuploader.cpp
lltextureview.cpp
lltoast.cpp
lltoastalertpanel.cpp
@@ -508,6 +511,8 @@ set(viewer_SOURCE_FILES
llwlparamset.cpp
llworld.cpp
llworldmap.cpp
+ llworldmapmessage.cpp
+ llworldmipmap.cpp
llworldmapview.cpp
llxmlrpctransaction.cpp
noise.cpp
@@ -738,7 +743,6 @@ set(viewer_HEADER_FILES
llmaniprotate.h
llmanipscale.h
llmaniptranslate.h
- llmapresponders.h
llmediadataclient.h
llmediaremotectrl.h
llmemoryview.h
@@ -859,6 +863,10 @@ set(viewer_HEADER_FILES
lltexturecache.h
lltexturectrl.h
lltexturefetch.h
+ lltextureinfo.h
+ lltextureinfodetails.h
+ lltexturestats.h
+ lltexturestatsuploader.h
lltextureview.h
lltoast.h
lltoastalertpanel.h
@@ -982,6 +990,8 @@ set(viewer_HEADER_FILES
llwlparamset.h
llworld.h
llworldmap.h
+ llworldmapmessage.h
+ llworldmipmap.h
llworldmapview.h
llxmlrpctransaction.h
macmain.h
@@ -1574,6 +1584,12 @@ LL_ADD_INTEGRATION_TEST(llcapabilitylistener
)
#ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
+#ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
+#ADD_VIEWER_BUILD_TEST(llworldmap viewer)
+#ADD_VIEWER_BUILD_TEST(llworldmipmap viewer)
+#ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
+#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
+#ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
# Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7e368b0c9c..aa43f8cd9c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -309,7 +309,18 @@
<key>Value</key>
<integer>0</integer>
</map>
- <key>AutoAcceptNewInventory</key>
+ <key>AuditTexture</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable texture auditting.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoAcceptNewInventory</key>
<map>
<key>Comment</key>
<string>Automatically accept new notecards/textures/landmarks</string>
@@ -4545,6 +4556,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>MiniMapPrimMaxRadius</key>
+ <map>
+ <key>Comment</key>
+ <string>Radius of the largest prim to show on the MiniMap. Increasing beyond 256 may cause client lag.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>256.0</real>
+ </map>
<key>MiniMapRotate</key>
<map>
<key>Comment</key>
@@ -4559,7 +4581,7 @@
<key>MiniMapScale</key>
<map>
<key>Comment</key>
- <string>Miniature world map zoom levle (pixels per region)</string>
+ <string>Miniature world map zoom level (pixels per region)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -8468,6 +8490,28 @@
<key>Value</key>
<real>20.0</real>
</map>
+ <key>TextureDisable</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE, do not load textures for in-world content</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureLoadFullRes</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE, always load textures at full resolution (discard = 0)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>TextureMemory</key>
<map>
<key>Comment</key>
@@ -10537,5 +10581,38 @@
<key>Value</key>
<integer>0</integer>
</map>
- </map>
+ <key>LogTextureDownloadsToViewerLog</key>
+ <map>
+ <key>Comment</key>
+ <string>Send texture download details to the viewer log</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LogTextureDownloadsToSimulator</key>
+ <map>
+ <key>Comment</key>
+ <string>Send a digest of texture info to the sim</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureLoggingThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies the byte threshold at which texture download data should be sent to the sim.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+</map>
</llsd>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 0fa3b1f04d..e182228ab3 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -74,6 +74,8 @@
#include "llstatusbar.h"
#include "llteleportflags.h"
#include "llteleporthistory.h"
+#include "lltexturestats.h"
+#include "lltexturestats.h"
#include "lltool.h"
#include "lltoolcomp.h"
#include "lltoolmgr.h"
@@ -6087,17 +6089,16 @@ void LLAgent::teleportCancel()
void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
{
LLViewerRegion* regionp = getRegion();
- LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
+ U64 handle = to_region_handle(pos_global);
+ LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
if(regionp && info)
{
- U32 x_pos;
- U32 y_pos;
- from_region_handle(info->mHandle, &x_pos, &y_pos);
+ LLVector3d region_origin = info->getGlobalOrigin();
LLVector3 pos_local(
- (F32)(pos_global.mdV[VX] - x_pos),
- (F32)(pos_global.mdV[VY] - y_pos),
+ (F32)(pos_global.mdV[VX] - region_origin.mdV[VX]),
+ (F32)(pos_global.mdV[VY] - region_origin.mdV[VY]),
(F32)(pos_global.mdV[VZ]));
- teleportRequest(info->mHandle, pos_local);
+ teleportRequest(handle, pos_local);
}
else if(regionp &&
teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY])))
@@ -6514,3 +6515,4 @@ LLAgentQueryManager::~LLAgentQueryManager()
}
// EOF
+
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index c673db2034..87d081b27c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -58,6 +58,8 @@
#include "llallocator.h"
#include "llares.h"
#include "llcurl.h"
+#include "lltexturestats.h"
+#include "lltexturestats.h"
#include "llviewerwindow.h"
#include "llviewerdisplay.h"
#include "llviewermedia.h"
@@ -248,9 +250,6 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
BOOL gDisconnected = FALSE;
-// Map scale in pixels per region
-F32 gMapScale = 128.f;
-
// used to restore texture state after a mode switch
LLFrameTimer gRestoreGLTimer;
BOOL gRestoreGL = FALSE;
@@ -413,7 +412,7 @@ static void settings_to_globals()
gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
gAllowTapTapHoldRun = gSavedSettings.getBOOL("AllowTapTapHoldRun");
gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
- gMapScale = gSavedSettings.getF32("MapScale");
+ LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
}
@@ -426,7 +425,7 @@ static void settings_modify()
LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
-
+ gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
#if LL_VECTORIZE
if (gSysCPU.hasAltivec())
{
@@ -547,7 +546,7 @@ LLAppViewer* LLAppViewer::sInstance = NULL;
const std::string LLAppViewer::sGlobalSettingsName = "Global";
LLTextureCache* LLAppViewer::sTextureCache = NULL;
-LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL;
+LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
LLAppViewer::LLAppViewer() :
@@ -639,6 +638,9 @@ bool LLAppViewer::init()
//////////////////////////////////////////////////////////////////////////////
// *FIX: The following code isn't grouped into functions yet.
+ // Statistics / debug timer initialization
+ init_statistics();
+
//
// Various introspection concerning the libs we're using - particularly
// the libs involved in getting to a full login screen.
@@ -1596,14 +1598,14 @@ bool LLAppViewer::initThreads()
LLWatchdog::getInstance()->init(watchdog_killer_callback);
}
- LLVFSThread::initClass(enable_threads && true);
- LLLFSThread::initClass(enable_threads && true);
+ LLVFSThread::initClass(enable_threads && false);
+ LLLFSThread::initClass(enable_threads && false);
// Image decoding
- LLAppViewer::sImageDecodeThread = new LLWorkerThread("ImageDecode", enable_threads && true);
+ LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
- LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), enable_threads && false);
- LLImage::initClass(LLAppViewer::getImageDecodeThread());
+ LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
+ LLImage::initClass();
if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
{
@@ -2397,7 +2399,7 @@ void LLAppViewer::cleanupSavedSettings()
}
}
- gSavedSettings.setF32("MapScale", gMapScale );
+ gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );
// Some things are cached in LLAgent.
if (gAgent.mInitialized)
@@ -2723,7 +2725,7 @@ void LLAppViewer::initMarkerFile()
// Create the marker file for this execution & lock it
apr_status_t s;
- s = mMarkerFile.open(mMarkerFileName, LL_APR_W, gAPRPoolp);
+ s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);
if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
{
@@ -4109,3 +4111,4 @@ void LLAppViewer::handleLoginComplete()
writeDebugInfo();
}
+
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 646b677264..d07ee6e94f 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -41,12 +41,10 @@ class LLCommandLineParser;
class LLFrameTimer;
class LLPumpIO;
class LLTextureCache;
+class LLImageDecodeThread;
class LLTextureFetch;
-class LLTimer;
-class LLVFS;
class LLWatchdogTimeout;
-class LLWorkerThread;
-
+class LLCommandLineParser;
class LLAppViewer : public LLApp
{
@@ -98,7 +96,7 @@ public:
// Thread accessors
static LLTextureCache* getTextureCache() { return sTextureCache; }
- static LLWorkerThread* getImageDecodeThread() { return sImageDecodeThread; }
+ static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
const std::string& getSerialNumber() { return mSerialNumber; }
@@ -228,7 +226,7 @@ private:
// Thread objects.
static LLTextureCache* sTextureCache;
- static LLWorkerThread* sImageDecodeThread;
+ static LLImageDecodeThread* sImageDecodeThread;
static LLTextureFetch* sTextureFetch;
S32 mNumSessions;
@@ -322,9 +320,6 @@ extern F32 gSimFrames;
extern BOOL gDisconnected;
-// Map scale in pixels per region
-extern F32 gMapScale;
-
extern LLFrameTimer gRestoreGLTimer;
extern BOOL gRestoreGL;
extern BOOL gUseWireframe;
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index ea3809d58d..f117e7d975 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -368,7 +368,7 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
std::string result = content["state"];
LLUUID new_id = content["new_asset"];
- llinfos << "LLSendTexLayerResponder::result from capabilities: " << result << llendl;
+ llinfos << "result: " << result << "new_id:" << new_id << llendl;
if (result == "complete"
&& mBakedUploadData != NULL)
{ // Invoke
@@ -382,6 +382,14 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
}
}
+void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason)
+{
+ llinfos << "status: " << statusNum << " reason: " << reason << llendl;
+
+ // Invoke the original callback with an error result
+ LLTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
+ mBakedUploadData = NULL; // deleted in onTextureUploadComplete()
+}
LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
const LLUUID& vfile_id,
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index a08d70213c..e656351305 100644
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -84,6 +84,7 @@ public:
~LLSendTexLayerResponder();
virtual void uploadComplete(const LLSD& content);
+ virtual void error(U32 statusNum, const std::string& reason);
LLBakedUploadData * mBakedUploadData;
};
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index 7b75c77a1e..5d27595a59 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -228,7 +228,7 @@ void LLColorSwatchCtrl::draw()
{
if (!mFallbackImageName.empty())
{
- LLPointer<LLViewerTexture> fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+ LLPointer<LLViewerFetchedTexture> fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
if( fallback_image->getComponents() == 4 )
{
gl_rect_2d_checkerboard( interior );
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index 24a57cb0c1..9057d84f63 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -45,7 +45,7 @@
#include "llviewerwindow.h"
#include "llappviewer.h"
#include "llmemoryview.h"
-
+#include "llviewertexture.h"
//
// Globals
//
@@ -102,17 +102,29 @@ LLDebugView::LLDebugView(const LLDebugView::Params& p)
gTextureView = LLUICtrlFactory::create<LLTextureView>(tvp);
addChild(gTextureView);
//gTextureView->reshape(r.getWidth(), r.getHeight(), TRUE);
-#if !LL_RELEASE_FOR_DOWNLOAD
- r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100);
- LLTextureSizeView::Params tsvp;
- tsvp.name("gTextureSizeView");
- tsvp.rect(r);
- tsvp.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
- tsvp.visible(false);
- gTextureSizeView = LLUICtrlFactory::create<LLTextureSizeView>(tsvp);
- addChild(gTextureSizeView);
-#endif
+ if(gAuditTexture)
+ {
+ r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100);
+ LLTextureSizeView::Params tsv ;
+ tsv.name("gTextureSizeView");
+ tsv.rect(r);
+ tsv.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
+ tsv.visible(false);
+ gTextureSizeView = LLUICtrlFactory::create<LLTextureSizeView>(tsv);
+ addChild(gTextureSizeView);
+ gTextureSizeView->setType(LLTextureSizeView::TEXTURE_MEM_OVER_SIZE) ;
+
+ r.set(150, rect.getHeight() - 50, 900 + LLViewerTexture::getTotalNumOfCategories() * 30, 100);
+ LLTextureSizeView::Params tcv ;
+ tcv.name("gTextureCategoryView");
+ tcv.rect(r);
+ tcv.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
+ tcv.visible(false);
+ gTextureCategoryView = LLUICtrlFactory::create<LLTextureSizeView>(tcv);
+ gTextureCategoryView->setType(LLTextureSizeView::TEXTURE_MEM_OVER_CATEGORY);
+ addChild(gTextureCategoryView);
+ }
}
@@ -122,5 +134,6 @@ LLDebugView::~LLDebugView()
gDebugView = NULL;
gTextureView = NULL;
gTextureSizeView = NULL;
+ gTextureCategoryView = NULL;
}
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 069155c255..03a3f2b43d 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -105,7 +105,7 @@ void LLDrawable::init()
mVObjp = NULL;
// mFaces
mSpatialGroupp = NULL;
- mVisible = 0;
+ mVisible = sCurVisible - 2;//invisible for the current frame and the last frame.
mRadius = 0.f;
mGeneration = -1;
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 976f02eeb7..1b46e0a478 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -279,7 +279,7 @@ S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage)
iter != face_list.end(); iter++)
{
LLFace *facep = *iter;
- gGL.getTexUnit(stage)->bind(facep->getTexture());
+ gGL.getTexUnit(stage)->bind(facep->getTexture(), TRUE) ;
gGL.getTexUnit(0)->activate();
res += facep->renderIndexed();
}
@@ -474,17 +474,13 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
{
if (params.mTexture.notNull())
{
- gGL.getTexUnit(0)->bind(params.mTexture.get());
+ gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
if (params.mTextureMatrix)
{
glMatrixMode(GL_TEXTURE);
glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
gPipeline.mTextureMatrixOps++;
}
- if(params.mTexture.notNull())//will be removed.
- {
- params.mTexture->addTextureStats(params.mVSize);
- }
}
else
{
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index a5a29dea7b..6d77361414 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -219,7 +219,7 @@ void LLDrawPoolAlpha::render(S32 pass)
gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
glColor4f(1,0,0,1);
LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep) ;
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ;
renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
LLVertexBuffer::MAP_TEXCOORD0);
}
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 8d2cbc583c..5521fb05a8 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -253,7 +253,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
LLGLState normalize(GL_NORMALIZE, TRUE);
// Bind the texture for this tree.
- gGL.getTexUnit(sDiffTex)->bind(mTexturep.get());
+ gGL.getTexUnit(sDiffTex)->bind(mTexturep.get(), TRUE);
U32 indices_drawn = 0;
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 0bb5edf3f9..e41c4104eb 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -104,7 +104,7 @@ void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum
{
setExplicitFormat(internal_format, primary_format, type_format, swap_bytes);
}
- createGLTexture(0, raw_image);
+ createGLTexture(0, raw_image, 0, TRUE, LLViewerTexture::DYNAMIC_TEX);
setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP);
mGLTexturep->setGLTextureCreated(false);
}
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4246cbc27f..edadc3dcf7 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -52,6 +52,7 @@
#include "llvovolume.h"
#include "pipeline.h"
#include "llviewerregion.h"
+#include "llviewerwindow.h"
#define LL_MAX_INDICES_COUNT 1000000
@@ -175,6 +176,9 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
mLastIndicesCount = mIndicesCount;
mLastIndicesIndex = mIndicesIndex;
+ mImportanceToCamera = 0.f ;
+ mBoundingSphereRadius = 0.0f ;
+
mAtlasInfop = NULL ;
mUsingAtlas = FALSE ;
}
@@ -186,6 +190,7 @@ void LLFace::destroy()
{
mTexture->removeFace(this) ;
}
+
if (mDrawPoolp)
{
mDrawPoolp->removeFace(this);
@@ -207,7 +212,7 @@ void LLFace::destroy()
}
}
}
-
+
setDrawInfo(NULL);
removeAtlas();
@@ -256,6 +261,7 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
}
mDrawPoolp = new_pool;
}
+
setTexture(texturep) ;
}
@@ -750,7 +756,9 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
}
mCenterLocal = (newMin+newMax)*0.5f;
-
+ LLVector3 tmp = (newMin - newMax) ;
+ mBoundingSphereRadius = tmp.length() * 0.5f ;
+
updateCenterAgent();
}
@@ -1305,6 +1313,151 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
return TRUE;
}
+const F32 LEAST_IMPORTANCE = 0.05f ;
+const F32 LEAST_IMPORTANCE_FOR_LARGE_IMAGE = 0.3f ;
+
+F32 LLFace::getTextureVirtualSize()
+{
+ F32 radius;
+ F32 cos_angle_to_view_dir;
+ mPixelArea = calcPixelArea(cos_angle_to_view_dir, radius);
+
+ if (mPixelArea <= 0)
+ {
+ return 0.f;
+ }
+
+ //get area of circle in texture space
+ LLVector2 tdim = mTexExtents[1] - mTexExtents[0];
+ F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f;
+ if (texel_area <= 0)
+ {
+ // Probably animated, use default
+ texel_area = 1.f;
+ }
+
+ //apply texel area to face area to get accurate ratio
+ //face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
+ F32 face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
+
+ if(face_area > LLViewerTexture::sMaxSmallImageSize)
+ {
+ if(mImportanceToCamera < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
+ {
+ static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
+ face_area = llmin(face_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
+ }
+ else if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
+ {
+ if(mImportanceToCamera < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
+ {
+ face_area = LLViewerTexture::sMinLargeImageSize ;
+ }
+ else if(mTexture.notNull() && mTexture->isLargeImage())
+ {
+ face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
+ }
+ }
+ }
+
+ return face_area;
+}
+
+F32 LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
+{
+ //get area of circle around face
+ LLVector3 center = getPositionAgent();
+ LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f;
+
+ LLVector3 lookAt = center - LLViewerCamera::getInstance()->getOrigin();
+ F32 dist = lookAt.normVec() ;
+
+ //get area of circle around node
+ F32 app_angle = atanf(size.length()/dist);
+ radius = app_angle*LLDrawable::sCurPixelAngle;
+ F32 face_area = radius*radius * 3.14159f;
+
+ if(dist < mBoundingSphereRadius) //camera is very close
+ {
+ cos_angle_to_view_dir = 1.0f ;
+ mImportanceToCamera = 1.0f ;
+ }
+ else
+ {
+ cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;
+ mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ;
+ }
+
+ return face_area ;
+}
+
+//the projection of the face partially overlaps with the screen
+F32 LLFace::adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius )
+{
+ F32 screen_radius = (F32)llmax(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()) ;
+ F32 center_angle = acosf(cos_angle_to_view_dir) ;
+ F32 d = center_angle * LLDrawable::sCurPixelAngle ;
+
+ if(d + radius > screen_radius + 5.f)
+ {
+ //----------------------------------------------
+ //calculate the intersection area of two circles
+ //F32 radius_square = radius * radius ;
+ //F32 d_square = d * d ;
+ //F32 screen_radius_square = screen_radius * screen_radius ;
+ //face_area =
+ // radius_square * acosf((d_square + radius_square - screen_radius_square)/(2 * d * radius)) +
+ // screen_radius_square * acosf((d_square + screen_radius_square - radius_square)/(2 * d * screen_radius)) -
+ // 0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ;
+ //----------------------------------------------
+
+ //the above calculation is too expensive
+ //the below is a good estimation: bounding box of the bounding sphere:
+ F32 alpha = 0.5f * (radius + screen_radius - d) / radius ;
+ alpha = llclamp(alpha, 0.f, 1.f) ;
+ return alpha * alpha ;
+ }
+ return 1.0f ;
+}
+
+const S8 FACE_IMPORTANCE_LEVEL = 4 ;
+const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL][2] = //{distance, importance_weight}
+ {{16.1f, 1.0f}, {32.1f, 0.5f}, {48.1f, 0.2f}, {96.1f, 0.05f} } ;
+const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[FACE_IMPORTANCE_LEVEL][2] = //{cos(angle), importance_weight}
+ {{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}} ;
+
+//static
+F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
+{
+ F32 importance = 0.f ;
+
+ if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() &&
+ dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0])
+ {
+ F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
+ F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
+
+ if(camera_moving_speed > 10.0f || camera_angular_speed > 1.0f)
+ {
+ //if camera moves or rotates too fast, ignore the importance factor
+ return 0.f ;
+ }
+
+ //F32 camera_relative_speed = camera_moving_speed * (lookAt * LLViewerCamera::getInstance()->getVelocityDir()) ;
+
+ S32 i = 0 ;
+ for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i);
+ i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
+ F32 dist_factor = FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][1] ;
+
+ for(i = 0; i < FACE_IMPORTANCE_LEVEL && cos_angle_to_view_dir < FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][0] ; ++i) ;
+ i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
+ importance = dist_factor * FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][1] ;
+ }
+
+ return importance ;
+}
+
BOOL LLFace::verify(const U32* indices_array) const
{
BOOL ok = TRUE;
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index d734b327d9..68eee061b8 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -188,6 +188,9 @@ public:
void setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
void setDrawInfo(LLDrawInfo* draw_info);
+ F32 getTextureVirtualSize() ;
+ F32 getImportanceToCamera()const {return mImportanceToCamera ;}
+
//for atlas
LLTextureAtlasSlot* getAtlasInfo() ;
void setAtlasInUse(BOOL flag);
@@ -200,6 +203,12 @@ public:
void removeAtlas() ;
BOOL switchTexture() ;
+private:
+ F32 adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius );
+ F32 calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) ;
+public:
+ static F32 calcImportanceToCamera(F32 to_view_dir, F32 dist);
+
public:
LLVector3 mCenterLocal;
@@ -214,7 +223,7 @@ public:
LLMatrix4* mTextureMatrix;
LLDrawInfo* mDrawInfo;
-protected:
+private:
friend class LLGeometryManager;
friend class LLVolumeGeometryManager;
@@ -244,9 +253,16 @@ protected:
F32 mVSize;
F32 mPixelArea;
+ //importance factor, in the range [0, 1.0].
+ //1.0: the most important.
+ //based on the distance from the face to the view point and the angle from the face center to the view direction.
+ F32 mImportanceToCamera ;
+ F32 mBoundingSphereRadius ;
+
+
//atlas
LLPointer<LLTextureAtlasSlot> mAtlasInfop ;
- BOOL mUsingAtlas ;
+ BOOL mUsingAtlas ;
protected:
static BOOL sSafeRenderSelect;
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 0c9a759f32..3fe711a166 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -51,11 +51,26 @@
#include "llviewermenu.h"
//
+// Constants
+//
+const F32 MAP_MINOR_DIR_THRESHOLD = 0.08f;
+
+//
// Member functions
//
LLFloaterMap::LLFloaterMap(const LLSD& key)
- : LLFloater(key)
+ : LLFloater(key),
+ mPopupMenu(NULL),
+ mTextBoxEast(NULL),
+ mTextBoxNorth(NULL),
+ mTextBoxWest(NULL),
+ mTextBoxSouth(NULL),
+ mTextBoxSouthEast(NULL),
+ mTextBoxNorthEast(NULL),
+ mTextBoxNorthWest(NULL),
+ mTextBoxSouthWest(NULL),
+ mMap(NULL)
{
//Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_map.xml", FALSE);
}
@@ -92,6 +107,8 @@ BOOL LLFloaterMap::postBuild()
mPopupMenu->setItemEnabled ("Stop Tracking", false);
}
+ updateMinorDirections();
+
// Get the drag handle all the way in back
sendChildToBack(getDragHandle());
@@ -139,6 +156,23 @@ void LLFloaterMap::setDirectionPos( LLTextBox* text_box, F32 rotation )
llround(map_half_height - text_half_height + radius * sin( rotation )) );
}
+void LLFloaterMap::updateMinorDirections()
+{
+ if (mTextBoxNorthEast == NULL)
+ {
+ return;
+ }
+
+ // Hide minor directions if they cover too much of the map
+ bool show_minors = mTextBoxNorthEast->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD *
+ llmin(getRect().getWidth(), getRect().getHeight());
+
+ mTextBoxNorthEast->setVisible(show_minors);
+ mTextBoxNorthWest->setVisible(show_minors);
+ mTextBoxSouthWest->setVisible(show_minors);
+ mTextBoxSouthEast->setVisible(show_minors);
+}
+
// virtual
void LLFloaterMap::draw()
{
@@ -180,17 +214,23 @@ void LLFloaterMap::draw()
LLFloater::draw();
}
+void LLFloaterMap::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLFloater::reshape(width, height, called_from_parent);
+ updateMinorDirections();
+}
+
void LLFloaterMap::handleZoom(const LLSD& userdata)
{
std::string level = userdata.asString();
F32 scale = 0.0f;
if (level == std::string("close"))
- scale = MAP_SCALE_MAX;
+ scale = LLNetMap::MAP_SCALE_MAX;
else if (level == std::string("medium"))
- scale = MAP_SCALE_MID;
+ scale = LLNetMap::MAP_SCALE_MID;
else if (level == std::string("far"))
- scale = MAP_SCALE_MIN;
+ scale = LLNetMap::MAP_SCALE_MIN;
if (scale != 0.0f)
{
gSavedSettings.setF32("MiniMapScale", scale );
diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h
index 501777ed07..6c9138c6a7 100644
--- a/indra/newview/llfloatermap.h
+++ b/indra/newview/llfloatermap.h
@@ -51,12 +51,14 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
/*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
/*virtual*/ void draw();
private:
void handleZoom(const LLSD& userdata);
void handleStopTracking (const LLSD& userdata);
void setDirectionPos( LLTextBox* text_box, F32 rotation );
+ void updateMinorDirections();
LLMenuGL* mPopupMenu;
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index b146ed9b38..8e5a76bfae 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -790,7 +790,7 @@ void LLFloaterReporter::takeScreenshot()
// store in the image list so it doesn't try to fetch from the server
LLPointer<LLViewerFetchedTexture> image_in_list =
LLViewerTextureManager::getFetchedTexture(mResourceDatap->mAssetInfo.mUuid, TRUE, FALSE, LLViewerTexture::FETCHED_TEXTURE);
- image_in_list->createGLTexture(0, raw);
+ image_in_list->createGLTexture(0, raw, 0, TRUE, LLViewerTexture::OTHER);
// the texture picker then uses that texture
LLTexturePicker* texture = getChild<LLTextureCtrl>("screenshot");
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index fbaf10d455..63560d2038 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -55,7 +55,6 @@
#include "llregionhandle.h"
#include "llscrolllistctrl.h"
#include "llslurl.h"
-#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltracker.h"
#include "lltrans.h"
@@ -63,7 +62,9 @@
#include "llviewermenu.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
+#include "llviewertexture.h"
#include "llworldmap.h"
+#include "llworldmapmessage.h"
#include "llworldmapview.h"
#include "lluictrlfactory.h"
#include "llappviewer.h"
@@ -79,6 +80,12 @@
//---------------------------------------------------------------------------
static const F32 MAP_ZOOM_TIME = 0.2f;
+// Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
+// width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
+// sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit.
+// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
+static const S32 MAX_VISIBLE_REGIONS = 512;
+
enum EPanDirection
{
PAN_UP,
@@ -160,11 +167,11 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
gFloaterWorldMap = this;
mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
- mFactoryMap["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL);
//Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", FALSE);
mCommitCallbackRegistrar.add("WMap.Location", boost::bind(&LLFloaterWorldMap::onLocationCommit, this));
mCommitCallbackRegistrar.add("WMap.AvatarCombo", boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this));
+ mCommitCallbackRegistrar.add("WMap.Landmark", boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this));
mCommitCallbackRegistrar.add("WMap.SearchResult", boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this));
mCommitCallbackRegistrar.add("WMap.CommitLocation", boost::bind(&LLFloaterWorldMap::onCommitLocation, this));
mCommitCallbackRegistrar.add("WMap.GoHome", boost::bind(&LLFloaterWorldMap::onGoHome, this));
@@ -183,17 +190,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data)
BOOL LLFloaterWorldMap::postBuild()
{
- mTabs = getChild<LLTabContainer>("maptab");
- if (!mTabs) return FALSE;
-
- mTabs->setCommitCallback(boost::bind(&LLFloaterWorldMap::onCommitBackground, this));
-
- // The following callback syncs the worlmap tabs with the images.
- // Commented out since it was crashing when LLWorldMap became a singleton.
- // We should be fine without it but override the onOpen method and put it
- // there if it turns out to be needed. -MG
- //
- //onCommitBackground();
+ mPanel = getChild<LLPanel>("objects_mapview");
LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
if (avatar_combo)
@@ -221,8 +218,8 @@ BOOL LLFloaterWorldMap::postBuild()
landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
}
- mCurZoomVal = log(gMapScale)/log(2.f);
- childSetValue("zoom slider", gMapScale);
+ mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
+ childSetValue("zoom slider", LLWorldMapView::sMapScale);
setDefaultBtn(NULL);
@@ -235,7 +232,7 @@ BOOL LLFloaterWorldMap::postBuild()
LLFloaterWorldMap::~LLFloaterWorldMap()
{
// All cleaned up by LLView destructor
- mTabs = NULL;
+ mPanel = NULL;
// Inventory deletes all observers on shutdown
mInventory = NULL;
@@ -268,7 +265,7 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
mIsClosing = FALSE;
LLWorldMapView* map_panel;
- map_panel = (LLWorldMapView*)mTabs->getCurrentPanel();
+ map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel;
map_panel->clearLastClick();
{
@@ -279,15 +276,8 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
}
map_panel->updateVisibleBlocks();
- // Reload the agent positions when we show the window
- LLWorldMap::getInstance()->eraseItems();
-
- // Reload any maps that may have changed
- LLWorldMap::getInstance()->clearSimFlags();
-
- const S32 panel_num = mTabs->getCurrentPanelIndex();
- const bool request_from_sim = true;
- LLWorldMap::getInstance()->setCurrentLayer(panel_num, request_from_sim);
+ // Reload items as they may have changed
+ LLWorldMap::getInstance()->reloadItems();
// We may already have a bounding box for the regions of the world,
// so use that to adjust the view.
@@ -321,12 +311,9 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
// static
void LLFloaterWorldMap::reloadIcons(void*)
{
- LLWorldMap::getInstance()->eraseItems();
-
- LLWorldMap::getInstance()->sendMapLayerRequest();
+ LLWorldMap::getInstance()->reloadItems();
}
-
// virtual
BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
{
@@ -358,12 +345,6 @@ BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent )
{
LLFloater::reshape( width, height, called_from_parent );
-
- // Might have changed size of world display area
- // JC: Technically, this is correct, but it makes the slider "pop"
- // if you resize the window, then draw the slider. Just leaving it
- // the way it was when you opened the window seems better.
- // adjustZoomSliderBounds();
}
@@ -445,7 +426,7 @@ void LLFloaterWorldMap::draw()
childSetEnabled("Teleport", (BOOL)tracking_status);
// childSetEnabled("Clear", (BOOL)tracking_status);
- childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->mIsTrackingUnknownLocation);
+ childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->isTracking());
childSetEnabled("copy_slurl", (mSLURL.size() > 0) );
setMouseOpaque(TRUE);
@@ -465,6 +446,18 @@ void LLFloaterWorldMap::draw()
mCurZoomVal = lerp(mCurZoomVal, (F32)childGetValue("zoom slider").asReal(), interp);
F32 map_scale = 256.f*pow(2.f, mCurZoomVal);
LLWorldMapView::setScale( map_scale );
+
+ // Enable/disable checkboxes depending on the zoom level
+ // If above threshold level (i.e. low res) -> Disable all checkboxes
+ // If under threshold level (i.e. high res) -> Enable all checkboxes
+ bool enable = LLWorldMapView::showRegionInfo();
+ childSetEnabled("people_chk", enable);
+ childSetEnabled("infohub_chk", enable);
+ childSetEnabled("telehub_chk", enable);
+ childSetEnabled("land_for_sale_chk", enable);
+ childSetEnabled("event_chk", enable);
+ childSetEnabled("event_mature_chk", enable);
+ childSetEnabled("event_adult_chk", enable);
LLFloater::draw();
}
@@ -553,14 +546,14 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info)
{
mTrackedStatus = LLTracker::TRACKING_LOCATION;
- LLTracker::trackLocation(event_info.mPosGlobal, event_info.mName, event_info.mToolTip, LLTracker::LOCATION_EVENT);
+ LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT);
setDefaultBtn("Teleport");
}
void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item)
{
mTrackedStatus = LLTracker::TRACKING_LOCATION;
- LLTracker::trackLocation(item.mPosGlobal, item.mName, item.mToolTip, LLTracker::LOCATION_ITEM);
+ LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM);
setDefaultBtn("Teleport");
}
@@ -569,29 +562,27 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
if (!sim_info)
{
- LLWorldMap::getInstance()->mIsTrackingUnknownLocation = TRUE;
- LLWorldMap::getInstance()->mInvalidLocation = FALSE;
- LLWorldMap::getInstance()->mUnknownLocation = pos_global;
+ // We haven't found a region for that point yet, leave the tracking to the world map
+ LLWorldMap::getInstance()->setTracking(pos_global);
LLTracker::stopTracking(NULL);
S32 world_x = S32(pos_global.mdV[0] / 256);
S32 world_y = S32(pos_global.mdV[1] / 256);
- LLWorldMap::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
+ LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true);
setDefaultBtn("");
return;
}
- if (sim_info->mAccess == SIM_ACCESS_DOWN)
+ if (sim_info->isDown())
{
- // Down sim. Show the blue circle of death!
- LLWorldMap::getInstance()->mIsTrackingUnknownLocation = TRUE;
- LLWorldMap::getInstance()->mUnknownLocation = pos_global;
- LLWorldMap::getInstance()->mInvalidLocation = TRUE;
+ // Down region. Show the blue circle of death!
+ // i.e. let the world map that this and tell it it's invalid
+ LLWorldMap::getInstance()->setTracking(pos_global);
+ LLWorldMap::getInstance()->setTrackingInvalid();
LLTracker::stopTracking(NULL);
setDefaultBtn("");
return;
}
- std::string sim_name;
- LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name );
+ std::string sim_name = sim_info->getName();
F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS );
F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS );
std::string full_name = llformat("%s (%d, %d, %d)",
@@ -603,9 +594,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global)
std::string tooltip("");
mTrackedStatus = LLTracker::TRACKING_LOCATION;
LLTracker::trackLocation(pos_global, full_name, tooltip);
- LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
- LLWorldMap::getInstance()->mIsTrackingDoubleClick = FALSE;
- LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
+ LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking
setDefaultBtn("Teleport");
}
@@ -718,9 +707,9 @@ void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S3
// pass sim name to combo box
gFloaterWorldMap->mCompletingRegionName = region_name;
- LLWorldMap::getInstance()->sendNamedRegionRequest(region_name);
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name);
LLStringUtil::toLower(gFloaterWorldMap->mCompletingRegionName);
- LLWorldMap::getInstance()->mIsTrackingCommit = TRUE;
+ LLWorldMap::getInstance()->setTrackingCommit();
}
}
@@ -787,19 +776,12 @@ void LLFloaterWorldMap::buildAvatarIDList()
// Delete all but the "None" entry
S32 list_size = list->getItemCount();
- while (list_size > 1)
+ if (list_size > 1)
{
- list->selectNthItem(1);
+ list->selectItemRange(1, -1);
list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
- --list_size;
}
- LLSD default_column;
- default_column["name"] = "friend name";
- default_column["label"] = "Friend Name";
- default_column["width"] = 500;
- list->addColumn(default_column);
-
// Get all of the calling cards for avatar that are currently online
LLCollectMappableBuddies collector;
LLAvatarTracker::instance().applyFunctor(collector);
@@ -820,10 +802,7 @@ void LLFloaterWorldMap::buildAvatarIDList()
void LLFloaterWorldMap::buildLandmarkIDLists()
{
LLCtrlListInterface *list = childGetListInterface("landmark combo");
- if (!list)
- {
- return;
- }
+ if (!list) return;
// Delete all but the "None" entry
S32 list_size = list->getItemCount();
@@ -864,7 +843,6 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
mLandmarkAssetIDList.put( item->getAssetUUID() );
mLandmarkItemIDList.put( item->getUUID() );
}
- list->sortByColumn(std::string("landmark name"), TRUE);
list->selectFirstItem();
}
@@ -901,7 +879,7 @@ void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)
{
childSetValue("spin z", 0);
}
- LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
+ LLWorldMap::getInstance()->cancelTracking();
mCompletingRegionName = "";
}
@@ -937,18 +915,16 @@ void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
// can see the whole world, plus a little.
void LLFloaterWorldMap::adjustZoomSliderBounds()
{
- // World size in regions
- S32 world_width_regions = LLWorldMap::getInstance()->getWorldWidth() / REGION_WIDTH_UNITS;
- S32 world_height_regions = LLWorldMap::getInstance()->getWorldHeight() / REGION_WIDTH_UNITS;
-
- // Pad the world size a little bit, so we have a nice border on
- // the edge
- world_width_regions++;
- world_height_regions++;
+ // Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed
+ // width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across
+ // sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit.
+ // Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window.
+ S32 world_width_regions = MAX_VISIBLE_REGIONS;
+ S32 world_height_regions = MAX_VISIBLE_REGIONS;
// Find how much space we have to display the world
LLWorldMapView* map_panel;
- map_panel = (LLWorldMapView*)mTabs->getCurrentPanel();
+ map_panel = (LLWorldMapView*)mPanel;
LLRect view_rect = map_panel->getRect();
// View size in pixels
@@ -1161,15 +1137,15 @@ void LLFloaterWorldMap::onLocationCommit()
LLStringUtil::toLower(str);
mCompletingRegionName = str;
- LLWorldMap::getInstance()->mIsTrackingCommit = TRUE;
+ LLWorldMap::getInstance()->setTrackingCommit();
if (str.length() >= 3)
{
- LLWorldMap::getInstance()->sendNamedRegionRequest(str);
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
}
else
{
str += "#";
- LLWorldMap::getInstance()->sendNamedRegionRequest(str);
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
}
}
@@ -1177,8 +1153,8 @@ void LLFloaterWorldMap::onClearBtn()
{
mTrackedStatus = LLTracker::TRACKING_NOTHING;
LLTracker::stopTracking((void *)(intptr_t)TRUE);
- LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
- mSLURL = ""; // Clear the SLURL since it's invalid
+ LLWorldMap::getInstance()->cancelTracking();
+ mSLURL = ""; // Clear the SLURL since it's invalid
mSetToUserPosition = TRUE; // Revert back to the current user position
}
@@ -1230,9 +1206,9 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate)
pos_global = LLTracker::getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();
}
}
- else if(LLWorldMap::getInstance()->mIsTrackingUnknownLocation)
+ else if(LLWorldMap::getInstance()->isTracking())
{
- pos_global = LLWorldMap::getInstance()->mUnknownLocation - gAgent.getCameraPositionGlobal();;
+ pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();;
}
else
{
@@ -1240,8 +1216,8 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate)
pos_global.clearVec();
}
- LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sPixelsPerMeter)),
- -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sPixelsPerMeter)),
+ LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
+ -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)),
!animate);
mWaitingForTracker = FALSE;
}
@@ -1399,13 +1375,6 @@ void LLFloaterWorldMap::flyToAvatar()
}
}
-void LLFloaterWorldMap::onCommitBackground()
-{
- // Find my index
- S32 index = mTabs->getCurrentPanelIndex();
- LLWorldMap::getInstance()->setCurrentLayer(index);
-}
-
void LLFloaterWorldMap::updateSims(bool found_null_sim)
{
if (mCompletingRegionName == "")
@@ -1422,24 +1391,23 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
S32 num_results = 0;
std::map<U64, LLSimInfo*>::const_iterator it;
- for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
+ for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
{
- LLSimInfo* info = (*it).second;
- std::string sim_name = info->mName;
- std::string sim_name_lower = sim_name;
+ LLSimInfo* info = it->second;
+ std::string sim_name_lower = info->getName();
LLStringUtil::toLower(sim_name_lower);
if (sim_name_lower.substr(0, name_length) == mCompletingRegionName)
{
if (sim_name_lower == mCompletingRegionName)
{
- match = sim_name;
+ match = info->getName();
}
LLSD value;
- value["id"] = sim_name;
+ value["id"] = info->getName();
value["columns"][0]["column"] = "sim_name";
- value["columns"][0]["value"] = sim_name;
+ value["columns"][0]["value"] = info->getName();
list->addElement(value);
num_results++;
}
@@ -1496,15 +1464,13 @@ void LLFloaterWorldMap::onCommitSearchResult()
LLStringUtil::toLower(sim_name);
std::map<U64, LLSimInfo*>::const_iterator it;
- for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
+ for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
{
- LLSimInfo* info = (*it).second;
- std::string info_sim_name = info->mName;
- LLStringUtil::toLower(info_sim_name);
+ LLSimInfo* info = it->second;
- if (sim_name == info_sim_name)
+ if (info->isName(sim_name))
{
- LLVector3d pos_global = from_region_handle( info->mHandle );
+ LLVector3d pos_global = info->getGlobalOrigin();
F64 local_x = childGetValue("spin x");
F64 local_y = childGetValue("spin y");
F64 local_z = childGetValue("spin z");
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index 20a8e6d321..7feebb583d 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -96,7 +96,7 @@ public:
static const LLUUID& getHomeID() { return sHomeID; }
// A z_attenuation of 0.0f collapses the distance into the X-Y plane
- F32 getDistanceToDestination(const LLVector3d& pos_global, F32 z_attenuation = 0.5f) const;
+ F32 getDistanceToDestination(const LLVector3d& pos_global, F32 z_attenuation = 0.5f) const;
void clearLocationSelection(BOOL clear_ui = FALSE);
void clearAvatarSelection(BOOL clear_ui = FALSE);
@@ -121,8 +121,6 @@ protected:
void onAvatarComboPrearrange();
void onAvatarComboCommit();
- void onCommitBackground();
-
void onComboTextEntry( );
void onSearchTextEntry( LLLineEditor* ctrl );
@@ -155,10 +153,10 @@ protected:
void cacheLandmarkPosition();
-protected:
- LLTabContainer* mTabs;
+private:
+ LLPanel* mPanel; // Panel displaying the map
- // Sets gMapScale, in pixels per region
+ // Ties to LLWorldMapView::sMapScale, in pixels per region
F32 mCurZoomVal;
LLFrameTimer mZoomTimer;
diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp
index a341720aec..12796507ca 100644
--- a/indra/newview/lllandmarkactions.cpp
+++ b/indra/newview/lllandmarkactions.cpp
@@ -49,6 +49,7 @@
#include "llstring.h"
#include "llviewerinventory.h"
#include "llviewerparcelmgr.h"
+#include "llworldmapmessage.h"
#include "llviewerwindow.h"
#include "llwindow.h"
#include "llworldmap.h"
@@ -268,13 +269,13 @@ void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slur
{
U64 new_region_handle = to_region_handle(global_pos);
- LLWorldMap::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseSLURL,
+ LLWorldMapMessage::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseSLURL,
cb,
global_pos,
escaped,
_2);
- LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
+ LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
}
}
@@ -285,18 +286,19 @@ void LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(const LLVector3d& gl
if (sim_infop)
{
LLVector3 pos = sim_infop->getLocalPos(global_pos);
- cb(sim_infop->mName, llround(pos.mV[VX]), llround(pos.mV[VY]));
+ std::string name = sim_infop->getName() ;
+ cb(name, llround(pos.mV[VX]), llround(pos.mV[VY]));
}
else
{
U64 new_region_handle = to_region_handle(global_pos);
- LLWorldMap::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseNameAndCoords,
+ LLWorldMapMessage::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseNameAndCoords,
cb,
global_pos,
_1);
- LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
+ LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
}
}
@@ -328,7 +330,8 @@ void LLLandmarkActions::onRegionResponseNameAndCoords(region_name_and_coords_cal
if (sim_infop)
{
LLVector3 local_pos = sim_infop->getLocalPos(global_pos);
- cb(sim_infop->mName, llround(local_pos.mV[VX]), llround(local_pos.mV[VY]));
+ std::string name = sim_infop->getName() ;
+ cb(name, llround(local_pos.mV[VX]), llround(local_pos.mV[VY]));
}
}
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index b91e23eace..b60f0f1246 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -51,7 +51,7 @@
#include "llurlsimstring.h"
#include "llviewerinventory.h"
#include "llviewerparcelmgr.h"
-#include "llworldmap.h"
+#include "llworldmapmessage.h"
#include "llappviewer.h"
#include "llviewercontrol.h"
#include "llfloatermediabrowser.h"
@@ -386,14 +386,13 @@ void LLNavigationBar::onLocationSelection()
// Resolve the region name to its global coordinates.
// If resolution succeeds we'll teleport.
- LLWorldMap::url_callback_t cb = boost::bind(
+ LLWorldMapMessage::url_callback_t cb = boost::bind(
&LLNavigationBar::onRegionNameResponse, this,
typed_location, region_name, local_coords, _1, _2, _3, _4);
// connect the callback each time, when user enter new location to get real location of agent after teleport
mTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1,typed_location));
-
- LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);
}
void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location)
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index b6b433c28f..4286582cdc 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -65,9 +65,15 @@
static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
+const F32 LLNetMap::MAP_SCALE_MIN = 32;
+const F32 LLNetMap::MAP_SCALE_MID = 1024;
+const F32 LLNetMap::MAP_SCALE_MAX = 4096;
+
const F32 MAP_SCALE_INCREMENT = 16;
-const F32 MAP_MIN_PICK_DIST = 4;
-const F32 MAX_PRIM_RADIUS = 256.0f; // Don't try to draw giant mega-prims on the mini map
+const F32 MAP_SCALE_ZOOM_FACTOR = 1.04f; // Zoom in factor per click of scroll wheel (4%)
+const F32 MIN_DOT_RADIUS = 3.5f;
+const F32 DOT_SCALE = 0.75f;
+const F32 MIN_PICK_SCALE = 2.f;
LLNetMap::LLNetMap (const Params & p)
: LLUICtrl (p),
@@ -89,6 +95,7 @@ LLNetMap::LLNetMap (const Params & p)
mRotateMap(FALSE),
mToolTipMsg()
{
+ mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
}
LLNetMap::~LLNetMap()
@@ -101,17 +108,18 @@ void LLNetMap::setScale( F32 scale )
if (mObjectImagep.notNull())
{
- F32 half_width = (F32)(getRect().getWidth() / 2);
- F32 half_height = (F32)(getRect().getHeight() / 2);
- F32 radius = sqrt( half_width * half_width + half_height * half_height );
- F32 region_widths = (2.f*radius)/mScale;
+ F32 width = (F32)(getRect().getWidth());
+ F32 height = (F32)(getRect().getHeight());
+ F32 diameter = sqrt(width * width + height * height);
+ F32 region_widths = diameter / mScale;
F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters();
F32 num_pixels = (F32)mObjectImagep->getWidth();
- mObjectMapTPM = num_pixels/meters;
- mObjectMapPixels = 2.f*radius;
+ mObjectMapTPM = num_pixels / meters;
+ mObjectMapPixels = diameter;
}
mPixelsPerMeter = mScale / REGION_WIDTH_METERS;
+ mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
mUpdateNow = TRUE;
}
@@ -302,6 +310,7 @@ void LLNetMap::draw()
LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
mClosestAgentToCursor.setNull();
F32 closest_dist = F32_MAX;
+ F32 min_pick_dist = mDotRadius * MIN_PICK_SCALE;
// Draw avatars
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
@@ -345,10 +354,10 @@ void LLNetMap::draw()
LLWorldMapView::drawAvatar(
pos_map.mV[VX], pos_map.mV[VY],
show_as_friend ? map_avatar_friend_color : map_avatar_color,
- pos_map.mV[VZ]);
+ pos_map.mV[VZ], mDotRadius);
F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y));
- if(dist_to_cursor < MAP_MIN_PICK_DIST && dist_to_cursor < closest_dist)
+ if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist)
{
closest_dist = dist_to_cursor;
mClosestAgentToCursor = regionp->mMapAvatarIDs.get(i);
@@ -378,10 +387,12 @@ void LLNetMap::draw()
// Draw dot for self avatar position
pos_global = gAgent.getPositionGlobal();
pos_map = globalPosToView(pos_global);
- LLUIImagePtr you = LLWorldMapView::sAvatarYouSmallImage;
- you->draw(
- llround(pos_map.mV[VX]) - you->getWidth()/2,
- llround(pos_map.mV[VY]) - you->getHeight()/2);
+ LLUIImagePtr you = LLWorldMapView::sAvatarYouLargeImage;
+ S32 dot_width = llround(mDotRadius * 2.f);
+ you->draw(llround(pos_map.mV[VX] - mDotRadius),
+ llround(pos_map.mV[VY] - mDotRadius),
+ dot_width,
+ dot_width);
// Draw frustum
F32 meters_to_pixels = mScale/ LLWorld::getInstance()->getRegionWidthInMeters();
@@ -429,6 +440,12 @@ void LLNetMap::draw()
LLUICtrl::draw();
}
+void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ LLUICtrl::reshape(width, height, called_from_parent);
+ createObjectImage();
+}
+
LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos )
{
LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal();
@@ -504,8 +521,12 @@ LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
{
- // note that clicks are reversed from what you'd think
- setScale(llclamp(mScale - clicks*MAP_SCALE_INCREMENT, MAP_SCALE_MIN, MAP_SCALE_MAX));
+ // note that clicks are reversed from what you'd think: i.e. > 0 means zoom out, < 0 means zoom in
+ F32 scale = mScale;
+
+ scale *= pow(MAP_SCALE_ZOOM_FACTOR, -clicks);
+ setScale(llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX));
+
return TRUE;
}
@@ -567,9 +588,7 @@ void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &
LLVector3 local_pos;
local_pos.setVec( pos - mObjectImageCenterGlobal );
- F32 radius_clamped = llmin(radius_meters, MAX_PRIM_RADIUS);
-
- S32 diameter_pixels = llround(2 * radius_clamped * mObjectMapTPM);
+ S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM);
renderPoint( local_pos, color, diameter_pixels );
}
@@ -662,13 +681,13 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color,
void LLNetMap::createObjectImage()
{
// Find the size of the side of a square that surrounds the circle that surrounds getRect().
- F32 half_width = (F32)(getRect().getWidth() / 2);
- F32 half_height = (F32)(getRect().getHeight() / 2);
- F32 radius = sqrt( half_width * half_width + half_height * half_height );
- S32 square_size = S32( 2 * radius );
+ // ... which is, the diagonal of the rect.
+ F32 width = (F32)getRect().getWidth();
+ F32 height = (F32)getRect().getHeight();
+ S32 square_size = llround( sqrt(width*width + height*height) );
// Find the least power of two >= the minimum size.
- const S32 MIN_SIZE = 32;
+ const S32 MIN_SIZE = 64;
const S32 MAX_SIZE = 256;
S32 img_size = MIN_SIZE;
while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) )
@@ -684,7 +703,7 @@ void LLNetMap::createObjectImage()
U8* data = mObjectRawImagep->getData();
memset( data, 0, img_size * img_size * 4 );
mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE);
- setScale(mScale);
}
+ setScale(mScale);
mUpdateNow = TRUE;
}
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index 5ebdd13384..7088ab3e70 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -70,9 +70,14 @@ protected:
public:
virtual ~LLNetMap();
+ static const F32 MAP_SCALE_MIN;
+ static const F32 MAP_SCALE_MID;
+ static const F32 MAP_SCALE_MAX;
+
/*virtual*/ void draw();
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
/*virtual*/ BOOL handleToolTip( S32 x, S32 y, MASK mask);
+ /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
void setScale( F32 scale );
void setRotateMap( BOOL b ) { mRotateMap = b; }
@@ -94,16 +99,17 @@ private:
void drawTracking( const LLVector3d& pos_global,
const LLColor4& color,
BOOL draw_arrow = TRUE);
-
- void createObjectImage();
+ void createObjectImage();
+
private:
LLUIColor mBackgroundColor;
F32 mScale; // Size of a region in pixels
F32 mPixelsPerMeter; // world meters to map pixels
F32 mObjectMapTPM; // texels per meter on map
- F32 mObjectMapPixels; // Width of object map in pixels;
+ F32 mObjectMapPixels; // Width of object map in pixels
+ F32 mDotRadius; // Size of avatar markers
F32 mTargetPanX;
F32 mTargetPanY;
F32 mCurPanX;
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index 7dd9df674c..92040eb2e5 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -357,7 +357,7 @@ void LLTeleportHistoryPanel::onCopySLURL()
U64 new_region_handle = to_region_handle(global_pos);
- LLWorldMap::url_callback_t cb = boost::bind(
+ LLWorldMapMessage::url_callback_t cb = boost::bind(
&LLPanelPlacesTab::onRegionResponse, this,
global_pos, _1, _2, _3, _4);
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 9c21faa3be..a44794122f 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -192,6 +192,11 @@ void LLPreviewTexture::draw()
// Pump the texture priority
F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() );
mImage->addTextureStats( pixel_area );
+ if(pixel_area > 0.f)
+ {
+ //boost the previewed image priority to the highest to make it to get loaded first.
+ mImage->setAdditionalDecodePriority(1.0f) ;
+ }
// Don't bother decoding more than we can display, unless
// we're loading the full image.
@@ -554,6 +559,7 @@ void LLPreviewTexture::loadAsset()
{
mImage = LLViewerTextureManager::getFetchedTexture(mImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
mImage->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);
+ mImage->forceToSaveRawImage(0) ;
mAssetStatus = PREVIEW_ASSET_LOADING;
updateDimensions();
}
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 9f317803ce..5afb821d15 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2679,8 +2679,7 @@ void renderTexturePriority(LLDrawable* drawable)
//LLViewerTexture* imagep = facep->getTexture();
//if (imagep)
{
-
- //F32 vsize = LLVOVolume::getTextureVirtualSize(facep);
+
//F32 vsize = imagep->mMaxVirtualSize;
F32 vsize = facep->getPixelArea();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 51b651d58e..bfe753a0aa 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -61,6 +61,7 @@
#include "llfocusmgr.h"
#include "llhttpsender.h"
#include "lllocationhistory.h"
+#include "llimageworker.h"
#include "llloginflags.h"
#include "llmd5.h"
#include "llmemorystream.h"
@@ -170,7 +171,7 @@
#include "llvoclouds.h"
#include "llweb.h"
#include "llworld.h"
-#include "llworldmap.h"
+#include "llworldmapmessage.h"
#include "llxfermanager.h"
#include "pipeline.h"
#include "llappviewer.h"
@@ -1812,6 +1813,7 @@ bool idle_startup()
gViewerWindow->moveProgressViewToFront();
LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
+
// set initial visibility of debug console
gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
}
@@ -3266,9 +3268,8 @@ void register_viewer_callbacks(LLMessageSystem* msg)
msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply);
- msg->setHandlerFunc("MapLayerReply", LLWorldMap::processMapLayerReply);
- msg->setHandlerFunc("MapBlockReply", LLWorldMap::processMapBlockReply);
- msg->setHandlerFunc("MapItemReply", LLWorldMap::processMapItemReply);
+ msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply);
+ msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply);
msg->setHandlerFunc("EventInfoReply", LLPanelEvent::processEventInfoReply);
msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply);
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index 5440b2c9ad..1d479bac8c 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -234,12 +234,7 @@ void LLSurface::createSTexture()
{
if (!mSTexturep)
{
- // Fill with dummy gray data.
-
- //mSTexturep = LLViewerTextureManager::getLocalTexture(sTextureSize, sTextureSize, 3, FALSE);
- //mSTexturep->dontDiscard();
- //mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
-
+ // Fill with dummy gray data.
// GL NOT ACTIVE HERE
LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3);
U8 *default_texture = raw->getData();
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 5d9046ac90..4ff5906b7e 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -1371,7 +1371,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, BOOL render_morph)
LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
- gGL.getTexUnit(0)->bind(tex);
+ gGL.getTexUnit(0)->bind(tex, TRUE);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
gl_rect_2d_simple_tex( width, height );
@@ -1393,7 +1393,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, BOOL render_morph)
LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
if( tex )
{
- gGL.getTexUnit(0)->bind(tex);
+ gGL.getTexUnit(0)->bind(tex, TRUE);
gl_rect_2d_simple_tex( width, height );
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
@@ -1506,7 +1506,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
if( tex )
{
LLGLSNoAlphaTest gls_no_alpha_test;
- gGL.getTexUnit(0)->bind(tex);
+ gGL.getTexUnit(0)->bind(tex, TRUE);
gl_rect_2d_simple_tex( width, height );
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
@@ -1585,7 +1585,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
- gGL.getTexUnit(0)->bind(tex);
+ gGL.getTexUnit(0)->bind(tex, TRUE);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
gl_rect_2d_simple_tex( width, height );
@@ -1608,7 +1608,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
( (tex->getComponents() == 1) && getInfo()->mStaticImageIsMask ) )
{
LLGLSNoAlphaTest gls_no_alpha_test;
- gGL.getTexUnit(0)->bind(tex);
+ gGL.getTexUnit(0)->bind(tex, TRUE);
gl_rect_2d_simple_tex( width, height );
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
@@ -2034,7 +2034,7 @@ LLViewerTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_n
// that once an image is a mask it's always a mask.
tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA );
}
- tex->createGLTexture(0, image_raw);
+ tex->createGLTexture(0, image_raw, 0, TRUE, LLViewerTexture::LOCAL);
gGL.getTexUnit(0)->bind(tex);
tex->setAddressMode(LLTexUnit::TAM_CLAMP);
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 1b249d75d1..69a2d1d7a6 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -43,11 +43,17 @@
// Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout
#include "llappviewer.h"
-#define USE_LFS_READ 0
-#define USE_LFS_WRITE 0
-
-// Note: first 4 bytes store file size, rest is j2c data
-const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024;
+// Cache organization:
+// cache/texture.entries
+// Unordered array of Entry structs
+// cache/texture.cache
+// First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order
+// cache/textures/[0-F]/UUID.texture
+// Actual texture body files
+
+const S32 TEXTURE_CACHE_ENTRY_SIZE = 1024;
+const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
+const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
class LLTextureCacheWorker : public LLWorkerClass
{
@@ -309,94 +315,75 @@ void LLTextureCacheWorker::startWork(S32 param)
{
}
+// This is where a texture is read from the cache system (header and body)
+// Current assumption are:
+// - the whole data are in a raw form, will be stored at mReadData
+// - 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)
+// - the code supports offset reading but this is actually never exercised in the viewer
bool LLTextureCacheRemoteWorker::doRead()
{
+ bool done = false;
+ S32 idx = -1;
+
S32 local_size = 0;
std::string local_filename;
+ // First state / stage : find out if the file is local
if (mState == INIT)
{
std::string filename = mCache->getLocalFileName(mID);
- local_filename = filename + ".j2c";
- local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
- if (local_size == 0)
+ // Is it a JPEG2000 file?
{
- local_filename = filename + ".tga";
+ local_filename = filename + ".j2c";
local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
if (local_size > 0)
{
- mImageFormat = IMG_CODEC_TGA;
- mDataSize = local_size; // Only a complete .tga file is valid
+ mImageFormat = IMG_CODEC_J2C;
}
}
- if (local_size > 0)
- {
- mState = LOCAL;
- }
- else
- {
- mState = CACHE;
- }
- }
-
- if (mState == LOCAL)
- {
-#if USE_LFS_READ
- if (mFileHandle == LLLFSThread::nullHandle())
+ // If not, is it a jpeg file?
+ if (local_size == 0)
{
- mImageLocal = TRUE;
- mImageSize = local_size;
- if (!mDataSize || mDataSize + mOffset > local_size)
+ local_filename = filename + ".jpg";
+ local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+ if (local_size > 0)
{
- mDataSize = local_size - mOffset;
+ mImageFormat = IMG_CODEC_JPEG;
+ mDataSize = local_size; // Only a complete .jpg file is valid
}
- if (mDataSize <= 0)
- {
- // no more data to read
- mDataSize = 0;
- return true;
- }
- mReadData = new U8[mDataSize];
- mBytesRead = -1;
- mBytesToRead = mDataSize;
- setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
- mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
- new ReadResponder(mCache, mRequestHandle));
- return false;
}
- else
+ // Hmm... What about a targa file? (used for UI texture mostly)
+ if (local_size == 0)
{
- if (mBytesRead >= 0)
- {
- if (mBytesRead != mBytesToRead)
- {
-// llwarns << "Error reading file from local cache: " << local_filename
-// << " Bytes: " << mDataSize << " Offset: " << mOffset
-// << " / " << mDataSize << llendl;
- mDataSize = 0; // failed
- delete[] mReadData;
- mReadData = NULL;
- }
- return true;
- }
- else
+ local_filename = filename + ".tga";
+ local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+ if (local_size > 0)
{
- return false;
+ mImageFormat = IMG_CODEC_TGA;
+ mDataSize = local_size; // Only a complete .tga file is valid
}
}
-#else
+ // Determine the next stage: if we found a file, then LOCAL else CACHE
+ mState = (local_size > 0 ? LOCAL : CACHE);
+ }
+
+ // Second state / stage : if the file is local, load it and leave
+ if (!done && (mState == LOCAL))
+ {
+ llassert(local_size != 0); // we're assuming there is a non empty local file here...
if (!mDataSize || mDataSize > local_size)
{
mDataSize = local_size;
}
+ // Allocate read buffer
mReadData = new U8[mDataSize];
S32 bytes_read = LLAPRFile::readEx(local_filename,
mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
if (bytes_read != mDataSize)
{
-// llwarns << "Error reading file from local cache: " << local_filename
-// << " Bytes: " << mDataSize << " Offset: " << mOffset
-// << " / " << mDataSize << llendl;
+ llwarns << "Error reading file from local cache: " << local_filename
+ << " Bytes: " << mDataSize << " Offset: " << mOffset
+ << " / " << mDataSize << llendl;
mDataSize = 0;
delete[] mReadData;
mReadData = NULL;
@@ -406,405 +393,275 @@ bool LLTextureCacheRemoteWorker::doRead()
mImageSize = local_size;
mImageLocal = TRUE;
}
- return true;
-#endif
+ // We're done...
+ done = true;
}
- S32 idx = -1;
-
- if (mState == CACHE)
+ // Second state / stage : identify the cache or not...
+ if (!done && (mState == CACHE))
{
- llassert_always(mImageSize == 0);
- idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
- if (idx >= 0 && mImageSize > mOffset)
+ idx = mCache->getHeaderCacheEntry(mID, mImageSize);
+ if (idx < 0)
{
- llassert_always(mImageSize > 0);
- if (!mDataSize || mDataSize > mImageSize)
- {
- mDataSize = mImageSize;
- }
- mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+ // The texture is *not* cached. We're done here...
+ mDataSize = 0; // no data
+ done = true;
}
else
{
- mDataSize = 0; // no data
- return true;
+ // If the read offset is bigger than the header cache, we read directly from the body
+ // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
+ mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
}
}
- if (mState == HEADER)
+ // Third state / stage : read data from the header cache (texture.entries) file
+ if (!done && (mState == HEADER))
{
-#if USE_LFS_READ
- if (mFileHandle == LLLFSThread::nullHandle())
- {
- llassert_always(idx >= 0);
- llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
- S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
- S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- llassert_always(mReadData == NULL);
- mReadData = new U8[size];
- mBytesRead = -1;
- mBytesToRead = size;
- setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
- mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
- mReadData, offset, mBytesToRead,
- new ReadResponder(mCache, mRequestHandle));
- return false;
- }
- else
- {
- if (mBytesRead >= 0)
- {
- if (mBytesRead != mBytesToRead)
- {
-// llwarns << "LLTextureCacheWorker: " << mID
-// << " incorrect number of bytes read from header: " << mBytesRead
-// << " != " << mBytesToRead << llendl;
- mDataSize = -1; // failed
- return true;
- }
- if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
- {
- return true; // done
- }
- else
- {
- mFileHandle = LLLFSThread::nullHandle();
- mState = BODY;
- }
- }
- else
- {
- return false;
- }
- }
-#else
- llassert_always(idx >= 0);
+ llassert_always(idx >= 0); // we need an entry here or reading the header makes no sense
llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+ // Compute the size we need to read (in bytes)
S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+ size = llmin(size, mDataSize);
+ // Allocate the read buffer
mReadData = new U8[size];
S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName,
mReadData, offset, size, mCache->getLocalAPRFilePool());
if (bytes_read != size)
{
-// llwarns << "LLTextureCacheWorker: " << mID
-// << " incorrect number of bytes read from header: " << bytes_read
-// << " / " << size << llendl;
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from header: " << bytes_read
+ << " / " << size << llendl;
+ delete[] mReadData;
+ mReadData = NULL;
mDataSize = -1; // failed
- return true;
+ done = true;
}
- if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
+ // If we already read all we expected, we're actually done
+ if (mDataSize <= bytes_read)
{
- return true; // done
+ done = true;
}
else
{
mState = BODY;
}
-#endif
}
- if (mState == BODY)
+ // Fourth state / stage : read the rest of the data from the UUID based cached file
+ if (!done && (mState == BODY))
{
-#if USE_LFS_READ
- if (mFileHandle == LLLFSThread::nullHandle())
- {
- std::string filename = mCache->getTextureFileName(mID);
- S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
- if (filesize > mOffset)
- {
- S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
- mDataSize = llmin(datasize, mDataSize);
- S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- data_offset = llmax(data_offset, 0);
- S32 file_size = mDataSize - data_offset;
- S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
- file_offset = llmax(file_offset, 0);
-
- llassert_always(mDataSize > 0);
- U8* data = new U8[mDataSize];
- if (data_offset > 0)
- {
- llassert_always(mReadData);
- llassert_always(data_offset <= mDataSize);
- memcpy(data, mReadData, data_offset);
- delete[] mReadData;
- mReadData = NULL;
- }
- llassert_always(mReadData == NULL);
- mReadData = data;
-
- mBytesRead = -1;
- mBytesToRead = file_size;
- setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
- llassert_always(data_offset + mBytesToRead <= mDataSize);
- mFileHandle = LLLFSThread::sLocal->read(filename,
- mReadData + data_offset, file_offset, mBytesToRead,
- new ReadResponder(mCache, mRequestHandle));
- return false;
- }
- else
- {
- mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
- return true; // done
- }
- }
- else
- {
- if (mBytesRead >= 0)
- {
- if (mBytesRead != mBytesToRead)
- {
-// llwarns << "LLTextureCacheWorker: " << mID
-// << " incorrect number of bytes read from body: " << mBytesRead
-// << " != " << mBytesToRead << llendl;
- mDataSize = -1; // failed
- }
- return true;
- }
- else
- {
- return false;
- }
- }
-#else
std::string filename = mCache->getTextureFileName(mID);
S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
- S32 bytes_read = 0;
- if (filesize > mOffset)
+
+ if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)
{
- S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
- mDataSize = llmin(datasize, mDataSize);
- S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- data_offset = llmax(data_offset, 0);
- S32 file_size = mDataSize - data_offset;
- S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
- file_offset = llmax(file_offset, 0);
+ S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset;
+ mDataSize = llmin(max_datasize, mDataSize);
+
+ S32 data_offset, file_size, file_offset;
+ // Reserve the whole data buffer first
U8* data = new U8[mDataSize];
- if (data_offset > 0)
+
+ // Set the data file pointers taking the read offset into account. 2 cases:
+ if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
{
+ // Offset within the header record. That means we read something from the header cache.
+ // Note: most common case is (mOffset = 0), so this is the "normal" code path.
+ data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset; // i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
+ file_offset = 0;
+ file_size = mDataSize - data_offset;
+ // Copy the raw data we've been holding from the header cache into the new sized buffer
llassert_always(mReadData);
memcpy(data, mReadData, data_offset);
delete[] mReadData;
+ mReadData = NULL;
+ }
+ else
+ {
+ // Offset bigger than the header record. That means we haven't read anything yet.
+ data_offset = 0;
+ file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+ file_size = mDataSize;
+ // No data from header cache to copy in that case, we skipped it all
}
+
+ // Now use that buffer as the object read buffer
+ llassert_always(mReadData == NULL);
mReadData = data;
- bytes_read = LLAPRFile::readEx(filename,
+
+ // Read the data at last
+ S32 bytes_read = LLAPRFile::readEx(filename,
mReadData + data_offset,
file_offset, file_size,
mCache->getLocalAPRFilePool());
if (bytes_read != file_size)
{
-// llwarns << "LLTextureCacheWorker: " << mID
-// << " incorrect number of bytes read from body: " << bytes_read
-// << " / " << file_size << llendl;
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes read from body: " << bytes_read
+ << " / " << file_size << llendl;
+ delete[] mReadData;
+ mReadData = NULL;
mDataSize = -1; // failed
- return true;
+ done = true;
}
}
else
{
- mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
- }
-
- return true;
-#endif
+ // No body, we're done.
+ mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0);
+ lldebugs << "No body file for: " << filename << llendl;
+ }
+ // Nothing else to do at that point...
+ done = true;
}
-
- return false;
+
+ // Clean up and exit
+ return done;
}
+// This is where *everything* about a texture is written down in the cache system (entry map, header and body)
+// Current assumption are:
+// - the whole data are in a raw form, starting at mWriteData
+// - 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)
+// - the code *does not* support offset writing so there are no difference between buffer addresses and start of data
bool LLTextureCacheRemoteWorker::doWrite()
{
+ bool done = false;
S32 idx = -1;
- // No LOCAL state for write()
-
+ // First state / stage : check that what we're trying to cache is in an OK shape
if (mState == INIT)
{
+ llassert_always(mOffset == 0); // We currently do not support write offsets
+ llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
+ mState = CACHE;
+ }
+
+ // No LOCAL state for write(): because it doesn't make much sense to cache a local file...
+
+ // Second state / stage : set an entry in the headers entry (texture.entries) file
+ if (!done && (mState == CACHE))
+ {
+ bool alreadyCached = false;
S32 cur_imagesize = 0;
- S32 offset = mOffset;
- idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
- if (idx >= 0 && cur_imagesize > 0)
+ // Checks if this image is already in the entry list
+ idx = mCache->getHeaderCacheEntry(mID, cur_imagesize);
+ if (idx >= 0 && (cur_imagesize >= 0))
{
- offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header
+ alreadyCached = true; // already there and non empty
}
- idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry
- if (idx >= 0)
+ idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry
+ if (idx < 0)
{
- if(cur_imagesize > 0 && mImageSize != cur_imagesize)
- {
-// llwarns << "Header cache entry size: " << cur_imagesize << " != mImageSize: " << mImageSize << llendl;
- offset = 0; // re-write header
- }
- mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " Unable to create header entry for writing!" << llendl;
+ mDataSize = -1; // failed
+ done = true;
}
else
{
- mDataSize = -1; // failed
- return true;
+ if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
+ {
+ alreadyCached = false; // re-write the header if the size changed in all cases
+ }
+ if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
+ {
+ // Small texture already cached case: we're done with writing
+ done = true;
+ }
+ else
+ {
+ // If the texture has already been cached, we don't resave the header and go directly to the body part
+ mState = alreadyCached ? BODY : HEADER;
+ }
}
}
-
- if (mState == HEADER)
+
+ // Third stage / state : write the header record in the header file (texture.cache)
+ if (!done && (mState == HEADER))
{
-#if USE_LFS_WRITE
- if (mFileHandle == LLLFSThread::nullHandle())
+ llassert_always(idx >= 0); // we need an entry here or storing the header makes no sense
+ S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file
+ S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header
+ S32 bytes_written;
+
+ if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
{
- llassert_always(idx >= 0);
- llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
- S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
- S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- mBytesRead = -1;
- mBytesToRead = size;
- setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
- mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
- mWriteData, offset, mBytesToRead,
- new WriteResponder(mCache, mRequestHandle));
- return false;
+ // We need to write a full record in the header cache so, if the amount of data is smaller
+ // than a record, we need to transfer the data to a buffer padded with 0 and write that
+ U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE];
+ memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros
+ memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer
+ bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool());
+ delete [] padBuffer;
}
else
{
- if (mBytesRead >= 0)
- {
- if (mBytesRead != mBytesToRead)
- {
-// llwarns << "LLTextureCacheWorker: " << mID
-// << " incorrect number of bytes written to header: " << mBytesRead
-// << " != " << mBytesToRead << llendl;
- mDataSize = -1; // failed
- return true;
- }
- if (mDataSize <= mBytesToRead)
- {
- return true; // done
- }
- else
- {
- mFileHandle = LLLFSThread::nullHandle();
- mState = BODY;
- }
- }
- else
- {
- return false;
- }
+ // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
+ bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
}
-#else
- llassert_always(idx >= 0);
- llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
- S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
- S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- S32 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
if (bytes_written <= 0)
{
-// llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " Unable to write header entry!" << llendl;
mDataSize = -1; // failed
- return true;
+ done = true;
}
- if (mDataSize <= size)
+ // If we wrote everything (may be more with padding) in the header cache,
+ // we're done so we don't have a body to store
+ if (mDataSize <= bytes_written)
{
- return true; // done
+ done = true;
}
else
{
mState = BODY;
}
-#endif
}
- if (mState == BODY)
+ // Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name
+ if (!done && (mState == BODY))
{
-#if USE_LFS_WRITE
- if (mFileHandle == LLLFSThread::nullHandle())
+ llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
+ S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
+ if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size))
{
- S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- data_offset = llmax(data_offset, 0);
- S32 file_size = mDataSize - data_offset;
- S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
- file_offset = llmax(file_offset, 0);
- if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
- {
- std::string filename = mCache->getTextureFileName(mID);
- mBytesRead = -1;
- mBytesToRead = file_size;
- setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
- mFileHandle = LLLFSThread::sLocal->write(filename,
- mWriteData + data_offset, file_offset, mBytesToRead,
- new WriteResponder(mCache, mRequestHandle));
- return false;
- }
- else
- {
- mDataSize = 0; // no data written
- return true; // done
- }
- }
- else
- {
- if (mBytesRead >= 0)
- {
- if (mBytesRead != mBytesToRead)
- {
-// llwarns << "LLTextureCacheWorker: " << mID
-// << " incorrect number of bytes written to body: " << mBytesRead
-// << " != " << mBytesToRead << llendl;
- mDataSize = -1; // failed
- }
- return true;
- }
- else
- {
- return false;
- }
- }
-#else
- S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
- data_offset = llmax(data_offset, 0);
- S32 file_size = mDataSize - data_offset;
- S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
- file_offset = llmax(file_offset, 0);
- S32 bytes_written = 0;
- if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
- {
- std::string filename = mCache->getTextureFileName(mID);
-
- bytes_written = LLAPRFile::writeEx(filename,
- mWriteData + data_offset,
- file_offset, file_size,
- mCache->getLocalAPRFilePool());
+ // build the cache file name from the UUID
+ std::string filename = mCache->getTextureFileName(mID);
+// llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;
+ S32 bytes_written = LLAPRFile::writeEx( filename,
+ mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
+ 0, file_size,
+ mCache->getLocalAPRFilePool());
if (bytes_written <= 0)
{
+ llwarns << "LLTextureCacheWorker: " << mID
+ << " incorrect number of bytes written to body: " << bytes_written
+ << " / " << file_size << llendl;
mDataSize = -1; // failed
+ done = true;
}
}
else
{
mDataSize = 0; // no data written
}
-
- return true;
-#endif
+ // Nothing else to do at that point...
+ done = true;
}
-
- return false;
+
+ // Clean up and exit
+ return done;
}
//virtual
bool LLTextureCacheWorker::doWork(S32 param)
{
-// *TODO reenable disabled apr_pool usage disabled due to maint-render-9 merge breakage -brad
- //allocate a new local apr_pool
-// LLAPRPool pool ;
-
- //save the current mFileAPRPool to avoid breaking anything.
-// apr_pool_t* old_pool = mCache->getFileAPRPool() ;
- //make mFileAPRPool to point to the local one
-// mCache->setFileAPRPool(pool.getAPRPool()) ;
-
bool res = false;
if (param == 0) // read
{
@@ -818,10 +675,6 @@ bool LLTextureCacheWorker::doWork(S32 param)
{
llassert_always(0);
}
-
- //set mFileAPRPool back, the local one will be released automatically.
-// mCache->setFileAPRPool(old_pool) ;
-
return res;
}
@@ -887,6 +740,7 @@ LLTextureCache::LLTextureCache(bool threaded)
mWorkersMutex(NULL),
mHeaderMutex(NULL),
mListMutex(NULL),
+ mHeaderAPRFile(NULL),
mReadOnly(FALSE),
mTexturesSizeTotal(0),
mDoPurge(FALSE)
@@ -926,6 +780,9 @@ S32 LLTextureCache::update(U32 max_time_ms)
}
}
+ unlockWorkers();
+
+ // call 'completed' with workers list unlocked (may call readComplete() or writeComplete()
for (responder_list_t::iterator iter1 = completed_list.begin();
iter1 != completed_list.end(); ++iter1)
{
@@ -934,8 +791,6 @@ S32 LLTextureCache::update(U32 max_time_ms)
responder->completed(success);
}
- unlockWorkers();
-
return res;
}
@@ -954,33 +809,48 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id)
{
std::string idstr = id.asString();
std::string delem = gDirUtilp->getDirDelimiter();
- std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
+ std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture";
return filename;
}
-bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
+bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize)
{
bool res = false;
bool purge = false;
- // Append UUID to end of texture entries
{
LLMutexLock lock(&mHeaderMutex);
- size_map_t::iterator iter = mTexturesSizeMap.find(id);
- if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
+ size_map_t::iterator iter1 = mTexturesSizeMap.find(id);
+ if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize)
{
llassert_always(bodysize > 0);
- Entry* entry = new Entry(id, bodysize, time(NULL));
- LLAPRFile::writeEx(mTexturesDirEntriesFileName,
- (U8*)entry, -1, 1*sizeof(Entry),
- getLocalAPRFilePool());
- delete entry;
- if (iter != mTexturesSizeMap.end())
+ S32 oldbodysize = 0;
+ if (iter1 != mTexturesSizeMap.end())
+ {
+ oldbodysize = iter1->second;
+ }
+
+ Entry entry;
+ S32 idx = openAndReadEntry(id, entry, false);
+ if (idx < 0)
+ {
+ // TODO: change to llwarns
+ llerrs << "Failed to open entry: " << id << llendl;
+ removeFromCache(id);
+ return false;
+ }
+ else if (oldbodysize != entry.mBodySize)
{
- mTexturesSizeTotal -= iter->second;
+ // TODO: change to llwarns
+ llerrs << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
+ << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
}
+ entry.mBodySize = bodysize;
+ writeEntryAndClose(idx, entry);
+
+ mTexturesSizeTotal -= oldbodysize;
mTexturesSizeTotal += bodysize;
- mTexturesSizeMap[id] = bodysize;
+
if (mTexturesSizeTotal > sCacheMaxTexturesSize)
{
purge = true;
@@ -995,11 +865,59 @@ bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
return res;
}
+//debug
+BOOL LLTextureCache::isInCache(const LLUUID& id)
+{
+ LLMutexLock lock(&mHeaderMutex);
+ id_map_t::const_iterator iter = mHeaderIDMap.find(id);
+
+ return (iter != mHeaderIDMap.end()) ;
+}
+
+//debug
+BOOL LLTextureCache::isInLocal(const LLUUID& id)
+{
+ S32 local_size = 0;
+ std::string local_filename;
+
+ std::string filename = getLocalFileName(id);
+ // Is it a JPEG2000 file?
+ {
+ local_filename = filename + ".j2c";
+ local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+ if (local_size > 0)
+ {
+ return TRUE ;
+ }
+ }
+
+ // If not, is it a jpeg file?
+ {
+ local_filename = filename + ".jpg";
+ local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+ if (local_size > 0)
+ {
+ return TRUE ;
+ }
+ }
+
+ // Hmm... What about a targa file? (used for UI texture mostly)
+ {
+ local_filename = filename + ".tga";
+ local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+ if (local_size > 0)
+ {
+ return TRUE ;
+ }
+ }
+
+ return FALSE ;
+}
//////////////////////////////////////////////////////////////////////////////
//static
const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
-F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
+F32 LLTextureCache::sHeaderCacheVersion = 1.3f;
U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
const char* entries_filename = "texture.entries";
@@ -1012,7 +930,6 @@ void LLTextureCache::setDirNames(ELLPath location)
mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
- mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
}
void LLTextureCache::purgeCache(ELLPath location)
@@ -1020,7 +937,7 @@ void LLTextureCache::purgeCache(ELLPath location)
if (!mReadOnly)
{
setDirNames(location);
-
+ llassert_always(mHeaderAPRFile == NULL);
LLAPRFile::remove(mHeaderEntriesFileName, getLocalAPRFilePool());
LLAPRFile::remove(mHeaderDataFileName, getLocalAPRFilePool());
}
@@ -1063,83 +980,317 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
return max_size; // unused cache space
}
-struct lru_data
+//----------------------------------------------------------------------------
+// mHeaderMutex must be locked for the following functions!
+
+LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
+{
+ llassert_always(mHeaderAPRFile == NULL);
+ apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
+ mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool());
+ mHeaderAPRFile->seek(APR_SET, offset);
+ return mHeaderAPRFile;
+}
+
+void LLTextureCache::closeHeaderEntriesFile()
+{
+ llassert_always(mHeaderAPRFile != NULL);
+ delete mHeaderAPRFile;
+ mHeaderAPRFile = NULL;
+}
+
+void LLTextureCache::readEntriesHeader()
+{
+ // mHeaderEntriesInfo initializes to default values so safe not to read it
+ llassert_always(mHeaderAPRFile == NULL);
+ if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
+ {
+ LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+ getLocalAPRFilePool());
+ }
+}
+
+void LLTextureCache::writeEntriesHeader()
{
- lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
- U32 time;
- S32 index;
- LLUUID uuid;
- struct Compare
- {
- // lhs < rhs
- typedef const lru_data* lru_data_ptr;
- bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
+ llassert_always(mHeaderAPRFile == NULL);
+ if (!mReadOnly)
+ {
+ LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+ getLocalAPRFilePool());
+ }
+}
+
+static S32 mHeaderEntriesMaxWriteIdx = 0;
+
+S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create)
+{
+ S32 idx = -1;
+
+ id_map_t::iterator iter1 = mHeaderIDMap.find(id);
+ if (iter1 != mHeaderIDMap.end())
+ {
+ idx = iter1->second;
+ }
+
+ if (idx < 0)
+ {
+ if (create && !mReadOnly)
{
- if(a->time == b->time)
- return (a->index < b->index);
+ if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
+ {
+ // Add an entry to the end of the list
+ idx = mHeaderEntriesInfo.mEntries++;
+
+ }
+ else if (!mFreeList.empty())
+ {
+ idx = *(mFreeList.begin());
+ mFreeList.erase(mFreeList.begin());
+ }
else
- return (a->time >= b->time);
+ {
+ // Look for a still valid entry in the LRU
+ for (std::set<LLUUID>::iterator iter2 = mLRU.begin(); iter2 != mLRU.end();)
+ {
+ std::set<LLUUID>::iterator curiter2 = iter2++;
+ LLUUID oldid = *curiter2;
+ // Erase entry from LRU regardless
+ mLRU.erase(curiter2);
+ // Look up entry and use it if it is valid
+ id_map_t::iterator iter3 = mHeaderIDMap.find(oldid);
+ if (iter3 != mHeaderIDMap.end() && iter3->second >= 0)
+ {
+ idx = iter3->second;
+ mHeaderIDMap.erase(oldid);
+ mTexturesSizeMap.erase(oldid);
+ break;
+ }
+ }
+ // if (idx < 0) at this point, we will rebuild the LRU
+ // and retry if called from setHeaderCacheEntry(),
+ // otherwise this shouldn't happen and will trigger an error
+ }
+ if (idx >= 0)
+ {
+ // Set the header index
+ mHeaderIDMap[id] = idx;
+ llassert_always(mTexturesSizeMap.erase(id) == 0);
+ // Initialize the entry (will get written later)
+ entry.init(id, time(NULL));
+ // Update Header
+ writeEntriesHeader();
+ // Write Entry
+ S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
+ S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
+ llassert_always(bytes_written == sizeof(Entry));
+ mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
+ closeHeaderEntriesFile();
+ }
}
- };
-};
+ }
+ else
+ {
+ // Remove this entry from the LRU if it exists
+ mLRU.erase(id);
+ // Read the entry
+ S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ LLAPRFile* aprfile = openHeaderEntriesFile(true, offset);
+ S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry));
+ llassert_always(bytes_read == sizeof(Entry));
+ llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
+ closeHeaderEntriesFile();
+ }
+ return idx;
+}
+
+void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry)
+{
+ if (idx >= 0)
+ {
+ if (!mReadOnly)
+ {
+ entry.mTime = time(NULL);
+ llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
+ if (entry.mBodySize > 0)
+ {
+ mTexturesSizeMap[entry.mID] = entry.mBodySize;
+ }
+// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl;
+ S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
+ S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
+ llassert_always(bytes_written == sizeof(Entry));
+ mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
+ closeHeaderEntriesFile();
+ }
+ }
+}
+
+U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
+{
+ U32 num_entries = mHeaderEntriesInfo.mEntries;
+
+ mHeaderIDMap.clear();
+ mTexturesSizeMap.clear();
+ mFreeList.clear();
+ mTexturesSizeTotal = 0;
+
+ LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
+ for (U32 idx=0; idx<num_entries; idx++)
+ {
+ Entry entry;
+ S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
+ if (bytes_read < sizeof(Entry))
+ {
+ llwarns << "Corrupted header entries, failed at " << idx << " / " << num_entries << llendl;
+ closeHeaderEntriesFile();
+ purgeAllTextures(false);
+ return 0;
+ }
+ entries.push_back(entry);
+// llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl;
+ if (entry.mImageSize < 0)
+ {
+ mFreeList.insert(idx);
+ }
+ else
+ {
+ mHeaderIDMap[entry.mID] = idx;
+ if (entry.mBodySize > 0)
+ {
+ mTexturesSizeMap[entry.mID] = entry.mBodySize;
+ mTexturesSizeTotal += entry.mBodySize;
+ }
+ llassert_always(entry.mImageSize == 0 || entry.mImageSize > entry.mBodySize);
+ }
+ }
+ closeHeaderEntriesFile();
+ return num_entries;
+}
+
+void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries)
+{
+ S32 num_entries = entries.size();
+ llassert_always(num_entries == mHeaderEntriesInfo.mEntries);
+
+ if (!mReadOnly)
+ {
+ LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
+ for (S32 idx=0; idx<num_entries; idx++)
+ {
+ S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry));
+ llassert_always(bytes_written == sizeof(Entry));
+ }
+ mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, num_entries-1);
+ closeHeaderEntriesFile();
+ }
+}
+
+//----------------------------------------------------------------------------
// Called from either the main thread or the worker thread
void LLTextureCache::readHeaderCache()
{
LLMutexLock lock(&mHeaderMutex);
- mHeaderEntriesInfo.mVersion = 0.f;
- mHeaderEntriesInfo.mEntries = 0;
- if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
- {
- LLAPRFile::readEx(mHeaderEntriesFileName,
- (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
- getLocalAPRFilePool());
- }
+
+ mLRU.clear(); // always clear the LRU
+
+ readEntriesHeader();
+
if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
{
if (!mReadOnly)
{
- // Info with 0 entries
- mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
-
- LLAPRFile::writeEx(mHeaderEntriesFileName,
- (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
- getLocalAPRFilePool());
+ purgeAllTextures(false);
}
}
else
{
- S32 num_entries = mHeaderEntriesInfo.mEntries;
+ std::vector<Entry> entries;
+ U32 num_entries = openAndReadEntries(entries);
if (num_entries)
{
- Entry* entries = new Entry[num_entries];
+ U32 empty_entries = 0;
+ typedef std::pair<U32, LLUUID> lru_data_t;
+ std::set<lru_data_t> lru;
+ std::vector<LLUUID> purge_list;
+ for (U32 i=0; i<num_entries; i++)
+ {
+ Entry& entry = entries[i];
+ const LLUUID& id = entry.mID;
+ if (entry.mImageSize < 0)
+ {
+ // This will be in the Free List, don't put it in the LRY
+ ++empty_entries;
+ }
+ else
+ {
+ lru.insert(std::make_pair(entry.mTime, id));
+ if (entry.mBodySize > 0)
+ {
+ if (entry.mBodySize > entry.mImageSize)
+ {
+ // Shouldn't happen, failsafe only
+ llwarns << "Bad entry: " << i << ": " << id << ": BodySize: " << entry.mBodySize << llendl;
+ purge_list.push_back(id);
+ }
+ }
+ }
+ }
+ if (num_entries > sCacheMaxEntries)
+ {
+ // Special case: cache size was reduced, need to remove entries
+ // Note: After we prune entries, we will call this again and create the LRU
+ U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
+ if (entries_to_purge > 0)
+ {
+ for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+ {
+ purge_list.push_back(iter->second);
+ if (--entries_to_purge <= 0)
+ break;
+ }
+ }
+ }
+ else
{
- LLAPRFile::readEx(mHeaderEntriesFileName,
- (U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry),
- getLocalAPRFilePool());
+ S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE);
+ for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+ {
+ mLRU.insert(iter->second);
+// llinfos << "LRU: " << iter->first << " : " << iter->second << llendl;
+ if (--lru_entries <= 0)
+ break;
+ }
}
- typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
- lru_set_t lru;
- for (S32 i=0; i<num_entries; i++)
+
+ if (purge_list.size() > 0)
{
- if (entries[i].mSize >= 0) // -1 indicates erased entry, skip
+ for (std::vector<LLUUID>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter)
{
- const LLUUID& id = entries[i].mID;
- lru.insert(new lru_data(entries[i].mTime, i, id));
- mHeaderIDMap[id] = i;
+ removeFromCache(*iter);
}
+ // If we removed any entries, we need to rebuild the entries list,
+ // write the header, and call this again
+ std::vector<Entry> new_entries;
+ for (U32 i=0; i<num_entries; i++)
+ {
+ const Entry& entry = entries[i];
+ if (entry.mImageSize >=0)
+ {
+ new_entries.push_back(entry);
+ }
+ }
+ llassert_always(new_entries.size() <= sCacheMaxEntries);
+ mHeaderEntriesInfo.mEntries = new_entries.size();
+ writeEntriesAndClose(new_entries);
+ readHeaderCache(); // repeat with new entries file
}
- mLRU.clear();
- S32 lru_entries = sCacheMaxEntries / 10;
- for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+ else
{
- lru_data* data = *iter;
- mLRU[data->index] = data->uuid;
- if (--lru_entries <= 0)
- break;
+ writeEntriesAndClose(entries);
}
- for_each(lru.begin(), lru.end(), DeletePointer());
- delete[] entries;
}
}
}
@@ -1162,13 +1313,21 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
LLFile::rmdir(dirname);
}
}
- LLAPRFile::remove(mTexturesDirEntriesFileName, getLocalAPRFilePool());
if (purge_directories)
{
LLFile::rmdir(mTexturesDirName);
}
}
+ mHeaderIDMap.clear();
mTexturesSizeMap.clear();
+ mTexturesSizeTotal = 0;
+ mFreeList.clear();
+ mTexturesSizeTotal = 0;
+
+ // Info with 0 entries
+ mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
+ mHeaderEntriesInfo.mEntries = 0;
+ writeEntriesHeader();
}
void LLTextureCache::purgeTextures(bool validate)
@@ -1182,51 +1341,37 @@ void LLTextureCache::purgeTextures(bool validate)
LLAppViewer::instance()->pauseMainloopTimeout();
LLMutexLock lock(&mHeaderMutex);
-
- S32 filesize = LLAPRFile::size(mTexturesDirEntriesFileName, getLocalAPRFilePool());
- S32 num_entries = filesize / sizeof(Entry);
- if (num_entries * (S32)sizeof(Entry) != filesize)
- {
- LL_WARNS("TextureCache") << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
- purgeAllTextures(false);
- return;
- }
- if (num_entries == 0)
+
+ llinfos << "TEXTURE CACHE: Purging." << llendl;
+
+ // Read the entries list
+ std::vector<Entry> entries;
+ U32 num_entries = openAndReadEntries(entries);
+ if (!num_entries)
{
- return; // nothing to do
+ writeEntriesAndClose(entries);
+ return; // nothing to purge
}
- Entry* entries = new Entry[num_entries];
- S32 bytes_read = LLAPRFile::readEx(mTexturesDirEntriesFileName,
- (U8*)entries, 0, num_entries*sizeof(Entry),
- getLocalAPRFilePool());
- if (bytes_read != filesize)
- {
- LL_WARNS("TextureCache") << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
- purgeAllTextures(false);
- return;
- }
-
- LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading Entries..." << LL_ENDL;
-
- std::map<LLUUID, S32> entry_idx_map;
- S64 total_size = 0;
- for (S32 idx=0; idx<num_entries; idx++)
- {
- const LLUUID& id = entries[idx].mID;
- LL_DEBUGS("TextureCache") << "Entry: " << id << " Size: " << entries[idx].mSize << " Time: " << entries[idx].mTime << LL_ENDL;
- std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
- if (iter != entry_idx_map.end())
+ // Use mTexturesSizeMap to collect UUIDs of textures with bodies
+ typedef std::set<std::pair<U32,S32> > time_idx_set_t;
+ std::set<std::pair<U32,S32> > time_idx_set;
+ for (size_map_t::iterator iter1 = mTexturesSizeMap.begin();
+ iter1 != mTexturesSizeMap.end(); ++iter1)
+ {
+ if (iter1->second > 0)
{
- // Newer entry replacing older entry
- S32 pidx = iter->second;
- total_size -= entries[pidx].mSize;
- entries[pidx].mSize = 0; // flag: skip older entry
+ id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first);
+ if (iter2 != mHeaderIDMap.end())
+ {
+ S32 idx = iter2->second;
+ time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
+// llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl;
+ }
}
- entry_idx_map[id] = idx;
- total_size += entries[idx].mSize;
}
-
+
+ // Validate 1/256th of the files on startup
U32 validate_idx = 0;
if (validate)
{
@@ -1235,19 +1380,17 @@ void LLTextureCache::purgeTextures(bool validate)
gSavedSettings.setU32("CacheValidateCounter", next_idx);
LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
}
-
- S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
+
+ S64 cache_size = mTexturesSizeTotal;
+ S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f-TEXTURE_CACHE_PURGE_AMOUNT)*100)) / 100;
S32 purge_count = 0;
- S32 next_idx = 0;
- for (S32 idx=0; idx<num_entries; idx++)
+ for (time_idx_set_t::iterator iter = time_idx_set.begin();
+ iter != time_idx_set.end(); ++iter)
{
- if (entries[idx].mSize == 0)
- {
- continue;
- }
+ S32 idx = iter->second;
bool purge_entry = false;
std::string filename = getTextureFileName(entries[idx].mID);
- if (total_size >= min_cache_size)
+ if (cache_size >= purged_cache_size)
{
purge_entry = true;
}
@@ -1257,60 +1400,44 @@ void LLTextureCache::purgeTextures(bool validate)
U32 uuididx = entries[idx].mID.mData[0];
if (uuididx == validate_idx)
{
- LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mSize << LL_ENDL;
+ LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL;
S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool());
- if (bodysize != entries[idx].mSize)
+ if (bodysize != entries[idx].mBodySize)
{
- LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
+ LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize
<< filename << LL_ENDL;
purge_entry = true;
}
}
}
+ else
+ {
+ break;
+ }
+
if (purge_entry)
{
purge_count++;
LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
LLAPRFile::remove(filename, getLocalAPRFilePool());
- total_size -= entries[idx].mSize;
- entries[idx].mSize = 0;
- }
- else
- {
- if (next_idx != idx)
- {
- entries[next_idx] = entries[idx];
- }
- ++next_idx;
+ cache_size -= entries[idx].mBodySize;
+ mTexturesSizeTotal -= entries[idx].mBodySize;
+ entries[idx].mBodySize = 0;
+ mTexturesSizeMap.erase(entries[idx].mID);
}
}
- num_entries = next_idx;
LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
-
- LLAPRFile::remove(mTexturesDirEntriesFileName, getLocalAPRFilePool());
- LLAPRFile::writeEx(mTexturesDirEntriesFileName,
- (U8*)&entries[0], 0, num_entries*sizeof(Entry),
- getLocalAPRFilePool());
-
- mTexturesSizeTotal = 0;
- mTexturesSizeMap.clear();
- for (S32 idx=0; idx<num_entries; idx++)
- {
- mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
- mTexturesSizeTotal += entries[idx].mSize;
- }
- llassert(mTexturesSizeTotal == total_size);
-
- delete[] entries;
+ writeEntriesAndClose(entries);
+
// *FIX:Mani - watchdog back on.
LLAppViewer::instance()->resumeMainloopTimeout();
LL_INFOS("TextureCache") << "TEXTURE CACHE:"
<< " PURGED: " << purge_count
<< " ENTRIES: " << num_entries
- << " CACHE SIZE: " << total_size / 1024*1024 << " MB"
+ << " CACHE SIZE: " << mTexturesSizeTotal / 1024*1024 << " MB"
<< llendl;
}
@@ -1340,78 +1467,39 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
}
//////////////////////////////////////////////////////////////////////////////
-
// Called from work thread
-S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
-{
- bool retry = false;
- S32 idx = -1;
+// Reads imagesize from the header, updates timestamp
+S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize)
+{
+ LLMutexLock lock(&mHeaderMutex);
+ Entry entry;
+ S32 idx = openAndReadEntry(id, entry, false);
+ if (idx >= 0)
{
- LLMutexLock lock(&mHeaderMutex);
- id_map_t::iterator iter = mHeaderIDMap.find(id);
- if (iter != mHeaderIDMap.end())
- {
- idx = iter->second;
- }
- else if (touch && !mReadOnly)
- {
- if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
- {
- // Add an entry
- idx = mHeaderEntriesInfo.mEntries++;
- mHeaderIDMap[id] = idx;
- // Update Info
- LLAPRFile::writeEx(mHeaderEntriesFileName,
- (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
- getLocalAPRFilePool());
- }
- else if (!mLRU.empty())
- {
- idx = mLRU.begin()->first; // will be erased below
- const LLUUID& oldid = mLRU.begin()->second;
- mHeaderIDMap.erase(oldid);
- mTexturesSizeMap.erase(oldid);
- mHeaderIDMap[id] = idx;
- }
- else
- {
- idx = -1;
- retry = true;
- }
- }
- if (idx >= 0)
- {
- if (touch && !mReadOnly)
- {
- // Update the lru entry
- mLRU.erase(idx);
- llassert_always(imagesize && *imagesize > 0);
- Entry* entry = new Entry(id, *imagesize, time(NULL));
- S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
- LLAPRFile::writeEx(mHeaderEntriesFileName,
- (U8*)entry, offset, sizeof(Entry),
- getLocalAPRFilePool());
- delete entry;
- }
- else if (imagesize)
- {
- // Get the image size
- Entry entry;
- S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+ imagesize = entry.mImageSize;
+ writeEntryAndClose(idx, entry); // updates time
+ }
+ return idx;
+}
- LLAPRFile::readEx(mHeaderEntriesFileName,
- (U8*)&entry, offset, sizeof(Entry),
- getLocalAPRFilePool());
- *imagesize = entry.mSize;
- }
- }
+// Writes imagesize to the header, updates timestamp
+S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize)
+{
+ LLMutexLock lock(&mHeaderMutex);
+ llassert_always(imagesize >= 0);
+ Entry entry;
+ S32 idx = openAndReadEntry(id, entry, true);
+ if (idx >= 0)
+ {
+ entry.mImageSize = imagesize;
+ writeEntryAndClose(idx, entry);
}
- if (retry)
+ else // retry
{
- readHeaderCache(); // updates the lru
+ readHeaderCache(); // We couldn't write an entry, so refresh the LRU
llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
- idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
+ idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion
}
return idx;
}
@@ -1427,8 +1515,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const std::string& filena
// so let the thread handle it
LLMutexLock lock(&mWorkersMutex);
LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id,
- NULL, size, offset, 0,
- responder);
+ NULL, size, offset, 0,
+ responder);
handle_t handle = worker->read();
mReaders[handle] = worker;
return handle;
@@ -1441,8 +1529,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 pri
// so let the thread handle it
LLMutexLock lock(&mWorkersMutex);
LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
- NULL, size, offset, 0,
- responder);
+ NULL, size, offset,
+ 0, responder);
handle_t handle = worker->read();
mReaders[handle] = worker;
return handle;
@@ -1453,7 +1541,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort)
{
lockWorkers();
handle_map_t::iterator iter = mReaders.find(handle);
- llassert_always(iter != mReaders.end());
+ llassert_always(iter != mReaders.end() || abort);
LLTextureCacheWorker* worker = iter->second;
bool res = worker->complete();
if (res || abort)
@@ -1487,19 +1575,13 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio
purgeTextures(false);
mDoPurge = FALSE;
}
- if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
- {
- LLMutexLock lock(&mWorkersMutex);
- llassert_always(imagesize > 0);
- LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
- data, datasize, 0,
- imagesize, responder);
- handle_t handle = worker->write();
- mWriters[handle] = worker;
- return handle;
- }
- delete responder;
- return LLWorkerThread::nullHandle();
+ LLMutexLock lock(&mWorkersMutex);
+ LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
+ data, datasize, 0,
+ imagesize, responder);
+ handle_t handle = worker->write();
+ mWriters[handle] = worker;
+ return handle;
}
bool LLTextureCache::writeComplete(handle_t handle, bool abort)
@@ -1542,25 +1624,17 @@ void LLTextureCache::addCompleted(Responder* responder, bool success)
bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
{
- if (mReadOnly)
- {
- return false;
- }
- LLMutexLock lock(&mHeaderMutex);
- id_map_t::iterator iter = mHeaderIDMap.find(id);
- if (iter != mHeaderIDMap.end())
+ if (!mReadOnly)
{
- S32 idx = iter->second;
+ LLMutexLock lock(&mHeaderMutex);
+ Entry entry;
+ S32 idx = openAndReadEntry(id, entry, false);
if (idx >= 0)
{
- Entry* entry = new Entry(id, -1, time(NULL));
- S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-
- LLAPRFile::writeEx(mHeaderEntriesFileName,
- (U8*)entry, offset, sizeof(Entry),
- getLocalAPRFilePool());
- delete entry;
- mLRU[idx] = id;
+ entry.mImageSize = -1;
+ entry.mBodySize = 0;
+ writeEntryAndClose(idx, entry);
+ mFreeList.insert(idx);
mHeaderIDMap.erase(id);
mTexturesSizeMap.erase(id);
return true;
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 68b1458e9a..bc9c988648 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -48,6 +48,27 @@ class LLTextureCache : public LLWorkerThread
friend class LLTextureCacheRemoteWorker;
friend class LLTextureCacheLocalFileWorker;
+private:
+ // Entries
+ struct EntriesInfo
+ {
+ EntriesInfo() : mVersion(0.f), mEntries(0) {}
+ F32 mVersion;
+ U32 mEntries;
+ };
+ struct Entry
+ {
+ Entry() {}
+ Entry(const LLUUID& id, S32 imagesize, S32 bodysize, U32 time) :
+ mID(id), mImageSize(imagesize), mBodySize(bodysize), mTime(time) {}
+ void init(const LLUUID& id, U32 time) { mID = id, mImageSize = 0; mBodySize = 0; mTime = time; }
+ LLUUID mID; // 16 bytes
+ S32 mImageSize; // total size of image if known
+ S32 mBodySize; // size of body file in body cache
+ U32 mTime; // seconds since 1/1/1970
+ };
+
+
public:
class Responder : public LLResponder
@@ -106,10 +127,16 @@ public:
// debug
S32 getNumReads() { return mReaders.size(); }
S32 getNumWrites() { return mWriters.size(); }
+ S64 getUsage() { return mTexturesSizeTotal; }
+ S64 getMaxUsage() { return sCacheMaxTexturesSize; }
+ U32 getEntries() { return mHeaderEntriesInfo.mEntries; }
+ U32 getMaxEntries() { return sCacheMaxEntries; };
+ BOOL isInCache(const LLUUID& id) ;
+ BOOL isInLocal(const LLUUID& id) ;
protected:
// Accessed by LLTextureCacheWorker
- bool appendToTextureEntryList(const LLUUID& id, S32 size);
+ bool updateTextureEntryList(const LLUUID& id, S32 size);
std::string getLocalFileName(const LLUUID& id);
std::string getTextureFileName(const LLUUID& id);
void addCompleted(Responder* responder, bool success);
@@ -122,7 +149,16 @@ private:
void readHeaderCache();
void purgeAllTextures(bool purge_directories);
void purgeTextures(bool validate);
- S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL);
+ LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset);
+ void closeHeaderEntriesFile();
+ void readEntriesHeader();
+ void writeEntriesHeader();
+ S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create);
+ void writeEntryAndClose(S32 idx, Entry& entry);
+ U32 openAndReadEntries(std::vector<Entry>& entries);
+ void writeEntriesAndClose(const std::vector<Entry>& entries);
+ S32 getHeaderCacheEntry(const LLUUID& id, S32& imagesize);
+ S32 setHeaderCacheEntry(const LLUUID& id, S32 imagesize);
bool removeHeaderCacheEntry(const LLUUID& id);
void lockHeaders() { mHeaderMutex.lock(); }
void unlockHeaders() { mHeaderMutex.unlock(); }
@@ -132,6 +168,7 @@ private:
LLMutex mWorkersMutex;
LLMutex mHeaderMutex;
LLMutex mListMutex;
+ LLAPRFile* mHeaderAPRFile;
typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
handle_map_t mReaders;
@@ -145,42 +182,28 @@ private:
BOOL mReadOnly;
- // Entries
- struct EntriesInfo
- {
- F32 mVersion;
- U32 mEntries;
- };
- struct Entry
- {
- Entry() {}
- Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {}
- LLUUID mID; // 128 bits
- S32 mSize; // total size of image if known (NOT size cached)
- U32 mTime; // seconds since 1/1/1970
- };
-
// HEADERS (Include first mip)
std::string mHeaderEntriesFileName;
std::string mHeaderDataFileName;
EntriesInfo mHeaderEntriesInfo;
- typedef std::map<S32,LLUUID> index_map_t;
- index_map_t mLRU; // index, id; stored as a map for fast removal
+ std::set<S32> mFreeList; // deleted entries
+ std::set<LLUUID> mLRU;
typedef std::map<LLUUID,S32> id_map_t;
id_map_t mHeaderIDMap;
// BODIES (TEXTURES minus headers)
std::string mTexturesDirName;
- std::string mTexturesDirEntriesFileName;
typedef std::map<LLUUID,S32> size_map_t;
size_map_t mTexturesSizeMap;
S64 mTexturesSizeTotal;
LLAtomic32<BOOL> mDoPurge;
-
+
// Statics
static F32 sHeaderCacheVersion;
static U32 sCacheMaxEntries;
static S64 sCacheMaxTexturesSize;
};
+extern const S32 TEXTURE_CACHE_ENTRY_SIZE;
+
#endif // LL_LLTEXTURECACHE_H
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 88fc7f98c0..c918f98895 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -32,108 +32,35 @@
#include "llviewerprecompiledheaders.h"
+#include <iostream>
+
#include "llstl.h"
#include "lltexturefetch.h"
#include "llcurl.h"
+#include "lldir.h"
#include "llhttpclient.h"
+#include "llhttpstatuscodes.h"
#include "llimage.h"
#include "llimageworker.h"
#include "llworkerthread.h"
#include "llagent.h"
#include "lltexturecache.h"
+#include "llviewercontrol.h"
#include "llviewertexturelist.h"
#include "llviewertexture.h"
#include "llviewerregion.h"
+#include "llworld.h"
//////////////////////////////////////////////////////////////////////////////
-//static
class LLTextureFetchWorker : public LLWorkerClass
{
-friend class LLTextureFetch;
-
-private:
-#if 0
- class URLResponder : public LLHTTPClient::Responder
- {
- public:
- URLResponder(LLTextureFetch* fetcher, const LLUUID& id)
- : mFetcher(fetcher), mID(id)
- {
- }
- ~URLResponder()
- {
- }
- virtual void error(U32 status, const std::string& reason)
- {
- mFetcher->lockQueue();
- LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
- if (worker)
- {
-// llwarns << "LLTextureFetchWorker::URLResponder::error " << status << ": " << reason << llendl;
- worker->callbackURLReceived(LLSD(), false);
- }
- mFetcher->unlockQueue();
- }
- virtual void result(const LLSD& content)
- {
- mFetcher->lockQueue();
- LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
- if (worker)
- {
- worker->callbackURLReceived(content, true);
- }
- mFetcher->unlockQueue();
- }
- private:
- LLTextureFetch* mFetcher;
- LLUUID mID;
- };
-
- class HTTPGetResponder : public LLHTTPClient::Responder
- {
- public:
- HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id)
- : mFetcher(fetcher), mID(id)
- {
- }
- ~HTTPGetResponder()
- {
- }
- virtual void completed(U32 status, const std::stringstream& content)
- {
- mFetcher->lockQueue();
- LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
- if (worker)
- {
- const std::string& cstr = content.str();
- if (200 <= status && status < 300)
- {
- if (203 == status) // partial information (i.e. last block)
- {
- worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), true);
- }
- else
- {
- worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), false);
- }
- }
- else
- {
-// llinfos << "LLTextureFetchWorker::HTTPGetResponder::error " << status << ": " << cstr << llendl;
- worker->callbackHttpGet(NULL, -1, true);
- }
- }
- mFetcher->unlockQueue();
- }
- private:
- LLTextureFetch* mFetcher;
- LLUUID mID;
- };
-#endif
+ friend class LLTextureFetch;
+ friend class HTTPGetResponder;
+private:
class CacheReadResponder : public LLTextureCache::ReadResponder
{
public:
@@ -179,20 +106,20 @@ private:
LLUUID mID;
};
- class DecodeResponder : public LLResponder
+ class DecodeResponder : public LLImageDecodeThread::Responder
{
public:
DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker)
: mFetcher(fetcher), mID(id), mWorker(worker)
{
}
- virtual void completed(bool success)
+ virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
{
mFetcher->lockQueue();
LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
if (worker)
{
- worker->callbackDecoded(success);
+ worker->callbackDecoded(success, raw, aux);
}
mFetcher->unlockQueue();
}
@@ -227,37 +154,45 @@ public:
~LLTextureFetchWorker();
void relese() { --mActiveCount; }
+ void callbackHttpGet(const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer,
+ bool last_block, bool success);
+ void callbackCacheRead(bool success, LLImageFormatted* image,
+ S32 imagesize, BOOL islocal);
+ void callbackCacheWrite(bool success);
+ void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
+
+ void setGetStatus(U32 status, const std::string& reason)
+ {
+ mGetStatus = status;
+ mGetReason = reason;
+ }
+
protected:
LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
F32 priority, S32 discard, S32 size);
+ LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
+ F32 priority, S32 discard, S32 size);
private:
/*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
/*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
- virtual std::string getName() { return LLStringUtil::null; }
void resetFormattedData();
void setImagePriority(F32 priority);
void setDesiredDiscard(S32 discard, S32 size);
bool insertPacket(S32 index, U8* data, S32 size);
void clearPackets();
+ void setupPacketData();
U32 calcWorkPriority();
void removeFromCache();
bool processSimulatorPackets();
- bool decodeImage();
bool writeToCacheComplete();
- void lockWorkData() { mWorkMutex.lock(); }
- void unlockWorkData() { mWorkMutex.unlock(); }
+ void lockWorkMutex() { mWorkMutex.lock(); }
+ void unlockWorkMutex() { mWorkMutex.unlock(); }
- void callbackURLReceived(const LLSD& data, bool success);
- void callbackHttpGet(U8* data, S32 data_size, bool last_block);
- void callbackCacheRead(bool success, LLImageFormatted* image,
- S32 imagesize, BOOL islocal);
- void callbackCacheWrite(bool success);
- void callbackDecoded(bool success);
-
private:
enum e_state // mState
{
@@ -268,8 +203,8 @@ private:
CACHE_POST,
LOAD_FROM_NETWORK,
LOAD_FROM_SIMULATOR,
- LOAD_FROM_HTTP_GET_URL,
- LOAD_FROM_HTTP_GET_DATA,
+ SEND_HTTP_REQ,
+ WAIT_HTTP_REQ,
DECODE_IMAGE,
DECODE_IMAGE_UPDATE,
WRITE_TO_CACHE,
@@ -280,19 +215,17 @@ private:
{
UNSENT = 0,
QUEUED = 1,
- SENT_SIM = 2,
- SENT_URL = 3,
- SENT_HTTP = 4
+ SENT_SIM = 2
};
static const char* sStateDescs[];
e_state mState;
LLTextureFetch* mFetcher;
- LLImageWorker* mImageWorker;
LLPointer<LLImageFormatted> mFormattedImage;
LLPointer<LLImageRaw> mRawImage;
LLPointer<LLImageRaw> mAuxImage;
LLUUID mID;
LLHost mHost;
+ std::string mUrl;
U8 mType;
F32 mImagePriority;
U32 mWorkPriority;
@@ -314,15 +247,18 @@ private:
S32 mCachedSize;
BOOL mLoaded;
e_request_state mSentRequest;
+ handle_t mDecodeHandle;
BOOL mDecoded;
BOOL mWritten;
BOOL mNeedsAux;
BOOL mHaveAllData;
BOOL mInLocalCache;
+ S32 mHTTPFailCount;
S32 mRetryAttempt;
- std::string mURL;
S32 mActiveCount;
-
+ U32 mGetStatus;
+ std::string mGetReason;
+
// Work Data
LLMutex mWorkMutex;
struct PacketData
@@ -340,25 +276,79 @@ private:
U8 mImageCodec;
};
-class LLTextureFetchLocalFileWorker : public LLTextureFetchWorker
-{
-friend class LLTextureFetch;
-
-protected:
- LLTextureFetchLocalFileWorker(LLTextureFetch* fetcher, const std::string& filename, const LLUUID& id, const LLHost& host,
- F32 priority, S32 discard, S32 size)
- : LLTextureFetchWorker(fetcher, id, host, priority, discard, size),
- mFileName(filename)
- {}
+//////////////////////////////////////////////////////////////////////////////
-private:
- /*virtual*/ std::string getName() { return mFileName; }
+class HTTPGetResponder : public LLCurl::Responder
+{
+ LOG_CLASS(HTTPGetResponder);
+public:
+ HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset)
+ : mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset)
+ {
+ }
+ ~HTTPGetResponder()
+ {
+ }
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
+ {
+ mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime);
+ U64 timeNow = LLTimer::getTotalTime();
+ mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
+ mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
+ mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
+ }
+ lldebugs << "HTTP COMPLETE: " << mID << llendl;
+ mFetcher->lockQueue();
+ LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
+ if (worker)
+ {
+ bool success = false;
+ bool partial = false;
+ if (200 <= status && status < 300)
+ {
+ success = true;
+ if (203 == status) // partial information (i.e. last block)
+ {
+ partial = true;
+ }
+ }
+ else
+ {
+ worker->setGetStatus(status, reason);
+// llwarns << status << ": " << reason << llendl;
+ }
+ if (!success)
+ {
+ worker->setGetStatus(status, reason);
+// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
+ }
+ mFetcher->removeFromHTTPQueue(mID);
+ worker->callbackHttpGet(channels, buffer, partial, success);
+ }
+ else
+ {
+ mFetcher->removeFromHTTPQueue(mID);
+ llwarns << "Worker not found: " << mID << llendl;
+ }
+ mFetcher->unlockQueue();
+ }
+
private:
- std::string mFileName;
+ LLTextureFetch* mFetcher;
+ LLUUID mID;
+ U64 mStartTime;
+ S32 mRequestedSize;
+ U32 mOffset;
};
+//////////////////////////////////////////////////////////////////////////////
//static
const char* LLTextureFetchWorker::sStateDescs[] = {
@@ -368,8 +358,8 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
"CACHE_POST",
"LOAD_FROM_NETWORK",
"LOAD_FROM_SIMULATOR",
- "LOAD_FROM_HTTP_URL",
- "LOAD_FROM_HTTP_DATA",
+ "SEND_HTTP_REQ",
+ "WAIT_HTTP_REQ",
"DECODE_IMAGE",
"DECODE_IMAGE_UPDATE",
"WRITE_TO_CACHE",
@@ -380,6 +370,7 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
// called from MAIN THREAD
LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
+ const std::string& url, // Optional URL
const LLUUID& id, // Image UUID
const LLHost& host, // Simulator host
F32 priority, // Priority
@@ -388,9 +379,9 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
: LLWorkerClass(fetcher, "TextureFetch"),
mState(INIT),
mFetcher(fetcher),
- mImageWorker(NULL),
mID(id),
mHost(host),
+ mUrl(url),
mImagePriority(priority),
mWorkPriority(0),
mRequestedPriority(0.f),
@@ -404,18 +395,21 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mBuffer(NULL),
mBufferSize(0),
mRequestedSize(0),
- mDesiredSize(FIRST_PACKET_SIZE),
+ mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
mFileSize(0),
mCachedSize(0),
mLoaded(FALSE),
mSentRequest(UNSENT),
+ mDecodeHandle(0),
mDecoded(FALSE),
mWritten(FALSE),
mNeedsAux(FALSE),
mHaveAllData(FALSE),
mInLocalCache(FALSE),
+ mHTTPFailCount(0),
mRetryAttempt(0),
mActiveCount(0),
+ mGetStatus(0),
mWorkMutex(NULL),
mFirstPacket(0),
mLastPacket(-1),
@@ -440,7 +434,7 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
// << " Requested=" << mRequestedDiscard
// << " Desired=" << mDesiredDiscard << llendl;
llassert_always(!haveWork());
- lockWorkData();
+ lockWorkMutex();
if (mCacheReadHandle != LLTextureCache::nullHandle())
{
mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
@@ -449,13 +443,9 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
{
mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
}
- if (mImageWorker)
- {
- mImageWorker->scheduleDelete();
- }
mFormattedImage = NULL;
clearPackets();
- unlockWorkData();
+ unlockWorkMutex();
}
void LLTextureFetchWorker::clearPackets()
@@ -467,6 +457,38 @@ void LLTextureFetchWorker::clearPackets()
mFirstPacket = 0;
}
+void LLTextureFetchWorker::setupPacketData()
+{
+ S32 data_size = 0;
+ if (mFormattedImage.notNull())
+ {
+ data_size = mFormattedImage->getDataSize();
+ }
+ if (data_size > 0)
+ {
+ // Only used for simulator requests
+ mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
+ if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
+ {
+ llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
+ removeFromCache();
+ resetFormattedData();
+ clearPackets();
+ }
+ else if (mFileSize > 0)
+ {
+ mLastPacket = mFirstPacket-1;
+ mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
+ }
+ else
+ {
+ // This file was cached using HTTP so we have to refetch the first packet
+ resetFormattedData();
+ clearPackets();
+ }
+ }
+}
+
U32 LLTextureFetchWorker::calcWorkPriority()
{
// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerTexture::maxDecodePriority());
@@ -538,7 +560,6 @@ void LLTextureFetchWorker::resetFormattedData()
// Called from MAIN thread
void LLTextureFetchWorker::startWork(S32 param)
{
- llassert(mImageWorker == NULL);
llassert(mFormattedImage.isNull());
}
@@ -549,6 +570,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
{
LLMutexLock lock(&mWorkMutex);
+ if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
+ {
+ if (mState < WRITE_TO_CACHE)
+ {
+ return true; // abort
+ }
+ }
+
if (mFetcher->mDebugPause)
{
return false; // debug: don't do any work
@@ -563,16 +592,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
mFetchTimer.reset();
}
- if (mImagePriority <= 0.0f)
- {
- if (mState < WRITE_TO_CACHE)
- {
- return true; // cancel request
- }
- }
-
if (mState == INIT)
{
+ mRawImage = NULL ;
mRequestedDiscard = -1;
mLoadedDiscard = -1;
mDecodedDiscard = -1;
@@ -590,8 +612,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
clearPackets(); // TODO: Shouldn't be necessary
mCacheReadHandle = LLTextureCache::nullHandle();
mCacheWriteHandle = LLTextureCache::nullHandle();
- mURL.clear();
mState = LOAD_FROM_TEXTURE_CACHE;
+ LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
+ << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
// fall through
}
@@ -612,16 +635,27 @@ bool LLTextureFetchWorker::doWork(S32 param)
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
- if (getName().empty())
+ if (mUrl.compare(0, 7, "file://") == 0)
+ {
+ // read file from local disk
+ std::string filename = mUrl.substr(7, std::string::npos);
+ mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
+ offset, size, responder);
+ }
+ else if (mUrl.empty())
{
mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
offset, size, responder);
}
else
{
- // read file from local disk
- mCacheReadHandle = mFetcher->mTextureCache->readFromCache(getName(), mID, cache_priority,
- offset, size, responder);
+ if (!(mUrl.compare(0, 7, "http://") == 0))
+ {
+ // *TODO:?remove this warning
+ llwarns << "Unknown URL Type: " << mUrl << llendl;
+ }
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+ mState = SEND_HTTP_REQ;
}
}
@@ -647,75 +681,101 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (mState == CACHE_POST)
{
- mDesiredSize = llmax(mDesiredSize, FIRST_PACKET_SIZE);
+ mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
// Successfully loaded
if ((mCachedSize >= mDesiredSize) || mHaveAllData)
{
// we have enough data, decode it
llassert_always(mFormattedImage->getDataSize() > 0);
+ mLoadedDiscard = mDesiredDiscard;
mState = DECODE_IMAGE;
+ LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize()
+ << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight())
+ << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
// fall through
}
else
{
- if (!getName().empty())
+ if (mUrl.compare(0, 7, "file://") == 0)
{
// failed to load local file, we're done.
return true;
}
// need more data
- mState = LOAD_FROM_NETWORK;
+ else
+ {
+ LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
+ mState = LOAD_FROM_NETWORK;
+ }
// fall through
}
}
if (mState == LOAD_FROM_NETWORK)
{
- if (mSentRequest == UNSENT)
+ bool get_url = gSavedSettings.getBOOL("ImagePipelineUseHTTP");
+ if (!mUrl.empty()) get_url = false;
+// if (mHost != LLHost::invalid) get_url = false;
+ if ( get_url )
{
- if (mFormattedImage.isNull())
- {
- mFormattedImage = new LLImageJ2C;
- }
- // Add this to the network queue and sit here.
- // LLTextureFetch::update() will send off a request which will change our state
- S32 data_size = mFormattedImage->getDataSize();
- if (data_size > 0)
+ LLViewerRegion* region = NULL;
+ if (mHost == LLHost::invalid)
+ region = gAgent.getRegion();
+ else
+ region = LLWorld::getInstance()->getRegion(mHost);
+
+ if (region)
{
- // Only used for simulator requests
- mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
- if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
- {
-// llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
- removeFromCache();
- resetFormattedData();
- clearPackets();
- }
- else
+ std::string http_url = region->getCapability("GetTexture");
+ if (!http_url.empty())
{
- mLastPacket = mFirstPacket-1;
- mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
+ mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
}
}
+ else
+ {
+ llwarns << "Region not found for host: " << mHost << llendl;
+ }
+ }
+ if (!mUrl.empty())
+ {
+ mState = LLTextureFetchWorker::SEND_HTTP_REQ;
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+ // don't return, fall through to next state
+ }
+ else if (mSentRequest == UNSENT)
+ {
+ // Add this to the network queue and sit here.
+ // LLTextureFetch::update() will send off a request which will change our state
mRequestedSize = mDesiredSize;
mRequestedDiscard = mDesiredDiscard;
mSentRequest = QUEUED;
- mFetcher->lockQueue();
mFetcher->addToNetworkQueue(this);
- mFetcher->unlockQueue();
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+ return false;
+ }
+ else
+ {
+ // Shouldn't need to do anything here
+ //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
+ // Make certain this is in the network queue
+ //mFetcher->addToNetworkQueue(this);
+ //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+ return false;
}
- return false;
}
if (mState == LOAD_FROM_SIMULATOR)
{
+ if (mFormattedImage.isNull())
+ {
+ mFormattedImage = new LLImageJ2C;
+ }
if (processSimulatorPackets())
{
- mFetcher->lockQueue();
- mFetcher->removeFromNetworkQueue(this);
- mFetcher->unlockQueue();
+ LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL;
+ mFetcher->removeFromNetworkQueue(this, false);
if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
{
// processSimulatorPackets() failed
@@ -727,108 +787,99 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
else
{
+ mFetcher->addToNetworkQueue(this); // failsafe
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
}
return false;
}
-#if 0
- if (mState == LOAD_FROM_HTTP_GET_URL)
- {
- if (!mSentRequest)
- {
- mSentRequest = TRUE;
- mLoaded = FALSE;
- std::string url;
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
+ if (mState == SEND_HTTP_REQ)
+ {
+ {
+ const S32 HTTP_QUEUE_MAX_SIZE = 32;
+ // *TODO: Integrate this with llviewerthrottle
+ // Note: LLViewerThrottle uses dynamic throttling which makes sense for UDP,
+ // but probably not for Textures.
+ // Set the throttle to the entire bandwidth, assuming UDP packets will get priority
+ // when they are needed
+ F32 max_bandwidth = mFetcher->mMaxBandwidth;
+ if ((mFetcher->getHTTPQueueSize() >= HTTP_QUEUE_MAX_SIZE) ||
+ (mFetcher->getTextureBandwidth() > max_bandwidth))
{
- url = region->getCapability("RequestTextureDownload");
- }
- if (!url.empty())
- {
- LLSD sd;
- sd = mID.asString();
- setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
- LLHTTPClient::post(url, sd, new URLResponder(mFetcher, mID));
+ // Make normal priority and return (i.e. wait until there is room in the queue)
+ setPriority(LLWorkerThread::PRIORITY_NORMAL | mWorkPriority);
return false;
}
- else
- {
-// llwarns << mID << ": HTTP get url failed, requesting from simulator" << llendl;
- mSentRequest = FALSE;
- mState = LOAD_FROM_SIMULATOR;
- return false;
- }
- }
- else
- {
- if (mLoaded)
+
+ mFetcher->removeFromNetworkQueue(this, false);
+
+ S32 cur_size = 0;
+ if (mFormattedImage.notNull())
{
- if (!mURL.empty())
- {
- mState = LOAD_FROM_HTTP_GET_DATA;
- mSentRequest = FALSE; // reset
- mLoaded = FALSE; // reset
- }
- else
- {
-// llwarns << mID << ": HTTP get url is empty, requesting from simulator" << llendl;
- mSentRequest = FALSE;
- mState = LOAD_FROM_SIMULATOR;
- return false;
- }
+ cur_size = mFormattedImage->getDataSize(); // amount of data we already have
}
- }
- // fall through
- }
-
- if (mState == LOAD_FROM_HTTP_GET_DATA)
- {
- if (!mSentRequest)
- {
- mSentRequest = TRUE;
- S32 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
mRequestedSize = mDesiredSize;
mRequestedDiscard = mDesiredDiscard;
-#if 1 // *TODO: LLCurl::getByteRange is broken (ignores range)
- cur_size = 0;
- mFormattedImage->deleteData();
-#endif
mRequestedSize -= cur_size;
- // F32 priority = mImagePriority / (F32)LLViewerTexture::maxDecodePriority(); // 0-1
S32 offset = cur_size;
mBufferSize = cur_size; // This will get modified by callbackHttpGet()
- std::string url;
- if (mURL.empty())
+
+ bool res = false;
+ if (!mUrl.empty())
{
- //url = "http://asset.agni/0000002f-38ae-0e17-8e72-712e58964e9c.texture";
- std::stringstream urlstr;
- urlstr << "http://asset.agni/" << mID.asString() << ".texture";
- url = urlstr.str();
+ mLoaded = FALSE;
+ mGetStatus = 0;
+ mGetReason.clear();
+ lldebugs << "HTTP GET: " << mID << " Offset: " << offset
+ << " Bytes: " << mRequestedSize
+ << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth
+ << llendl;
+ setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+ mState = WAIT_HTTP_REQ;
+
+ mFetcher->addToHTTPQueue(mID);
+ // Will call callbackHttpGet when curl request completes
+ std::vector<std::string> headers;
+ headers.push_back("Accept: image/x-j2c");
+ res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
+ new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset));
}
- else
+ if (!res)
{
- url = mURL;
+ llwarns << "HTTP GET request failed for " << mID << llendl;
+ resetFormattedData();
+ ++mHTTPFailCount;
+ return true; // failed
}
- mLoaded = FALSE;
-// llinfos << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize << llendl;
- setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
- LLCurl::getByteRange(url, offset, mRequestedSize,
- new HTTPGetResponder(mFetcher, mID)); // *TODO: use mWorkPriority
- return false; // not done
+ // fall through
}
-
+ }
+
+ if (mState == WAIT_HTTP_REQ)
+ {
if (mLoaded)
{
- S32 cur_size = mFormattedImage->getDataSize();
+ S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
if (mRequestedSize < 0)
{
-// llwarns << "http get failed for: " << mID << llendl;
+ const S32 HTTP_MAX_RETRY_COUNT = 3;
+ S32 max_attempts = (mGetStatus == HTTP_NOT_FOUND) ? 1 : HTTP_MAX_RETRY_COUNT + 1;
+ llinfos << "HTTP GET failed for: " << mUrl
+ << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
+ << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
if (cur_size == 0)
{
- resetFormattedData();
- return true; // failed
+ ++mHTTPFailCount;
+ if (mHTTPFailCount >= max_attempts)
+ {
+ resetFormattedData();
+ return true; // failed
+ }
+ else
+ {
+ mState = SEND_HTTP_REQ;
+ return false; // retry
+ }
}
else
{
@@ -836,6 +887,18 @@ bool LLTextureFetchWorker::doWork(S32 param)
return false; // use what we have
}
}
+
+ if (mFormattedImage.isNull())
+ {
+ // For now, create formatted image based on extension
+ std::string extension = gDirUtilp->getExtension(mUrl);
+ mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension));
+ if (mFormattedImage.isNull())
+ {
+ mFormattedImage = new LLImageJ2C; // default
+ }
+ }
+
llassert_always(mBufferSize == cur_size + mRequestedSize);
if (mHaveAllData)
{
@@ -854,43 +917,51 @@ bool LLTextureFetchWorker::doWork(S32 param)
mBuffer = NULL;
mBufferSize = 0;
mLoadedDiscard = mRequestedDiscard;
- setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
mState = DECODE_IMAGE;
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+ return false;
+ }
+ else
+ {
+ setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
return false;
}
-
- // NOTE: Priority gets updated when the http get completes (in callbackHTTPGet())
- setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
- return false;
}
-#endif
if (mState == DECODE_IMAGE)
{
- llassert_always(mFormattedImage->getDataSize() > 0);
+ if (mFormattedImage->getDataSize() <= 0)
+ {
+ llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl;
+ }
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
mRawImage = NULL;
mAuxImage = NULL;
- llassert_always(mImageWorker == NULL);
llassert_always(mFormattedImage.notNull());
+ llassert_always(mLoadedDiscard >= 0);
S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
mDecoded = FALSE;
mState = DECODE_IMAGE_UPDATE;
- mImageWorker = new LLImageWorker(mFormattedImage, image_priority, discard, new DecodeResponder(mFetcher, mID, this));
- // fall though (need to call requestDecodedData() to start work)
+ LL_DEBUGS("Texture") << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard
+ << " All Data: " << mHaveAllData << LL_ENDL;
+ mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux,
+ new DecodeResponder(mFetcher, mID, this));
+ // fall though
}
if (mState == DECODE_IMAGE_UPDATE)
{
- if (decodeImage())
+ if (mDecoded)
{
if (mDecodedDiscard < 0)
{
+ LL_DEBUGS("Texture") << mID << ": Failed to Decode." << LL_ENDL;
if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)
{
// Cache file should be deleted, try again
// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl;
+ llassert_always(mDecodeHandle == 0);
mFormattedImage = NULL;
++mRetryAttempt;
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
@@ -905,6 +976,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
}
else
{
+ llassert_always(mRawImage.notNull());
+ LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard
+ << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
mState = WRITE_TO_CACHE;
}
@@ -918,9 +992,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (mState == WRITE_TO_CACHE)
{
- if (mInLocalCache || !mFileSize || mSentRequest == UNSENT)
+ if (mInLocalCache || mSentRequest == UNSENT || mFormattedImage.isNull())
{
- // If we're in a local cache or we didn't actually receive any new data, skip
+ // If we're in a local cache or we didn't actually receive any new data,
+ // or we failed to load anything, skip
mState = DONE;
return false;
}
@@ -979,10 +1054,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
// Called from MAIN thread
void LLTextureFetchWorker::endWork(S32 param, bool aborted)
{
- if (mImageWorker)
+ if (mDecodeHandle != 0)
{
- mImageWorker->scheduleDelete();
- mImageWorker = NULL;
+ mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
+ mDecodeHandle = 0;
}
mFormattedImage = NULL;
}
@@ -1035,7 +1110,7 @@ bool LLTextureFetchWorker::deleteOK()
if ((haveWork() &&
// not ok to delete from these states
- ((mState >= LOAD_FROM_HTTP_GET_URL && mState <= LOAD_FROM_HTTP_GET_DATA) ||
+ ((mState >= SEND_HTTP_REQ && mState <= WAIT_HTTP_REQ) ||
(mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
{
delete_ok = false;
@@ -1044,7 +1119,6 @@ bool LLTextureFetchWorker::deleteOK()
return delete_ok;
}
-
void LLTextureFetchWorker::removeFromCache()
{
if (!mInLocalCache)
@@ -1061,6 +1135,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()
if (mFormattedImage.isNull() || mRequestedSize < 0)
{
// not sure how we got here, but not a valid state, abort!
+ llassert_always(mDecodeHandle == 0);
mFormattedImage = NULL;
return true;
}
@@ -1074,6 +1149,12 @@ bool LLTextureFetchWorker::processSimulatorPackets()
buffer_size += mPackets[i]->mSize;
}
bool have_all_data = mLastPacket >= mTotalPackets-1;
+ if (mRequestedSize <= 0)
+ {
+ // We received a packed but haven't requested anything yet (edge case)
+ // Return true (we're "done") since we didn't request anything
+ return true;
+ }
if (buffer_size >= mRequestedSize || have_all_data)
{
/// We have enough (or all) data
@@ -1109,50 +1190,36 @@ bool LLTextureFetchWorker::processSimulatorPackets()
//////////////////////////////////////////////////////////////////////////////
-void LLTextureFetchWorker::callbackURLReceived(const LLSD& data, bool success)
+void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer,
+ bool last_block, bool success)
{
-#if 0
LLMutexLock lock(&mWorkMutex);
- if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_URL)
- {
- llwarns << "callbackURLReceived for unrequested fetch worker, req="
- << mSentRequest << " state= " << mState << llendl;
- return;
- }
- if (success)
- {
- mURL = data.asString();
- }
- mLoaded = TRUE;
- setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-#endif
-}
-
-//////////////////////////////////////////////////////////////////////////////
-void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_block)
-{
-#if 0
- LLMutexLock lock(&mWorkMutex);
- if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_DATA)
+ if (mState != WAIT_HTTP_REQ)
{
- llwarns << "callbackHttpGet for unrequested fetch worker, req="
- << mSentRequest << " state= " << mState << llendl;
+ llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
+ << " req=" << mSentRequest << " state= " << mState << llendl;
return;
}
-// llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
if (mLoaded)
{
llwarns << "Duplicate callback for " << mID.asString() << llendl;
return; // ignore duplicate callback
}
- if (data_size >= 0)
+ if (success)
{
+ // get length of stream:
+ S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+ gTextureList.sTextureBits += data_size * 8; // Approximate - does not include header bits
+
+ //llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
if (data_size > 0)
{
+ // *TODO: set the formatted image data here directly to avoid the copy
mBuffer = new U8[data_size];
- // *TODO: set the formatted image data here
- memcpy(mBuffer, data, data_size);
+ buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
mBufferSize += data_size;
if (data_size < mRequestedSize || last_block == true)
{
@@ -1160,10 +1227,11 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
}
else if (data_size > mRequestedSize)
{
- // *TODO: This will happen until we fix LLCurl::getByteRange()
-// llinfos << "HUH?" << llendl;
+ // *TODO: This shouldn't be happening any more
+ llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
mHaveAllData = TRUE;
- mFormattedImage->deleteData();
+ llassert_always(mDecodeHandle == 0);
+ mFormattedImage = NULL; // discard any previous data we had
mBufferSize = data_size;
}
}
@@ -1181,7 +1249,6 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
}
mLoaded = TRUE;
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-#endif
}
//////////////////////////////////////////////////////////////////////////////
@@ -1197,7 +1264,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima
}
if (success)
{
- llassert_always(imagesize > 0);
+ llassert_always(imagesize >= 0);
mFileSize = imagesize;
mFormattedImage = image;
mImageCodec = image->getCodec();
@@ -1225,65 +1292,40 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success)
//////////////////////////////////////////////////////////////////////////////
-void LLTextureFetchWorker::callbackDecoded(bool success)
+void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux)
{
+ LLMutexLock lock(&mWorkMutex);
+ if (mDecodeHandle == 0)
+ {
+ return; // aborted, ignore
+ }
if (mState != DECODE_IMAGE_UPDATE)
{
// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl;
+ mDecodeHandle = 0;
return;
}
-// llinfos << mID << " : DECODE COMPLETE " << llendl;
- setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-bool LLTextureFetchWorker::decodeImage()
-{
- if(!mImageWorker)
- {
- //LLTextureFetchWorker is aborted, skip image decoding.
- return true ;
- }
-
- bool res = true;
- if (mRawImage.isNull())
- {
- res = false;
- if (mImageWorker->requestDecodedData(mRawImage, -1))
- {
- res = true;
-// llinfos << mID << " : BASE DECODE FINISHED" << llendl;
- }
- }
- if (res &&
- (mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
- (mNeedsAux && mAuxImage.isNull()))
+ llassert_always(mFormattedImage.notNull());
+
+ mDecodeHandle = 0;
+ if (success)
{
- res = false;
- if (mImageWorker->requestDecodedAuxData(mAuxImage, 4, -1))
- {
- res = true;
-// llinfos << mID << " : AUX DECODE FINISHED" << llendl;
- }
+ llassert_always(raw);
+ mRawImage = raw;
+ mAuxImage = aux;
+ mDecodedDiscard = mFormattedImage->getDiscardLevel();
+ LL_DEBUGS("Texture") << mID << ": Decode Finished. Discard: " << mDecodedDiscard
+ << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
}
- if (res)
+ else
{
- if ((mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
- (!mNeedsAux || (mAuxImage.notNull() && mAuxImage->getDataSize() > 0)))
- {
- mDecodedDiscard = mFormattedImage->getDiscardLevel();
-// llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
- }
- else
- {
-// llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
- removeFromCache();
- }
- mImageWorker->scheduleDelete();
- mImageWorker = NULL;
+ llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
+ removeFromCache();
+ mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
}
- return res;
+ mDecoded = TRUE;
+// llinfos << mID << " : DECODE COMPLETE " << llendl;
+ setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
}
//////////////////////////////////////////////////////////////////////////////
@@ -1314,15 +1356,21 @@ bool LLTextureFetchWorker::writeToCacheComplete()
//////////////////////////////////////////////////////////////////////////////
// public
-LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded)
+LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded)
: LLWorkerThread("TextureFetch", threaded),
mDebugCount(0),
mDebugPause(FALSE),
mPacketCount(0),
mBadPacketCount(0),
mQueueMutex(getAPRPool()),
- mTextureCache(cache)
+ mNetworkQueueMutex(getAPRPool()),
+ mTextureCache(cache),
+ mImageDecodeThread(imagedecodethread),
+ mTextureBandwidth(0),
+ mCurlGetRequest(NULL)
{
+ mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+ mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
}
LLTextureFetch::~LLTextureFetch()
@@ -1330,13 +1378,7 @@ LLTextureFetch::~LLTextureFetch()
// ~LLQueuedThread() called here
}
-bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 priority,
- S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
-{
- return createRequest(LLStringUtil::null, id, host, priority, w, h, c, desired_discard, needs_aux);
-}
-
-bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
+bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
{
if (mDebugPause)
@@ -1361,7 +1403,14 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
}
S32 desired_size;
- if (desired_discard == 0)
+ std::string exten = gDirUtilp->getExtension(url);
+ if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
+ {
+ // Only do partial requests for J2C at the moment
+ //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl;
+ desired_size = MAX_IMAGE_DATA_SIZE;
+ }
+ else if (desired_discard == 0)
{
// if we want the entire image, and we know its size, then get it all
// (calcDataSizeJ2C() below makes assumptions about how the image
@@ -1378,7 +1427,7 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
}
else
{
- desired_size = FIRST_PACKET_SIZE;
+ desired_size = TEXTURE_CACHE_ENTRY_SIZE;
desired_discard = MAX_DISCARD_LEVEL;
}
@@ -1389,10 +1438,10 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
{
return false; // need to wait for previous aborted request to complete
}
- worker->lockWorkData();
+ worker->lockWorkMutex();
worker->setImagePriority(priority);
worker->setDesiredDiscard(desired_discard, desired_size);
- worker->unlockWorkData();
+ worker->unlockWorkMutex();
if (!worker->haveWork())
{
worker->mState = LLTextureFetchWorker::INIT;
@@ -1401,16 +1450,7 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
}
else
{
- if (filename.empty())
- {
- // do remote fetch
- worker = new LLTextureFetchWorker(this, id, host, priority, desired_discard, desired_size);
- }
- else
- {
- // do local file fetch
- worker = new LLTextureFetchLocalFileWorker(this, filename, id, host, priority, desired_discard, desired_size);
- }
+ worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
mRequestMap[id] = worker;
}
worker->mActiveCount++;
@@ -1430,10 +1470,9 @@ void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
}
// protected
-
-// call lockQueue() first!
void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
{
+ LLMutexLock lock(&mNetworkQueueMutex);
if (mRequestMap.find(worker->mID) != mRequestMap.end())
{
// only add to the queue if in the request map
@@ -1447,10 +1486,27 @@ void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
}
}
-// call lockQueue() first!
-void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker)
+void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
{
- mNetworkQueue.erase(worker->mID);
+ LLMutexLock lock(&mNetworkQueueMutex);
+ size_t erased = mNetworkQueue.erase(worker->mID);
+ if (cancel && erased > 0)
+ {
+ mCancelQueue[worker->mHost].insert(worker->mID);
+ }
+}
+
+// protected
+void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
+{
+ LLMutexLock lock(&mNetworkQueueMutex);
+ mHTTPTextureQueue.insert(id);
+}
+
+void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id)
+{
+ LLMutexLock lock(&mNetworkQueueMutex);
+ mHTTPTextureQueue.erase(id);
}
// call lockQueue() first!
@@ -1458,11 +1514,7 @@ void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
{
size_t erased_1 = mRequestMap.erase(worker->mID);
llassert_always(erased_1 > 0) ;
- size_t erased = mNetworkQueue.erase(worker->mID);
- if (cancel && erased > 0)
- {
- mCancelQueue[worker->mHost].insert(worker->mID);
- }
+ removeFromNetworkQueue(worker, cancel);
llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
worker->scheduleDelete();
@@ -1504,24 +1556,27 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
}
else if (worker->checkWork())
{
+ worker->lockWorkMutex();
discard_level = worker->mDecodedDiscard;
- raw = worker->mRawImage; worker->mRawImage = NULL;
- aux = worker->mAuxImage; worker->mAuxImage = NULL;
+ raw = worker->mRawImage;
+ aux = worker->mAuxImage;
res = true;
+ LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL;
+ worker->unlockWorkMutex();
}
else
{
- worker->lockWorkData();
+ worker->lockWorkMutex();
if ((worker->mDecodedDiscard >= 0) &&
(worker->mDecodedDiscard < discard_level || discard_level < 0) &&
(worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE))
{
// Not finished, but data is ready
discard_level = worker->mDecodedDiscard;
- if (worker->mRawImage) raw = worker->mRawImage;
- if (worker->mAuxImage) aux = worker->mAuxImage;
+ raw = worker->mRawImage;
+ aux = worker->mAuxImage;
}
- worker->unlockWorkData();
+ worker->unlockWorkMutex();
}
}
else
@@ -1538,9 +1593,9 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
LLTextureFetchWorker* worker = getWorker(id);
if (worker)
{
- worker->lockWorkData();
+ worker->lockWorkMutex();
worker->setImagePriority(priority);
- worker->unlockWorkData();
+ worker->unlockWorkMutex();
res = true;
}
return res;
@@ -1548,40 +1603,106 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
//////////////////////////////////////////////////////////////////////////////
+// MAIN THREAD
//virtual
S32 LLTextureFetch::update(U32 max_time_ms)
{
S32 res;
+
+ mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+
res = LLWorkerThread::update(max_time_ms);
- const F32 REQUEST_TIME = 1.f;
-
- // Periodically, gather the list of textures that need data from the network
- // And send the requests out to the simulators
- if (mNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME)
+ if (!mDebugPause)
{
- mNetworkTimer.reset();
sendRequestListToSimulators();
}
return res;
}
+// WORKER THREAD
+void LLTextureFetch::startThread()
+{
+ // Construct mCurlGetRequest from Worker Thread
+ mCurlGetRequest = new LLCurlRequest();
+}
+
+// WORKER THREAD
+void LLTextureFetch::endThread()
+{
+ // Destroy mCurlGetRequest from Worker Thread
+ delete mCurlGetRequest;
+ mCurlGetRequest = NULL;
+}
+
+// WORKER THREAD
+void LLTextureFetch::threadedUpdate()
+{
+ llassert_always(mCurlGetRequest);
+
+ // Limit update frequency
+ const F32 PROCESS_TIME = 0.05f;
+ static LLFrameTimer process_timer;
+ if (process_timer.getElapsedTimeF32() < PROCESS_TIME)
+ {
+ return;
+ }
+ process_timer.reset();
+
+ // Update Curl on same thread as mCurlGetRequest was constructed
+ S32 processed = mCurlGetRequest->process();
+ if (processed > 0)
+ {
+ lldebugs << "processed: " << processed << " messages." << llendl;
+ }
+
+#if 0
+ const F32 INFO_TIME = 1.0f;
+ static LLFrameTimer info_timer;
+ if (info_timer.getElapsedTimeF32() >= INFO_TIME)
+ {
+ S32 q = mCurlGetRequest->getQueued();
+ if (q > 0)
+ {
+ llinfos << "Queued gets: " << q << llendl;
+ info_timer.reset();
+ }
+ }
+#endif
+
+}
+
//////////////////////////////////////////////////////////////////////////////
void LLTextureFetch::sendRequestListToSimulators()
{
+ // All requests
+ const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps
+
+ // Sim requests
const S32 IMAGES_PER_REQUEST = 50;
- const F32 LAZY_FLUSH_TIMEOUT = 15.f; // 10.0f // temp
+ const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
const F32 MIN_REQUEST_TIME = 1.0f;
const F32 MIN_DELTA_PRIORITY = 1000.f;
- LLMutexLock lock(&mQueueMutex);
+ // Periodically, gather the list of textures that need data from the network
+ // And send the requests out to the simulators
+ static LLFrameTimer timer;
+ if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME)
+ {
+ return;
+ }
+ timer.reset();
+ LLMutexLock lock(&mQueueMutex);
+
// Send requests
typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t;
typedef std::map< LLHost, request_list_t > work_request_map_t;
work_request_map_t requests;
+ {
+ LLMutexLock lock2(&mNetworkQueueMutex);
for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); )
{
queue_t::iterator curiter = iter++;
@@ -1591,65 +1712,65 @@ void LLTextureFetch::sendRequestListToSimulators()
mNetworkQueue.erase(curiter);
continue; // paranoia
}
+ if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) &&
+ (req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR))
+ {
+ // We already received our URL, remove from the queue
+ llwarns << "Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl;
+ mNetworkQueue.erase(curiter);
+ continue;
+ }
if (req->mID == mDebugID)
{
mDebugCount++; // for setting breakpoints
}
- if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1)
+ if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM &&
+ req->mTotalPackets > 0 &&
+ req->mLastPacket >= req->mTotalPackets-1)
{
// We have all the packets... make sure this is high priority
// req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority);
continue;
}
F32 elapsed = req->mRequestedTimer.getElapsedTimeF32();
- F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
- if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
- (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
- (elapsed >= LAZY_FLUSH_TIMEOUT))
{
- requests[req->mHost].insert(req);
+ F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
+ if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
+ (delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
+ (elapsed >= SIM_LAZY_FLUSH_TIMEOUT))
+ {
+ requests[req->mHost].insert(req);
+ }
}
}
-
- std::string http_url;
-#if 0
- if (gSavedSettings.getBOOL("ImagePipelineUseHTTP"))
- {
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- http_url = region->getCapability("RequestTextureDownload");
- }
}
-#endif
-
+
for (work_request_map_t::iterator iter1 = requests.begin();
iter1 != requests.end(); ++iter1)
{
- bool use_http = http_url.empty() ? false : true;
LLHost host = iter1->first;
// invalid host = use agent host
if (host == LLHost::invalid)
{
host = gAgent.getRegionHost();
}
- else
- {
- use_http = false;
- }
- if (use_http)
+ S32 sim_request_count = 0;
+
+ for (request_list_t::iterator iter2 = iter1->second.begin();
+ iter2 != iter1->second.end(); ++iter2)
{
- }
- else
- {
- S32 request_count = 0;
- for (request_list_t::iterator iter2 = iter1->second.begin();
- iter2 != iter1->second.end(); ++iter2)
+ LLTextureFetchWorker* req = *iter2;
+ if (gMessageSystem)
{
- LLTextureFetchWorker* req = *iter2;
- req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
- if (0 == request_count)
+ if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM)
+ {
+ // Initialize packet data based on data read from cache
+ req->lockWorkMutex();
+ req->setupPacketData();
+ req->unlockWorkMutex();
+ }
+ if (0 == sim_request_count)
{
gMessageSystem->newMessageFast(_PREHASH_RequestImage);
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -1666,30 +1787,42 @@ void LLTextureFetch::sendRequestListToSimulators()
// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
- req->lockWorkData();
+ if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
+ {
+ mTextureInfo.setRequestStartTime(req->mID, LLTimer::getTotalTime());
+ mTextureInfo.setRequestOffset(req->mID, 0);
+ mTextureInfo.setRequestSize(req->mID, 0);
+ mTextureInfo.setRequestType(req->mID, LLTextureInfoDetails::REQUEST_TYPE_UDP);
+ }
+
+ req->lockWorkMutex();
+ req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
req->mSimRequestedDiscard = req->mDesiredDiscard;
req->mRequestedPriority = req->mImagePriority;
req->mRequestedTimer.reset();
- req->unlockWorkData();
- request_count++;
- if (request_count >= IMAGES_PER_REQUEST)
+ req->unlockWorkMutex();
+ sim_request_count++;
+ if (sim_request_count >= IMAGES_PER_REQUEST)
{
-// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
+// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
+
gMessageSystem->sendSemiReliable(host, NULL, NULL);
- request_count = 0;
+ sim_request_count = 0;
}
}
- if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
- {
-// llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
- gMessageSystem->sendSemiReliable(host, NULL, NULL);
- request_count = 0;
- }
+ }
+ if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST)
+ {
+// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
+ gMessageSystem->sendSemiReliable(host, NULL, NULL);
+ sim_request_count = 0;
}
}
// Send cancelations
- if (!mCancelQueue.empty())
+ {
+ LLMutexLock lock2(&mNetworkQueueMutex);
+ if (gMessageSystem && !mCancelQueue.empty())
{
for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
iter1 != mCancelQueue.end(); ++iter1)
@@ -1732,6 +1865,7 @@ void LLTextureFetch::sendRequestListToSimulators()
}
mCancelQueue.clear();
}
+ }
}
//////////////////////////////////////////////////////////////////////////////
@@ -1808,7 +1942,7 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
return false;
}
- worker->lockWorkData();
+ worker->lockWorkMutex();
// Copy header data into image object
worker->mImageCodec = codec;
@@ -1819,7 +1953,7 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
res = worker->insertPacket(0, data, data_size);
worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
- worker->unlockWorkData();
+ worker->unlockWorkMutex();
return res;
}
@@ -1853,7 +1987,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
return false;
}
- worker->lockWorkData();
+ worker->lockWorkMutex();
res = worker->insertPacket(packet_num, data, data_size);
@@ -1866,12 +2000,20 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
else
{
// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
-// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
- removeFromNetworkQueue(worker); // failsafe
- mCancelQueue[host].insert(id);
+// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
+ removeFromNetworkQueue(worker, true); // failsafe
}
-
- worker->unlockWorkData();
+
+ if(packet_num >= (worker->mTotalPackets - 1))
+ {
+ if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
+ {
+ U64 timeNow = LLTimer::getTotalTime();
+ mTextureInfo.setRequestSize(id, worker->mFileSize);
+ mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);
+ }
+ }
+ worker->unlockWorkMutex();
return res;
}
@@ -1885,9 +2027,9 @@ BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id)
LLTextureFetchWorker* worker = getWorker(id);
if (worker)
{
- worker->lockWorkData();
+ worker->lockWorkMutex() ;
from_cache = worker->mInLocalCache ;
- worker->unlockWorkData();
+ worker->unlockWorkMutex() ;
}
return from_cache ;
@@ -1907,7 +2049,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
LLTextureFetchWorker* worker = getWorker(id);
if (worker && worker->haveWork())
{
- worker->lockWorkData();
+ worker->lockWorkMutex();
state = worker->mState;
fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
@@ -1924,7 +2066,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
}
}
- if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA)
+ if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
{
requested_priority = worker->mRequestedPriority;
}
@@ -1933,7 +2075,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
requested_priority = worker->mImagePriority;
}
fetch_priority = worker->getPriority();
- worker->unlockWorkData();
+ worker->unlockWorkMutex();
}
data_progress_p = data_progress;
requested_priority_p = requested_priority;
@@ -1959,5 +2101,3 @@ void LLTextureFetch::dump()
}
}
-
-//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 97719a9468..373e38a83c 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -37,26 +37,29 @@
#include "llimage.h"
#include "lluuid.h"
#include "llworkerthread.h"
+#include "llcurl.h"
+#include "lltextureinfo.h"
class LLViewerTexture;
class LLTextureFetchWorker;
+class HTTPGetResponder;
class LLTextureCache;
+class LLImageDecodeThread;
class LLHost;
// Interface class
class LLTextureFetch : public LLWorkerThread
{
friend class LLTextureFetchWorker;
+ friend class HTTPGetResponder;
public:
- LLTextureFetch(LLTextureCache* cache, bool threaded);
+ LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded);
~LLTextureFetch();
/*virtual*/ S32 update(U32 max_time_ms);
- bool createRequest(const LLUUID& id, const LLHost& host, F32 priority,
- S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
- bool createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
+ bool createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
void deleteRequest(const LLUUID& id, bool cancel);
bool getRequestFinished(const LLUUID& id, S32& discard_level,
@@ -66,25 +69,39 @@ public:
bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data);
bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data);
+ void setTextureBandwidth(F32 bandwidth) { mTextureBandwidth = bandwidth; }
+ F32 getTextureBandwidth() { return mTextureBandwidth; }
+
// Debug
BOOL isFromLocalCache(const LLUUID& id);
S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p,
U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p);
void dump();
S32 getNumRequests() { return mRequestMap.size(); }
+ S32 getNumHTTPRequests() { return mHTTPTextureQueue.size(); }
// Public for access by callbacks
void lockQueue() { mQueueMutex.lock(); }
void unlockQueue() { mQueueMutex.unlock(); }
LLTextureFetchWorker* getWorker(const LLUUID& id);
+
+ LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
protected:
void addToNetworkQueue(LLTextureFetchWorker* worker);
- void removeFromNetworkQueue(LLTextureFetchWorker* worker);
+ void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
+ void addToHTTPQueue(const LLUUID& id);
+ void removeFromHTTPQueue(const LLUUID& id);
+ S32 getHTTPQueueSize() { return (S32)mHTTPTextureQueue.size(); }
void removeRequest(LLTextureFetchWorker* worker, bool cancel);
+ // Called from worker thread (during doWork)
+ void processCurlRequests();
private:
void sendRequestListToSimulators();
+ /*virtual*/ void startThread(void);
+ /*virtual*/ void endThread(void);
+ /*virtual*/ void threadedUpdate(void);
public:
LLUUID mDebugID;
@@ -95,8 +112,11 @@ public:
private:
LLMutex mQueueMutex;
+ LLMutex mNetworkQueueMutex;
LLTextureCache* mTextureCache;
+ LLImageDecodeThread* mImageDecodeThread;
+ LLCurlRequest* mCurlGetRequest;
// Map of all requests by UUID
typedef std::map<LLUUID,LLTextureFetchWorker*> map_t;
@@ -105,10 +125,13 @@ private:
// Set of requests that require network data
typedef std::set<LLUUID> queue_t;
queue_t mNetworkQueue;
+ queue_t mHTTPTextureQueue;
typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t;
cancel_queue_t mCancelQueue;
-
- LLFrameTimer mNetworkTimer;
+ F32 mTextureBandwidth;
+ F32 mMaxBandwidth;
+ LLTextureInfo mTextureInfo;
};
#endif // LL_LLTEXTUREFETCH_H
+
diff --git a/indra/newview/lltextureinfo.cpp b/indra/newview/lltextureinfo.cpp
new file mode 100644
index 0000000000..672a36a8bd
--- /dev/null
+++ b/indra/newview/lltextureinfo.cpp
@@ -0,0 +1,290 @@
+/**
+ * @file lltextureinfo.cpp
+ * @brief Object which handles local texture info
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltextureinfo.h"
+#include "lltexturestats.h"
+#include "llviewercontrol.h"
+
+LLTextureInfo::LLTextureInfo() :
+ mLogTextureDownloadsToViewerLog(false),
+ mLogTextureDownloadsToSimulator(false),
+ mTotalBytes(0),
+ mTotalMilliseconds(0),
+ mTextureDownloadsStarted(0),
+ mTextureDownloadsCompleted(0),
+ mTextureDownloadProtocol("NONE"),
+ mTextureLogThreshold(100 * 1024),
+ mCurrentStatsBundleStartTime(0)
+{
+ mTextures.clear();
+}
+
+void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold)
+{
+ mLogTextureDownloadsToViewerLog = writeToViewerLog;
+ mLogTextureDownloadsToSimulator = sendToSim;
+ mTextureLogThreshold = textureLogThreshold;
+}
+
+LLTextureInfo::~LLTextureInfo()
+{
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator;
+ for (iterator = mTextures.begin(); iterator != mTextures.end(); iterator++)
+ {
+ LLTextureInfoDetails *info = (*iterator).second;
+ delete info;
+ }
+
+ mTextures.clear();
+}
+
+void LLTextureInfo::addRequest(const LLUUID& id)
+{
+ LLTextureInfoDetails *info = new LLTextureInfoDetails();
+ mTextures[id] = info;
+}
+
+U32 LLTextureInfo::getTextureInfoMapSize()
+{
+ return mTextures.size();
+}
+
+bool LLTextureInfo::has(const LLUUID& id)
+{
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+ if (iterator == mTextures.end())
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime)
+{
+ if (!has(id))
+ {
+ addRequest(id);
+ }
+ mTextures[id]->mStartTime = startTime;
+ mTextureDownloadsStarted++;
+}
+
+void LLTextureInfo::setRequestSize(const LLUUID& id, U32 size)
+{
+ if (!has(id))
+ {
+ addRequest(id);
+ }
+ mTextures[id]->mSize = size;
+}
+
+void LLTextureInfo::setRequestOffset(const LLUUID& id, U32 offset)
+{
+ if (!has(id))
+ {
+ addRequest(id);
+ }
+ mTextures[id]->mOffset = offset;
+}
+
+void LLTextureInfo::setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type)
+{
+ if (!has(id))
+ {
+ addRequest(id);
+ }
+ mTextures[id]->mType = type;
+}
+
+void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime)
+{
+ if (!has(id))
+ {
+ addRequest(id);
+ }
+ mTextures[id]->mCompleteTime = completeTime;
+
+ std::string protocol = "NONE";
+ switch(mTextures[id]->mType)
+ {
+ case LLTextureInfoDetails::REQUEST_TYPE_HTTP:
+ protocol = "HTTP";
+ break;
+
+ case LLTextureInfoDetails::REQUEST_TYPE_UDP:
+ protocol = "UDP";
+ break;
+
+ case LLTextureInfoDetails::REQUEST_TYPE_NONE:
+ default:
+ break;
+ }
+
+ if (mLogTextureDownloadsToViewerLog)
+ {
+ llinfos << "texture=" << id
+ << " start=" << mTextures[id]->mStartTime
+ << " end=" << mTextures[id]->mCompleteTime
+ << " size=" << mTextures[id]->mSize
+ << " offset=" << mTextures[id]->mOffset
+ << " length_in_ms=" << (mTextures[id]->mCompleteTime - mTextures[id]->mStartTime) / 1000
+ << " protocol=" << protocol
+ << llendl;
+ }
+
+ if(mLogTextureDownloadsToSimulator)
+ {
+ S32 texture_stats_upload_threshold = mTextureLogThreshold;
+ mTotalBytes += mTextures[id]->mSize;
+ mTotalMilliseconds += mTextures[id]->mCompleteTime - mTextures[id]->mStartTime;
+ mTextureDownloadsCompleted++;
+ mTextureDownloadProtocol = protocol;
+ if (mTotalBytes >= texture_stats_upload_threshold)
+ {
+ LLSD texture_data;
+ std::stringstream startTime;
+ startTime << mCurrentStatsBundleStartTime;
+ texture_data["start_time"] = startTime.str();
+ std::stringstream endTime;
+ endTime << completeTime;
+ texture_data["end_time"] = endTime.str();
+ texture_data["averages"] = getAverages();
+ send_texture_stats_to_sim(texture_data);
+ resetTextureStatistics();
+ }
+ }
+
+ mTextures.erase(id);
+}
+
+LLSD LLTextureInfo::getAverages()
+{
+ LLSD averagedTextureData;
+ S32 averageDownloadRate;
+ if(mTotalMilliseconds == 0)
+ {
+ averageDownloadRate = 0;
+ }
+ else
+ {
+ averageDownloadRate = (mTotalBytes * 8) / mTotalMilliseconds;
+ }
+
+ averagedTextureData["bits_per_second"] = averageDownloadRate;
+ averagedTextureData["bytes_downloaded"] = mTotalBytes;
+ averagedTextureData["texture_downloads_started"] = mTextureDownloadsStarted;
+ averagedTextureData["texture_downloads_completed"] = mTextureDownloadsCompleted;
+ averagedTextureData["transport"] = mTextureDownloadProtocol;
+
+ return averagedTextureData;
+}
+
+void LLTextureInfo::resetTextureStatistics()
+{
+ mTotalMilliseconds = 0;
+ mTotalBytes = 0;
+ mTextureDownloadsStarted = 0;
+ mTextureDownloadsCompleted = 0;
+ mTextureDownloadProtocol = "NONE";
+ mCurrentStatsBundleStartTime = LLTimer::getTotalTime();
+}
+
+U32 LLTextureInfo::getRequestStartTime(const LLUUID& id)
+{
+ if (!has(id))
+ {
+ return 0;
+ }
+ else
+ {
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+ return (*iterator).second->mStartTime;
+ }
+}
+
+U32 LLTextureInfo::getRequestSize(const LLUUID& id)
+{
+ if (!has(id))
+ {
+ return 0;
+ }
+ else
+ {
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+ return (*iterator).second->mSize;
+ }
+}
+
+U32 LLTextureInfo::getRequestOffset(const LLUUID& id)
+{
+ if (!has(id))
+ {
+ return 0;
+ }
+ else
+ {
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+ return (*iterator).second->mOffset;
+ }
+}
+
+LLTextureInfoDetails::LLRequestType LLTextureInfo::getRequestType(const LLUUID& id)
+{
+ if (!has(id))
+ {
+ return LLTextureInfoDetails::REQUEST_TYPE_NONE;
+ }
+ else
+ {
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+ return (*iterator).second->mType;
+ }
+}
+
+U32 LLTextureInfo::getRequestCompleteTime(const LLUUID& id)
+{
+ if (!has(id))
+ {
+ return 0;
+ }
+ else
+ {
+ std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+ return (*iterator).second->mCompleteTime;
+ }
+}
+
diff --git a/indra/newview/lltextureinfo.h b/indra/newview/lltextureinfo.h
new file mode 100644
index 0000000000..71b0ea431f
--- /dev/null
+++ b/indra/newview/lltextureinfo.h
@@ -0,0 +1,80 @@
+/**
+ * @file lltextureinfo.h
+ * @brief Object for managing texture information.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTEXTUREINFO_H
+#define LL_LLTEXTUREINFO_H
+
+#include "lluuid.h"
+#include "lltextureinfodetails.h"
+#include <map>
+
+class LLTextureInfo
+{
+public:
+ LLTextureInfo();
+ ~LLTextureInfo();
+
+ void setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold);
+ bool has(const LLUUID& id);
+ void setRequestStartTime(const LLUUID& id, U64 startTime);
+ void setRequestSize(const LLUUID& id, U32 size);
+ void setRequestOffset(const LLUUID& id, U32 offset);
+ void setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type);
+ void setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime);
+ U32 getRequestStartTime(const LLUUID& id);
+ U32 getRequestSize(const LLUUID& id);
+ U32 getRequestOffset(const LLUUID& id);
+ LLTextureInfoDetails::LLRequestType getRequestType(const LLUUID& id);
+ U32 getRequestCompleteTime(const LLUUID& id);
+ void resetTextureStatistics();
+ U32 getTextureInfoMapSize();
+ LLSD getAverages();
+
+private:
+ void addRequest(const LLUUID& id);
+
+ std::map<LLUUID, LLTextureInfoDetails *> mTextures;
+
+ LLSD mAverages;
+
+ bool mLogTextureDownloadsToViewerLog;
+ bool mLogTextureDownloadsToSimulator;
+ S32 mTotalBytes;
+ S32 mTotalMilliseconds;
+ S32 mTextureDownloadsStarted;
+ S32 mTextureDownloadsCompleted;
+ std::string mTextureDownloadProtocol;
+ U32 mTextureLogThreshold; // in bytes
+ U64 mCurrentStatsBundleStartTime;
+};
+
+#endif // LL_LLTEXTUREINFO_H
diff --git a/indra/newview/lltextureinfodetails.cpp b/indra/newview/lltextureinfodetails.cpp
new file mode 100644
index 0000000000..f6ef47a2ee
--- /dev/null
+++ b/indra/newview/lltextureinfodetails.cpp
@@ -0,0 +1,40 @@
+/**
+ * @file lltextureinfodetails.cpp
+ * @brief Object which handles details of any individual texture
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltextureinfodetails.h"
+
+LLTextureInfoDetails::LLTextureInfoDetails() : mStartTime(0), mCompleteTime(0), mSize(0), mType(REQUEST_TYPE_NONE), mOffset(0)
+{
+}
+
diff --git a/indra/newview/lltextureinfodetails.h b/indra/newview/lltextureinfodetails.h
new file mode 100644
index 0000000000..091fa01a3d
--- /dev/null
+++ b/indra/newview/lltextureinfodetails.h
@@ -0,0 +1,58 @@
+/**
+ * @file lltextureinfo.h
+ * @brief Object for managing texture information.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTEXTUREINFODETAILS_H
+#define LL_LLTEXTUREINFODETAILS_H
+
+#include "lluuid.h"
+
+class LLTextureInfoDetails
+{
+public:
+ enum LLRequestType
+ {
+ REQUEST_TYPE_NONE,
+ REQUEST_TYPE_HTTP,
+ REQUEST_TYPE_UDP
+ };
+
+ U32 mStartTime;
+ U32 mCompleteTime;
+ U32 mOffset;
+ U32 mSize;
+ LLRequestType mType;
+
+ LLTextureInfoDetails();
+};
+
+#endif // LL_LLTEXTUREINFODETAILS_H
+
diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp
new file mode 100644
index 0000000000..c91bfd4df2
--- /dev/null
+++ b/indra/newview/lltexturestats.cpp
@@ -0,0 +1,61 @@
+/**
+ * @file lltexturerstats.cpp
+ * @brief texture stats helper methods
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "pipeline.h"
+#include "llagent.h"
+#include "lltexturefetch.h"
+#include "lltexturestats.h"
+#include "lltexturestatsuploader.h"
+#include "llviewerregion.h"
+
+void send_texture_stats_to_sim(const LLSD &texture_stats)
+{
+ LLSD texture_stats_report;
+ // Only send stats if the agent is connected to a region.
+ if (!gAgent.getRegion() || gNoRender)
+ {
+ return;
+ }
+
+ LLUUID agent_id = gAgent.getID();
+ texture_stats_report["agent_id"] = agent_id;
+ texture_stats_report["region_id"] = gAgent.getRegion()->getRegionID();
+ texture_stats_report["stats_data"] = texture_stats;
+
+ std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats");
+ LLTextureStatsUploader tsu;
+ llinfos << "uploading texture stats data to simulator" << llendl;
+ tsu.uploadStatsToSimulator(texture_cap_url, texture_stats);
+}
+
diff --git a/indra/newview/lltexturestats.h b/indra/newview/lltexturestats.h
new file mode 100644
index 0000000000..2deb377dfd
--- /dev/null
+++ b/indra/newview/lltexturestats.h
@@ -0,0 +1,41 @@
+/**
+ * @file lltexturestats.h
+ * @brief texture stats utilities
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTEXTURESTATS_H
+#define LL_LLTEXTURESTATS_H
+
+#include "llappviewer.h"
+
+// utility functions to capture data on texture download speeds and send to simulator periodically
+void send_texture_stats_to_sim(const LLSD &texture_stats);
+
+#endif // LL_LLTEXTURESTATS_H
diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp
new file mode 100644
index 0000000000..e0358e1fca
--- /dev/null
+++ b/indra/newview/lltexturestatsuploader.cpp
@@ -0,0 +1,59 @@
+/**
+ * @file lltexturerstats.cpp
+ * @brief texture stats upload class
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lltexturestatsuploader.h"
+
+LLTextureStatsUploader::LLTextureStatsUploader()
+{
+}
+
+LLTextureStatsUploader::~LLTextureStatsUploader()
+{
+}
+
+void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats)
+{
+ if ( texture_cap_url != "" )
+ {
+ LLHTTPClient::post(texture_cap_url, texture_stats, NULL);
+ }
+ else
+ {
+ llinfos << "Not sending texture stats: "
+ << texture_stats
+ << " as there is no cap url."
+ << llendl;
+ }
+}
+
diff --git a/indra/newview/lltexturestatsuploader.h b/indra/newview/lltexturestatsuploader.h
new file mode 100644
index 0000000000..f6cc8be8fe
--- /dev/null
+++ b/indra/newview/lltexturestatsuploader.h
@@ -0,0 +1,48 @@
+/**
+ * @file lltexturestatsuploader.h
+ * @brief Class to send the texture stats to the simulatore
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLTEXTURESTATSUPLOADER_H
+#define LL_LLTEXTURESTATSUPLOADER_H
+
+#include "llappviewer.h"
+
+// utility functions to capture data on texture download speeds and send to simulator periodically
+
+class LLTextureStatsUploader
+{
+public:
+ LLTextureStatsUploader();
+ ~LLTextureStatsUploader();
+ void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats);
+};
+
+#endif // LL_LLTEXTURESTATSUPLOADER_H
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index ea675c5a6e..44ef6717e7 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -44,19 +44,21 @@
#include "llrender.h"
#include "lltooltip.h"
+#include "llappviewer.h"
#include "llselectmgr.h"
#include "lltexlayer.h"
#include "lltexturecache.h"
#include "lltexturefetch.h"
+#include "llviewercontrol.h"
#include "llviewerobject.h"
#include "llviewertexture.h"
#include "llviewertexturelist.h"
-#include "llappviewer.h"
-
+#include "llvovolume.h"
extern F32 texmem_lower_bound_scale;
LLTextureView *gTextureView = NULL;
LLTextureSizeView *gTextureSizeView = NULL;
+LLTextureSizeView *gTextureCategoryView = NULL;
//static
std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages;
@@ -230,10 +232,10 @@ void LLTextureBar::draw()
{ "DSK", LLColor4::blue }, // CACHE_POST
{ "NET", LLColor4::green }, // LOAD_FROM_NETWORK
{ "SIM", LLColor4::green }, // LOAD_FROM_SIMULATOR
- { "URL", LLColor4::green2 },// LOAD_FROM_HTTP_GET_URL
- { "HTP", LLColor4::green }, // LOAD_FROM_HTTP_GET_DATA
+ { "REQ", LLColor4::yellow },// SEND_HTTP_REQ
+ { "HTP", LLColor4::green }, // WAIT_HTTP_REQ
{ "DEC", LLColor4::yellow },// DECODE_IMAGE
- { "DEC", LLColor4::yellow },// DECODE_IMAGE_UPDATE
+ { "DEC", LLColor4::green }, // DECODE_IMAGE_UPDATE
{ "WRT", LLColor4::purple },// WRITE_TO_CACHE
{ "WRT", LLColor4::orange },// WAIT_ON_WRITE
{ "END", LLColor4::red }, // DONE
@@ -261,7 +263,7 @@ void LLTextureBar::draw()
// Draw the progress bar.
S32 bar_width = 100;
- S32 bar_left = 280;
+ S32 bar_left = 260;
left = bar_left;
right = left + bar_width;
@@ -286,30 +288,31 @@ void LLTextureBar::draw()
S32 pip_x = title_x3 + pip_space/2;
// Draw the packet pip
+ const F32 pip_max_time = 5.f;
F32 last_event = mImagep->mLastPacketTimer.getElapsedTimeF32();
- if (last_event < 1.f)
+ if (last_event < pip_max_time)
{
clr = LLColor4::white;
}
else
{
last_event = mImagep->mRequestDeltaTime;
- if (last_event < 1.f)
+ if (last_event < pip_max_time)
{
clr = LLColor4::green;
}
else
{
last_event = mImagep->mFetchDeltaTime;
- if (last_event < 1.f)
+ if (last_event < pip_max_time)
{
clr = LLColor4::yellow;
}
}
}
- if (last_event < 1.f)
+ if (last_event < pip_max_time)
{
- clr.setAlpha(1.f - last_event);
+ clr.setAlpha(1.f - last_event/pip_max_time);
gGL.color4fv(clr.mV);
gl_rect_2d(pip_x, top, pip_x + pip_width, bottom);
}
@@ -406,89 +409,113 @@ void LLGLTexMemBar::draw()
S32 total_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sTotalTextureMemoryInBytes);
S32 max_total_mem = LLViewerTexture::sMaxTotalTextureMemInMegaBytes;
F32 discard_bias = LLViewerTexture::sDesiredDiscardBias;
+ F32 cache_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getUsage()) ;
+ F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ;
S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
S32 h_offset = (S32)((texture_bar_height + 2.5f) * mTextureView->mNumTextureBars + 2.5f);
//----------------------------------------------------------------------------
LLGLSUIDefault gls_ui;
- F32 text_color[] = {1.f, 1.f, 1.f, 0.75f};
+ LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
+ LLColor4 color;
std::string text;
- text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Discard Bias: %.2f",
+ text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
total_mem,
max_total_mem,
bound_mem,
max_bound_mem,
- discard_bias);
+ LLImageRaw::sGlobalRawMemory >> 20, discard_bias,
+ cache_usage, cache_max_usage);
+ //, cache_entries, cache_max_entries
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, h_offset + line_height*3,
- text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
//----------------------------------------------------------------------------
- S32 bar_left = 380;
+#if 0
+ S32 bar_left = 400;
S32 bar_width = 200;
S32 top = line_height*3 - 2 + h_offset;
S32 bottom = top - 6;
S32 left = bar_left;
S32 right = left + bar_width;
-
- F32 bar_scale = (F32)bar_width / (max_bound_mem * 1.5f);
+ F32 bar_scale;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f);
- gl_rect_2d(left, top, right, bottom);
-
+ // GL Mem Bar
+
left = bar_left;
- right = left + llfloor(bound_mem * bar_scale);
- if (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale))
- {
- gGL.color4f(0.f, 1.f, 0.f, 0.75f);
- }
- else if (bound_mem < max_bound_mem)
- {
- gGL.color4f(1.f, 1.f, 0.f, 0.75f);
- }
- else
- {
- gGL.color4f(1.f, 0.f, 0.f, 0.75f);
- }
+ text = "GL";
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*3,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+ left = bar_left+20;
+ right = left + bar_width;
+
+ gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f); // grey
gl_rect_2d(left, top, right, bottom);
bar_scale = (F32)bar_width / (max_total_mem * 1.5f);
+ right = left + llfloor(total_mem * bar_scale);
+ right = llclamp(right, bar_left, bar_left + bar_width);
- top = bottom - 2;
- bottom = top - 6;
+ color = (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale)) ? LLColor4::green :
+ (total_mem < max_total_mem) ? LLColor4::yellow : LLColor4::red;
+ color[VALPHA] = .75f;
+ glColor4fv(color.mV);
+
+ gl_rect_2d(left, top, right, bottom); // red/yellow/green
+
+ //
+ bar_left += bar_width + bar_space;
+ //top = bottom - 2; bottom = top - 6;
+
+ // Bound Mem Bar
+
left = bar_left;
- right = left + llfloor(total_mem * bar_scale);
- if (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale))
- {
- gGL.color4f(0.f, 1.f, 0.f, 0.75f);
- }
- else if (total_mem < max_total_mem)
- {
- gGL.color4f(1.f, 1.f, 0.f, 0.75f);
- }
- else
- {
- gGL.color4f(1.f, 0.f, 0.f, 0.75f);
- }
+ text = "GL";
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*3,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ left = bar_left + 20;
+ right = left + bar_width;
+
+ gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f);
gl_rect_2d(left, top, right, bottom);
+ color = (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale)) ? LLColor4::green :
+ (bound_mem < max_bound_mem) ? LLColor4::yellow : LLColor4::red;
+ color[VALPHA] = .75f;
+ glColor4fv(color.mV);
+
+ gl_rect_2d(left, top, right, bottom);
+#else
+ S32 left = 0 ;
+#endif
//----------------------------------------------------------------------------
- text = llformat("Textures: Count: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d(%d) RAW:%d mRaw:%d mAux:%d CB:%d",
+ text = llformat("Textures: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d RAW:%d HTP:%d",
gTextureList.getNumImages(),
LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(),
LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount,
LLAppViewer::getTextureCache()->getNumReads(), LLAppViewer::getTextureCache()->getNumWrites(),
LLLFSThread::sLocal->getPending(),
- LLImageWorker::sCount, LLImageWorker::getWorkerThread()->getNumDeletes(),
- LLImageRaw::sRawImageCount, LLViewerFetchedTexture::sRawCount, LLViewerFetchedTexture::sAuxCount,
- gTextureList.mCallbackList.size());
+ LLAppViewer::getImageDecodeThread()->getPending(),
+ LLImageRaw::sRawImageCount,
+ LLAppViewer::getTextureFetch()->getNumHTTPRequests());
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, h_offset + line_height*2,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+
+ left = 550;
+ F32 bandwidth = LLAppViewer::getTextureFetch()->getTextureBandwidth();
+ F32 max_bandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+ color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color;
+ color[VALPHA] = text_color[VALPHA];
+ text = llformat("BW:%.0f/%.0f",bandwidth, max_bandwidth);
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*2,
+ color, LLFontGL::LEFT, LLFontGL::TOP);
S32 dx1 = 0;
if (LLAppViewer::getTextureFetch()->mDebugPause)
@@ -555,7 +582,7 @@ public:
void setTop(S32 loaded, S32 bound, F32 scale) {mTopLoaded = loaded ; mTopBound = bound; mScale = scale ;}
void draw();
- BOOL handleHover(S32 x, S32 y, MASK mask) ;
+ BOOL handleHover(S32 x, S32 y, MASK mask, BOOL set_pick_size) ;
private:
S32 mIndex ;
@@ -568,19 +595,16 @@ private:
F32 mScale ;
};
-BOOL LLGLTexSizeBar::handleHover(S32 x, S32 y, MASK mask)
+BOOL LLGLTexSizeBar::handleHover(S32 x, S32 y, MASK mask, BOOL set_pick_size)
{
-#if !LL_RELEASE_FOR_DOWNLOAD
if(y > mBottom && (y < mBottom + (S32)(mTopLoaded * mScale) || y < mBottom + (S32)(mTopBound * mScale)))
{
- LLImageGL::setCurTexSizebar(mIndex);
+ LLImageGL::setCurTexSizebar(mIndex, set_pick_size);
}
-#endif
return TRUE ;
}
void LLGLTexSizeBar::draw()
{
-#if !LL_RELEASE_FOR_DOWNLOAD
LLGLSUIDefault gls_ui;
if(LLImageGL::sCurTexSizeBar == mIndex)
@@ -601,7 +625,6 @@ void LLGLTexSizeBar::draw()
F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f};
gl_rect_2d(mLeft, mBottom + (S32)(mTopLoaded * mScale), (mLeft + mRight) / 2, mBottom, loaded_color) ;
gl_rect_2d((mLeft + mRight) / 2, mBottom + (S32)(mTopBound * mScale), mRight, mBottom, bound_color) ;
-#endif
}
////////////////////////////////////////////////////////////////////////////
@@ -675,7 +698,13 @@ void LLTextureView::draw()
<< "\t" << cur_discard
<< llendl;
}
-
+
+ if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID)
+ {
+ static S32 debug_count = 0;
+ ++debug_count; // for breakpoints
+ }
+
#if 0
if (imagep->getDontDiscard())
{
@@ -889,8 +918,7 @@ BOOL LLTextureView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
}
//-----------------------------------------------------------------
-LLTextureSizeView::LLTextureSizeView(const LLTextureSizeView::Params& p)
- : LLView(p)
+LLTextureSizeView::LLTextureSizeView(const LLTextureSizeView::Params& p) : LLContainerView(p)
{
setVisible(FALSE) ;
@@ -910,7 +938,31 @@ LLTextureSizeView::~LLTextureSizeView()
}
void LLTextureSizeView::draw()
{
-#if !LL_RELEASE_FOR_DOWNLOAD
+ if(mType == TEXTURE_MEM_OVER_SIZE)
+ {
+ drawTextureSizeGraph();
+ }
+ else
+ {
+ drawTextureCategoryGraph() ;
+ }
+
+ LLView::draw();
+}
+
+BOOL LLTextureSizeView::handleHover(S32 x, S32 y, MASK mask)
+{
+ if(x > mTextureSizeBarRect.mLeft && x < mTextureSizeBarRect.mRight)
+ {
+ mTextureSizeBar[(x - mTextureSizeBarRect.mLeft) / mTextureSizeBarWidth]->handleHover(x, y, mask, (mType == TEXTURE_MEM_OVER_SIZE)) ;
+ }
+
+ return TRUE ;
+}
+
+//draw real-time texture mem bar over size
+void LLTextureSizeView::drawTextureSizeGraph()
+{
if(mTextureSizeBar.size() == 0)
{
S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
@@ -931,29 +983,16 @@ void LLTextureSizeView::draw()
mTextureSizeBar[i]->draw() ;
}
LLImageGL::resetCurTexSizebar();
-
- LLView::draw();
-#endif
-}
-
-BOOL LLTextureSizeView::handleHover(S32 x, S32 y, MASK mask)
-{
- if(x > mTextureSizeBarRect.mLeft && x < mTextureSizeBarRect.mRight)
- {
- mTextureSizeBar[(x - mTextureSizeBarRect.mLeft) / mTextureSizeBarWidth]->handleHover(x, y, mask) ;
- }
-
- return TRUE ;
}
//draw background of texture size bar graph
F32 LLTextureSizeView::drawTextureSizeDistributionGraph()
{
+ //scale
F32 scale = 1.0f ;
-#if !LL_RELEASE_FOR_DOWNLOAD
+
LLGLSUIDefault gls_ui;
- //scale
{
S32 count = 0 ;
for(U32 i = 0 ; i < LLImageGL::sTextureLoadedCounter.size() ; i++)
@@ -1043,8 +1082,137 @@ F32 LLTextureSizeView::drawTextureSizeDistributionGraph()
text = llformat("Texture Size Distribution") ;
LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
-
-#endif
return scale ;
}
+//draw real-time texture mem bar over category
+void LLTextureSizeView::drawTextureCategoryGraph()
+{
+ if(mTextureSizeBar.size() == 0)
+ {
+ S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+ mTextureSizeBar.resize(LLViewerTexture::getTotalNumOfCategories()) ;
+ mTextureSizeBarRect.set(700, line_height * 2 + 400, 700 + mTextureSizeBar.size() * mTextureSizeBarWidth, line_height * 2) ;
+
+ for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+ {
+ mTextureSizeBar[i] = new LLGLTexSizeBar(i, mTextureSizeBarRect.mLeft + i * mTextureSizeBarWidth ,
+ line_height * 2, mTextureSizeBarRect.mLeft + (i + 1) * mTextureSizeBarWidth, line_height) ;
+ }
+ }
+
+ F32 size_bar_scale = drawTextureCategoryDistributionGraph() ;
+ for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+ {
+ U32 k = LLViewerTexture::getIndexFromCategory(i) ;
+ mTextureSizeBar[i]->setTop(LLImageGL::sTextureMemByCategory[k] >> 20, LLImageGL::sTextureMemByCategoryBound[k] >> 20, size_bar_scale) ;
+ mTextureSizeBar[i]->draw() ;
+ }
+ LLImageGL::resetCurTexSizebar();
+}
+
+//draw background for TEXTURE_MEM_OVER_CATEGORY
+F32 LLTextureSizeView::drawTextureCategoryDistributionGraph()
+{
+ //scale
+ F32 scale = 4.0f ;
+
+ LLGLSUIDefault gls_ui;
+
+ {
+ S32 count = 0 ;
+ for(U32 i = 0 ; i < LLImageGL::sTextureMemByCategory.size() ; i++)
+ {
+ S32 tmp = LLImageGL::sTextureMemByCategory[i] >> 20 ;
+ if(tmp > count)
+ {
+ count = tmp ;
+ }
+ }
+ if(count > mTextureSizeBarRect.getHeight() * 0.25f)
+ {
+ scale = (F32)mTextureSizeBarRect.getHeight() * 0.25f / count ;
+ }
+ }
+
+ S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+ S32 left = mTextureSizeBarRect.mLeft ;
+ S32 bottom = mTextureSizeBarRect.mBottom ;
+ S32 right = mTextureSizeBarRect.mRight ;
+ S32 top = mTextureSizeBarRect.mTop ;
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ //background rect
+ gl_rect_2d(left - 25, top + 30, right + 100, bottom - 25, LLColor4(0.0f, 0.0f, 0.0f, 0.25f)) ;
+
+ //--------------------------------------------------
+ gGL.color4f(1.0f, 0.5f, 0.5f, 0.75f);
+ gl_line_2d(left, bottom, right, bottom) ; //x axis
+ gl_line_2d(left, bottom, left, top) ; //y axis
+
+ //ruler
+ //--------------------------------------------------
+ gGL.color4f(1.0f, 0.5f, 0.5f, 0.5f);
+ for(S32 i = bottom + 50 ; i <= top ; i += 50)
+ {
+ gl_line_2d(left, i, right, i) ;
+ }
+
+ //texts
+ //--------------------------------------------------
+ F32 text_color[] = {1.f, 1.f, 1.f, 0.75f};
+ std::string text;
+
+ //-------
+ //x axis: size label
+ static char category[LLViewerTexture::MAX_GL_IMAGE_CATEGORY][4] =
+ {"Non", "Bak", "Av", "Cld", "Scp", "Hi", "Trn", "Slt", "Hud", "Bsf", "UI", "Pvw", "Map", "Mvs", "Slf", "Loc", "Scr", "Dyn", "Mdi", "ALT", "Oth" } ;
+
+ text = llformat("%s", category[0]) ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 12, bottom - line_height / 2,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ for(U32 i = 1 ; i < mTextureSizeBar.size() ; i++)
+ {
+ text = llformat("%s", category[i]) ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + i * mTextureSizeBarWidth + 12, bottom - line_height / 2,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ }
+ //-------
+
+ //y axis: number label
+ for(S32 i = bottom + 50 ; i <= top ; i += 50)
+ {
+ text = llformat("%d", (S32)((i - bottom) / scale)) ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, i + line_height / 2 ,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 5, i + line_height / 2 ,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ }
+
+ text = llformat("MB") ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, top + line_height * 2 ,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+ //--------------------------------------------------
+ F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f};
+ gl_rect_2d(left + 70, top + line_height * 2, left + 90, top + line_height, loaded_color) ;
+ text = llformat("Loaded") ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 100, top + line_height * 2,
+ loaded_color,
+ LLFontGL::LEFT, LLFontGL::TOP);
+
+ F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f};
+ gl_rect_2d(left + 170, top + line_height * 2, left + 190, top + line_height, bound_color) ;
+ text = llformat("Bound") ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 200, top + line_height * 2,
+ bound_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+ //--------------------------------------------------
+
+ //title
+ text = llformat("Texture Category Distribution") ;
+ LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3,
+ text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+ return scale ;
+}
diff --git a/indra/newview/lltextureview.h b/indra/newview/lltextureview.h
index e917c0235e..435a55df83 100644
--- a/indra/newview/lltextureview.h
+++ b/indra/newview/lltextureview.h
@@ -79,24 +79,41 @@ public:
};
class LLGLTexSizeBar;
-
-class LLTextureSizeView : public LLView
+class LLTextureSizeView : public LLContainerView
{
-public:
+protected:
LLTextureSizeView(const Params&);
+ friend class LLUICtrlFactory;
+public:
~LLTextureSizeView();
/*virtual*/ void draw();
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) ;
+ void setType(S32 type) {mType = type ;}
+ enum
+ {
+ TEXTURE_MEM_OVER_SIZE,
+ TEXTURE_MEM_OVER_CATEGORY
+ };
private:
+ //draw background for TEXTURE_MEM_OVER_SIZE
F32 drawTextureSizeDistributionGraph() ;
-
+ //draw real-time texture mem bar over size
+ void drawTextureSizeGraph();
+
+ //draw background for TEXTURE_MEM_OVER_CATEGORY
+ F32 drawTextureCategoryDistributionGraph() ;
+ //draw real-time texture mem bar over category
+ void drawTextureCategoryGraph();
+
private:
std::vector<LLGLTexSizeBar*> mTextureSizeBar ;
LLRect mTextureSizeBarRect ;
- S32 mTextureSizeBarWidth ;
+ S32 mTextureSizeBarWidth ;
+ S32 mType ;
};
extern LLTextureView *gTextureView;
extern LLTextureSizeView *gTextureSizeView;
+extern LLTextureSizeView *gTextureCategoryView;
#endif // LL_TEXTURE_VIEW_H
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index 841902f683..a3daca6fa4 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -46,7 +46,7 @@
#include "llstartup.h" // gStartupState
#include "llurlsimstring.h"
#include "llweb.h"
-#include "llworldmap.h"
+#include "llworldmapmessage.h"
// library includes
#include "llsd.h"
@@ -201,7 +201,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mous
//if(url_displayp) url_displayp->setName(region_name);
// Request a region handle by name
- LLWorldMap::getInstance()->sendNamedRegionRequest(region_name,
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name,
LLURLDispatcherImpl::regionNameCallback,
url,
false); // don't teleport
@@ -240,7 +240,7 @@ void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::strin
LLVector3d global_pos = from_region_handle(region_handle) + LLVector3d(local_pos);
U64 new_region_handle = to_region_handle(global_pos);
- LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle,
+ LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle,
LLURLDispatcherImpl::regionHandleCallback,
url, teleport);
}
@@ -335,7 +335,7 @@ public:
{
url += tokens[i].asString() + "/";
}
- LLWorldMap::getInstance()->sendNamedRegionRequest(region_name,
+ LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name,
LLURLDispatcherImpl::regionHandleCallback,
url,
true); // teleport
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index f65baea6ca..b5709fa102 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -109,10 +109,13 @@ LLViewerCamera::LLViewerCamera() : LLCamera()
{
calcProjection(getFar());
mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
+ mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
mPixelMeterRatio = 0.f;
mScreenPixelArea = 0;
mZoomFactor = 1.f;
mZoomSubregion = 1;
+ mAverageSpeed = 0.f;
+ mAverageAngularSpeed = 0.f;
gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2));
}
@@ -151,15 +154,22 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
setOriginAndLookAt(origin, up_direction, point_of_interest);
- F32 dpos = (center - last_position).magVec();
+ mVelocityDir = center - last_position ;
+ F32 dpos = mVelocityDir.normVec() ;
LLQuaternion rotation;
rotation.shortestArc(last_axis, getAtAxis());
F32 x, y, z;
F32 drot;
rotation.getAngleAxis(&drot, &x, &y, &z);
+
mVelocityStat.addValue(dpos);
mAngularVelocityStat.addValue(drot);
+
+ mAverageSpeed = mVelocityStat.getMeanPerSec() ;
+ mAverageAngularSpeed = mAngularVelocityStat.getMeanPerSec() ;
+ mCosHalfCameraFOV = cosf(0.5f * getView() * llmax(1.0f, getAspect()));
+
// update pixel meter ratio using default fov, not modified one
mPixelMeterRatio = getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5));
// update screen pixel area
@@ -818,10 +828,12 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
LLCamera::setView(vertical_fov_rads); // call base implementation
}
-void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) {
+void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads)
+{
vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
setView(vertical_fov_rads);
mCameraFOVDefault = vertical_fov_rads;
+ mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
}
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index 90b77f771f..2b8a0892bf 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -91,17 +91,20 @@ public:
BOOL projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp = TRUE) const;
BOOL projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const;
-
+ const LLVector3* getVelocityDir() const {return &mVelocityDir;}
LLStat *getVelocityStat() { return &mVelocityStat; }
LLStat *getAngularVelocityStat() { return &mAngularVelocityStat; }
+ F32 getCosHalfFov() {return mCosHalfCameraFOV;}
+ F32 getAverageSpeed() {return mAverageSpeed ;}
+ F32 getAverageAngularSpeed() {return mAverageAngularSpeed;}
void getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right);
LLVector3 roundToPixel(const LLVector3 &pos_agent);
// Sets the current matrix
/* virtual */ void setView(F32 vertical_fov_rads);
- // Sets the current matrix AND remembers result as default view
- void setDefaultFOV(F32 vertical_fov_rads);
+
+ void setDefaultFOV(F32 fov) ;
F32 getDefaultFOV() { return mCameraFOVDefault; }
BOOL cameraUnderWater() const;
@@ -120,9 +123,14 @@ protected:
LLStat mVelocityStat;
LLStat mAngularVelocityStat;
+ LLVector3 mVelocityDir ;
+ F32 mAverageSpeed ;
+ F32 mAverageAngularSpeed ;
+
mutable LLMatrix4 mProjectionMatrix; // Cache of perspective matrix
mutable LLMatrix4 mModelviewMatrix;
F32 mCameraFOVDefault;
+ F32 mCosHalfCameraFOV;
LLVector3 mLastPointOfInterest;
F32 mPixelMeterRatio; // Divide by distance from camera to get pixels per meter at that distance.
S32 mScreenPixelArea; // Pixel area of entire window
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index b71291f834..6d3bf277bb 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -90,7 +90,7 @@ std::string gCurrentVersion;
extern BOOL gResizeScreenTexture;
extern BOOL gDebugGL;
-
+extern BOOL gAuditTexture;
////////////////////////////////////////////////////////////////////////////
// Listeners
@@ -378,6 +378,12 @@ static bool handleRenderUseImpostorsChanged(const LLSD& newvalue)
return true;
}
+static bool handleAuditTextureChanged(const LLSD& newvalue)
+{
+ gAuditTexture = newvalue.asBoolean();
+ return true;
+}
+
static bool handleRenderDebugGLChanged(const LLSD& newvalue)
{
gDebugGL = newvalue.asBoolean() || gDebugSession;
@@ -566,6 +572,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("RenderDeferredShadow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderDeferredGI")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2));
+ gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _2));
gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _2));
gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _2));
gSavedSettings.getControl("ConsoleMaxLines")->getSignal()->connect(boost::bind(&handleConsoleMaxLinesChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index a6a72e9666..e0bb8fedeb 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -712,7 +712,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
- const F32 max_image_decode_time = llmin(0.005f, 0.005f*10.f*gFrameIntervalSeconds); // 50 ms/second decode time (no more than 5ms/frame)
+ F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
+ max_image_decode_time = llclamp(max_image_decode_time, 0.001f, 0.005f ); // min 1ms/frame, max 5ms/frame)
gTextureList.updateImages(max_image_decode_time);
//remove dead textures from GL
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index e4643a15b5..3374720a68 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -606,6 +606,14 @@ class LLAdvancedToggleConsole : public view_listener_t
{
toggle_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
}
+ else if (gTextureSizeView && "texture size" == console_type)
+ {
+ toggle_visibility( (void*)gTextureSizeView );
+ }
+ else if (gTextureCategoryView && "texture category" == console_type)
+ {
+ toggle_visibility( (void*)gTextureCategoryView );
+ }
else if ("fast timers" == console_type)
{
toggle_visibility( (void*)gDebugView->mFastTimerView );
@@ -633,6 +641,14 @@ class LLAdvancedCheckConsole : public view_listener_t
{
new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
}
+ else if (gTextureSizeView && "texture size" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureSizeView );
+ }
+ else if (gTextureCategoryView && "texture category" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureCategoryView );
+ }
else if ("fast timers" == console_type)
{
new_value = get_visibility( (void*)gDebugView->mFastTimerView );
@@ -1157,28 +1173,6 @@ class LLAdvancedCheckWireframe : public view_listener_t
};
//////////////////////
-// DISABLE TEXTURES //
-//////////////////////
-
-class LLAdvancedToggleDisableTextures : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerTexture::sDontLoadVolumeTextures = !LLViewerTexture::sDontLoadVolumeTextures;
- return true;
- }
-};
-
-class LLAdvancedCheckDisableTextures : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLViewerTexture::sDontLoadVolumeTextures; // <-- make this using LLCacheControl
- return new_value;
- }
-};
-
-//////////////////////
// TEXTURE ATLAS //
//////////////////////
@@ -1909,7 +1903,7 @@ class LLAdvancedRebakeTextures : public view_listener_t
};
-#ifndef LL_RELEASE_FOR_DOWNLOAD
+#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD
///////////////////////////
// DEBUG AVATAR TEXTURES //
///////////////////////////
@@ -3511,9 +3505,8 @@ void set_god_level(U8 god_level)
gIMMgr->refresh();
LLViewerParcelMgr::getInstance()->notifyObservers();
- // God mode changes sim visibility
- LLWorldMap::getInstance()->reset();
- LLWorldMap::getInstance()->setCurrentLayer(0);
+ // God mode changes region visibility
+ LLWorldMap::getInstance()->reloadItems(true);
// inventory in items may change in god mode
gObjectList.dirtyAllObjectInventory();
@@ -7887,8 +7880,6 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
- view_listener_t::addMenu(new LLAdvancedToggleDisableTextures(), "Advanced.ToggleDisableTextures");
- view_listener_t::addMenu(new LLAdvancedCheckDisableTextures(), "Advanced.CheckDisableTextures");
view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 20cd516fa0..5de52367ef 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2906,7 +2906,7 @@ F32 LLViewerObject::getMidScale() const
}
-void LLViewerObject::updateTextures(LLAgent &agent)
+void LLViewerObject::updateTextures()
{
}
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index b8ae31118c..01b213a87d 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -199,7 +199,7 @@ public:
S32 getNumFaces() const { return mNumFaces; }
// Graphical stuff for objects - maybe broken out into render class later?
- virtual void updateTextures(LLAgent &agent);
+ virtual void updateTextures();
virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object
virtual LLDrawable* createDrawable(LLPipeline *pipeline);
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 2927ca5292..96828ee1b6 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -642,7 +642,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
// Update distance & gpw
objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area
- objectp->updateTextures(agent); // Update the image levels of textures for this object.
+ objectp->updateTextures(); // Update the image levels of textures for this object.
}
}
@@ -1074,6 +1074,7 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
LLColor4 group_own_below_water_color =
LLUIColorTable::instance().getColor( "NetMapGroupOwnBelowWater" );
+ F32 max_radius = gSavedSettings.getF32("MiniMapPrimMaxRadius");
for (S32 i = 0; i < mMapObjects.count(); i++)
{
@@ -1089,6 +1090,11 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
F32 approx_radius = (scale.mV[VX] + scale.mV[VY]) * 0.5f * 0.5f * 1.3f; // 1.3 is a fudge
+ // Limit the size of megaprims so they don't blot out everything on the minimap.
+ // Attempting to draw very large megaprims also causes client lag.
+ // See DEV-17370 and DEV-29869/SNOW-79 for details.
+ approx_radius = llmin(approx_radius, max_radius);
+
LLColor4U color = above_water_color;
if( objectp->permYouOwner() )
{
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 7ea55b49e8..d1c9840a97 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1427,11 +1427,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("EstateChangeInfo");
capabilityNames.append("EventQueueGet");
capabilityNames.append("FetchInventory");
- capabilityNames.append("WebFetchInventoryDescendents");
capabilityNames.append("ObjectMedia");
capabilityNames.append("ObjectMediaNavigate");
capabilityNames.append("FetchLib");
capabilityNames.append("FetchLibDescendents");
+ capabilityNames.append("GetTexture");
capabilityNames.append("GroupProposalBallot");
capabilityNames.append("HomeLocation");
capabilityNames.append("MapLayer");
@@ -1452,6 +1452,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("SendUserReportWithScreenshot");
capabilityNames.append("ServerReleaseNotes");
capabilityNames.append("StartGroupProposal");
+ capabilityNames.append("TextureStats");
capabilityNames.append("UntrustedSimulatorMessage");
capabilityNames.append("UpdateAgentInformation");
capabilityNames.append("UpdateAgentLanguage");
@@ -1464,6 +1465,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("UploadBakedTexture");
capabilityNames.append("ViewerStartAuction");
capabilityNames.append("ViewerStats");
+ capabilityNames.append("WebFetchInventoryDescendents");
// Please add new capabilities alphabetically to reduce
// merge conflicts.
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 6e07d8f246..caa94dba38 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -560,12 +560,18 @@ extern U32 gVisCompared;
extern U32 gVisTested;
std::map<S32,LLFrameTimer> gDebugTimers;
+std::map<S32,std::string> gDebugTimerLabel;
+
+void init_statistics()
+{
+ // Label debug timers
+ gDebugTimerLabel[0] = "Texture";
+}
void update_statistics(U32 frame_count)
{
gTotalWorldBytes += gVLManager.getTotalBytes();
gTotalObjectBytes += gObjectBits / 8;
- gTotalTextureBytes += gTextureList.mTextureBits / 8;
// make sure we have a valid time delta for this frame
if (gFrameIntervalSeconds > 0.f)
@@ -617,7 +623,6 @@ void update_statistics(U32 frame_count)
F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
LLViewerStats::getInstance()->mLayersKBitStat.addValue(layer_bits/1024.f);
LLViewerStats::getInstance()->mObjectKBitStat.addValue(gObjectBits/1024.f);
- LLViewerStats::getInstance()->mTextureKBitStat.addValue(gTextureList.mTextureBits/1024.f);
LLViewerStats::getInstance()->mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
LLViewerStats::getInstance()->mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
@@ -631,8 +636,6 @@ void update_statistics(U32 frame_count)
gDebugTimers[0].unpause();
}
- LLViewerStats::getInstance()->mTexturePacketsStat.addValue(gTextureList.mTexturePackets);
-
{
static F32 visible_avatar_frames = 0.f;
static F32 avg_visible_avatars = 0;
@@ -652,8 +655,20 @@ void update_statistics(U32 frame_count)
gObjectBits = 0;
// gDecodedBits = 0;
- gTextureList.mTextureBits = 0;
- gTextureList.mTexturePackets = 0;
+ // Only update texture stats ones per second so that they are less noisy
+ {
+ static const F32 texture_stats_freq = 1.f;
+ static LLFrameTimer texture_stats_timer;
+ if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
+ {
+ LLViewerStats::getInstance()->mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
+ LLViewerStats::getInstance()->mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
+ gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
+ LLViewerTextureList::sTextureBits = 0;
+ LLViewerTextureList::sTexturePackets = 0;
+ texture_stats_timer.reset();
+ }
+ }
}
@@ -826,3 +841,4 @@ void send_stats()
LLViewerStats::getInstance()->addToMessage(body);
LLHTTPClient::post(url, body, new ViewerStatsResponder());
}
+
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index ba89fbf02a..13d73000d2 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -34,6 +34,7 @@
#define LL_LLVIEWERSTATS_H
#include "llstat.h"
+#include "lltextureinfo.h"
class LLViewerStats : public LLSingleton<LLViewerStats>
{
@@ -205,10 +206,13 @@ private:
static const F32 SEND_STATS_PERIOD = 300.0f;
// The following are from (older?) statistics code found in appviewer.
+void init_statistics();
void reset_statistics();
void output_statistics(void*);
void update_statistics(U32 frame_count);
void send_stats();
extern std::map<S32,LLFrameTimer> gDebugTimers;
+extern std::map<S32,std::string> gDebugTimerLabel;
+
#endif // LL_LLVIEWERSTATS_H
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a0ab4cb1e6..b2ca9edfea 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -60,6 +60,8 @@
#include "llviewercontrol.h"
#include "pipeline.h"
#include "llappviewer.h"
+#include "llface.h"
+#include "llviewercamera.h"
#include "lltextureatlas.h"
#include "lltextureatlasmanager.h"
#include "lltextureentry.h"
@@ -88,7 +90,15 @@ S32 LLViewerTexture::sTotalTextureMemoryInBytes = 0;
S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0;
S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0;
S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ;
-BOOL LLViewerTexture::sDontLoadVolumeTextures = FALSE;
+S8 LLViewerTexture::sCameraMovingDiscardBias = 0 ;
+S32 LLViewerTexture::sMaxSculptRez = 128 ; //max sculpt image size
+const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64 ;
+const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez ;
+const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128 ;
+S32 LLViewerTexture::sMinLargeImageSize = 65536 ; //256 * 256.
+S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ;
+BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE ;
+F32 LLViewerTexture::sCurrentTime = 0.0f ;
BOOL LLViewerTexture::sUseTextureAtlas = FALSE ;
const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve image quality by
@@ -161,6 +171,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(BOOL usemipma
if(generate_gl_tex)
{
tex->generateGLTexture() ;
+ tex->setCategory(LLViewerTexture::LOCAL) ;
}
return tex ;
}
@@ -170,12 +181,14 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const LLUUID&
if(generate_gl_tex)
{
tex->generateGLTexture() ;
+ tex->setCategory(LLViewerTexture::LOCAL) ;
}
return tex ;
}
LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps)
{
LLPointer<LLViewerTexture> tex = new LLViewerTexture(raw, usemipmaps) ;
+ tex->setCategory(LLViewerTexture::LOCAL) ;
return tex ;
}
LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex)
@@ -184,6 +197,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 wid
if(generate_gl_tex)
{
tex->generateGLTexture() ;
+ tex->setCategory(LLViewerTexture::LOCAL) ;
}
return tex ;
}
@@ -212,6 +226,19 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile(
return gTextureList.getImageFromFile(filename, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id) ;
}
+//static
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url,
+ BOOL usemipmaps,
+ BOOL level_immediate, // Get the requested level immediately upon creation.
+ S8 texture_type,
+ LLGLint internal_format,
+ LLGLenum primary_format,
+ const LLUUID& force_id
+ )
+{
+ return gTextureList.getImageFromUrl(url, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id) ;
+}
+
LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host)
{
return gTextureList.getImageFromHost(image_id, host) ;
@@ -253,11 +280,12 @@ void LLViewerTextureManager::init()
}
imagep->createGLTexture(0, image_raw);
image_raw = NULL;
- LLViewerFetchedTexture::sDefaultImagep->dontDiscard();
#else
LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE);
#endif
-
+ LLViewerFetchedTexture::sDefaultImagep->dontDiscard();
+ LLViewerFetchedTexture::sDefaultImagep->setCategory(LLViewerTexture::OTHER) ;
+
LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, TRUE, TRUE);
LLViewerFetchedTexture::sSmokeImagep->setNoDelete() ;
@@ -281,6 +309,8 @@ void LLViewerTextureManager::cleanup()
LLViewerFetchedTexture::sWhiteImagep = NULL;
LLViewerMediaTexture::cleanup() ;
+
+ LLViewerTexture::cleanupClass() ;
}
//----------------------------------------------------------------------------------------------
@@ -291,6 +321,11 @@ void LLViewerTextureManager::cleanup()
void LLViewerTexture::initClass()
{
LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ;
+
+ if(gAuditTexture)
+ {
+ LLImageGL::setHighlightTexture(LLViewerTexture::OTHER) ;
+ }
}
// static
@@ -298,6 +333,25 @@ void LLViewerTexture::cleanupClass()
{
}
+// static
+S32 LLViewerTexture::getTotalNumOfCategories()
+{
+ return MAX_GL_IMAGE_CATEGORY - (BOOST_HIGH - BOOST_SCULPTED) + 2 ;
+}
+
+// static
+//index starts from zero.
+S32 LLViewerTexture::getIndexFromCategory(S32 category)
+{
+ return (category < BOOST_HIGH) ? category : category - (BOOST_HIGH - BOOST_SCULPTED) + 1 ;
+}
+
+//static
+S32 LLViewerTexture::getCategoryFromIndex(S32 index)
+{
+ return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ;
+}
+
// tuning params
const F32 discard_bias_delta = .05f;
const F32 discard_delta_time = 0.5f;
@@ -309,6 +363,8 @@ F32 texmem_middle_bound_scale = 0.925f;
//static
void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity)
{
+ sCurrentTime = gFrameTimeSeconds ;
+
if(LLViewerTextureManager::sTesterp)
{
LLViewerTextureManager::sTesterp->update() ;
@@ -349,6 +405,13 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
}
sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max);
LLViewerTexture::sUseTextureAtlas = gSavedSettings.getBOOL("EnableTextureAtlas") ;
+
+ F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
+ F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
+ sCameraMovingDiscardBias = (S8)llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1) ;
+
+ LLViewerTexture::sFreezeImageScalingDown = (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < 0.75f * sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) &&
+ (BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < 0.75f * sMaxTotalTextureMemInMegaBytes * texmem_middle_bound_scale) ;
}
//end of static functions
@@ -414,7 +477,9 @@ void LLViewerTexture::init(bool firstinit)
mTextureState = NO_DELETE ;
mDontDiscard = FALSE;
mMaxVirtualSize = 0.f;
+ mNeedsGLTexture = FALSE ;
mNeedsResetMaxVirtualSize = FALSE ;
+ mAdditionalDecodePriority = 0.f ;
}
//virtual
@@ -455,11 +520,15 @@ void LLViewerTexture::setBoostLevel(S32 level)
{
setNoDelete() ;
}
+ if(gAuditTexture)
+ {
+ setCategory(mBoostLevel);
+ }
}
}
-bool LLViewerTexture::bindDefaultImage(S32 stage) const
+bool LLViewerTexture::bindDefaultImage(S32 stage)
{
if (stage < 0) return false;
@@ -478,6 +547,10 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) const
llwarns << "LLViewerTexture::bindDefaultImage failed." << llendl;
}
stop_glerror();
+
+ //check if there is cached raw image and switch to it if possible
+ switchToCachedImage() ;
+
if(LLViewerTextureManager::sTesterp)
{
LLViewerTextureManager::sTesterp->updateGrayTextureBinding() ;
@@ -496,24 +569,32 @@ void LLViewerTexture::forceImmediateUpdate()
{
}
-void LLViewerTexture::addTextureStats(F32 virtual_size) const
+void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const
{
- if (virtual_size > mMaxVirtualSize)
+ if(needs_gltexture)
{
- mMaxVirtualSize = virtual_size;
+ mNeedsGLTexture = TRUE ;
}
-}
-void LLViewerTexture::resetTextureStats(BOOL zero)
-{
- if (zero)
+ if(mNeedsResetMaxVirtualSize)
{
- mMaxVirtualSize = 0.0f;
+ //flag to reset the values because the old values are used.
+ mNeedsResetMaxVirtualSize = FALSE ;
+ mMaxVirtualSize = virtual_size;
+ mAdditionalDecodePriority = 0.f ;
+ mNeedsGLTexture = needs_gltexture ;
}
- else
+ else if (virtual_size > mMaxVirtualSize)
{
- mMaxVirtualSize -= mMaxVirtualSize * .10f; // decay by 5%/update
- }
+ mMaxVirtualSize = virtual_size;
+ }
+}
+
+void LLViewerTexture::resetTextureStats()
+{
+ mMaxVirtualSize = 0.0f;
+ mAdditionalDecodePriority = 0.f ;
+ mNeedsResetMaxVirtualSize = FALSE ;
}
//virtual
@@ -534,6 +615,12 @@ void LLViewerTexture::removeFace(LLFace* facep)
mFaceList.remove(facep) ;
}
+//virtual
+void LLViewerTexture::switchToCachedImage()
+{
+ //nothing here.
+}
+
void LLViewerTexture::forceActive()
{
mTextureState = ACTIVE ;
@@ -578,11 +665,11 @@ BOOL LLViewerTexture::createGLTexture()
return mGLTexturep->createGLTexture() ;
}
-BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename)
+BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category)
{
llassert_always(mGLTexturep.notNull()) ;
- BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename) ;
+ BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ;
if(ret)
{
@@ -694,6 +781,13 @@ void LLViewerTexture::setGLTextureCreated (bool initialized)
mGLTexturep->setGLTextureCreated (initialized) ;
}
+void LLViewerTexture::setCategory(S32 category)
+{
+ llassert_always(mGLTexturep.notNull()) ;
+
+ mGLTexturep->setCategory(category) ;
+}
+
LLTexUnit::eTextureAddressMode LLViewerTexture::getAddressMode(void) const
{
llassert_always(mGLTexturep.notNull()) ;
@@ -742,18 +836,18 @@ BOOL LLViewerTexture::getMissed() const
return mGLTexturep->getMissed() ;
}
-BOOL LLViewerTexture::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents)
+BOOL LLViewerTexture::isJustBound() const
{
llassert_always(mGLTexturep.notNull()) ;
- return mGLTexturep->isValidForSculpt(discard_level, image_width, image_height, ncomponents) ;
+ return mGLTexturep->isJustBound() ;
}
-BOOL LLViewerTexture::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
+void LLViewerTexture::forceUpdateBindStats(void) const
{
llassert_always(mGLTexturep.notNull()) ;
- return mGLTexturep->readBackRaw(discard_level, imageraw, compressed_ok) ;
+ return mGLTexturep->forceUpdateBindStats() ;
}
U32 LLViewerTexture::getTexelsInAtlas() const
@@ -793,6 +887,11 @@ void LLViewerTexture::destroyGLTexture()
}
}
+BOOL LLViewerTexture::isLargeImage()
+{
+ return mFullWidth * mFullHeight > LLViewerTexture::sMinLargeImageSize ;
+}
+
//virtual
void LLViewerTexture::updateBindStatsForTester()
{
@@ -813,11 +912,12 @@ void LLViewerTexture::updateBindStatsForTester()
//static
F32 LLViewerFetchedTexture::maxDecodePriority()
{
- return 2000000.f;
+ return 6000000.f;
}
-LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, BOOL usemipmaps)
- : LLViewerTexture(id, usemipmaps)
+LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, const LLHost& host, BOOL usemipmaps)
+ : LLViewerTexture(id, usemipmaps),
+ mTargetHost(host)
{
init(TRUE) ;
generateGLTexture() ;
@@ -829,9 +929,9 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemi
init(TRUE) ;
}
-LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps)
+LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps)
: LLViewerTexture(id, usemipmaps),
- mLocalFileName(full_path)
+ mUrl(url)
{
init(TRUE) ;
generateGLTexture() ;
@@ -879,6 +979,16 @@ void LLViewerFetchedTexture::init(bool firstinit)
mVisibleFrame = 0;
mForSculpt = FALSE ;
mIsFetched = FALSE ;
+
+ mCachedRawImage = NULL ;
+ mCachedRawDiscardLevel = -1 ;
+ mCachedRawImageReady = FALSE ;
+
+ mSavedRawImage = NULL ;
+ mForceToSaveRawImage = FALSE ;
+ mSavedRawDiscardLevel = -1 ;
+ mDesiredSavedRawDiscardLevel = -1 ;
+ mLastReferencedSavedRawImageTime = 0.0f ;
}
LLViewerFetchedTexture::~LLViewerFetchedTexture()
@@ -915,11 +1025,25 @@ void LLViewerFetchedTexture::cleanup()
// Clean up image data
destroyRawImage();
+ mCachedRawImage = NULL ;
+ mCachedRawDiscardLevel = -1 ;
+ mCachedRawImageReady = FALSE ;
+ mSavedRawImage = NULL ;
}
void LLViewerFetchedTexture::setForSculpt()
{
mForSculpt = TRUE ;
+ if(isForSculptOnly() && !getBoundRecently())
+ {
+ destroyGLTexture() ; //sculpt image does not need gl texture.
+ }
+ checkCachedRawSculptImage() ;
+}
+
+BOOL LLViewerFetchedTexture::isForSculptOnly() const
+{
+ return mForSculpt && !mNeedsGLTexture ;
}
BOOL LLViewerFetchedTexture::isDeleted()
@@ -954,17 +1078,37 @@ void LLViewerFetchedTexture::setInactive()
}
}
+BOOL LLViewerFetchedTexture::isFullyLoaded() const
+{
+ // Unfortunately, the boolean "mFullyLoaded" is never updated correctly so we use that logic
+ // to check if the texture is there and completely downloaded
+ return (mFullWidth != 0) && (mFullHeight != 0) && !mIsFetching && !mHasFetcher;
+}
+
+
// virtual
void LLViewerFetchedTexture::dump()
{
LLViewerTexture::dump();
- llinfos << "LLViewerFetchedTexture"
- << " mIsMissingAsset " << (S32)mIsMissingAsset
- << " mFullWidth " << mFullWidth
- << " mFullHeight " << mFullHeight
- << " mOrigWidth" << mOrigWidth
- << " mOrigHeight" << mOrigHeight
+ llinfos << "Dump : " << mID
+ << ", mIsMissingAsset = " << (S32)mIsMissingAsset
+ << ", mFullWidth = " << (S32)mFullWidth
+ << ", mFullHeight = " << (S32)mFullHeight
+ << ", mOrigWidth = " << (S32)mOrigWidth
+ << ", mOrigHeight = " << (S32)mOrigHeight
+ << llendl;
+ llinfos << " : "
+ << " mFullyLoaded = " << (S32)mFullyLoaded
+ << ", mFetchState = " << (S32)mFetchState
+ << ", mFetchPriority = " << (S32)mFetchPriority
+ << ", mDownloadProgress = " << (F32)mDownloadProgress
+ << llendl;
+ llinfos << " : "
+ << " mHasFetcher = " << (S32)mHasFetcher
+ << ", mIsFetching = " << (S32)mIsFetching
+ << ", mIsFetched = " << (S32)mIsFetched
+ << ", mBoostLevel = " << (S32)mBoostLevel
<< llendl;
}
@@ -985,6 +1129,75 @@ void LLViewerFetchedTexture::destroyTexture()
mFullyLoaded = FALSE ;
}
+//
+//do not change the discard level of the loaded texture image.
+BOOL LLViewerFetchedTexture::keepReuestedDiscardLevel()
+{
+ if (!mLoadedCallbackList.empty())
+ {
+ return TRUE ;
+ }
+
+ return FALSE ;
+}
+
+void LLViewerFetchedTexture::addToCreateTexture()
+{
+ if(isForSculptOnly())
+ {
+ //just update some variables, not to create a real GL texture.
+ createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE) ;
+ mNeedsCreateTexture = FALSE ;
+ destroyRawImage();
+ }
+ else
+ {
+#if 1
+ //
+ //if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
+ //so do not scale down the over qualified image.
+ //Note: scaling down image is expensensive. Do it only when very necessary.
+ //
+ if(mRequestedDiscardLevel <= mDesiredDiscardLevel && !keepReuestedDiscardLevel())
+ {
+ S32 w = mFullWidth >> mRawDiscardLevel;
+ S32 h = mFullHeight >> mRawDiscardLevel;
+
+ //if big image, do not load extra data
+ //scale it down to size >= LLViewerTexture::sMinLargeImageSize
+ if(w * h > LLViewerTexture::sMinLargeImageSize)
+ {
+ S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel ;
+
+ if(d_level > 0)
+ {
+ S32 i = 0 ;
+ while((d_level > 0) && ((w >> i) * (h >> i) > LLViewerTexture::sMinLargeImageSize))
+ {
+ i++;
+ d_level--;
+ }
+ if(i > 0)
+ {
+ mRawDiscardLevel += i ;
+ if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)
+ {
+ mNeedsCreateTexture = FALSE ;
+ destroyRawImage();
+ return ;
+ }
+ mRawImage->scale(w >> i, h >> i) ;
+ }
+ }
+ }
+ }
+#endif
+ mNeedsCreateTexture = TRUE;
+ gTextureList.mCreateTextureList.insert(this);
+ }
+ return ;
+}
+
// ONLY called from LLViewerTextureList
BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
{
@@ -1006,7 +1219,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
if (!gNoRender)
{
// store original size only for locally-sourced images
- if (!mLocalFileName.empty())
+ if (mUrl.compare(0, 7, "file://") == 0)
{
mOrigWidth = mRawImage->getWidth();
mOrigHeight = mRawImage->getHeight();
@@ -1052,7 +1265,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
if(!(res = insertToAtlas()))
{
- res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename);
+ res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
resetFaceAtlas() ;
}
setActive() ;
@@ -1099,7 +1312,15 @@ void LLViewerFetchedTexture::processTextureStats()
return ;
}
- if(!mFullWidth || !mFullHeight)
+ updateVirtualSize() ;
+
+ static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
+
+ if (textures_fullres)
+ {
+ mDesiredDiscardLevel = 0;
+ }
+ else if(!mFullWidth || !mFullHeight)
{
mDesiredDiscardLevel = getMaxDiscardLevel() ;
}
@@ -1148,8 +1369,11 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
{
return mDecodePriority; // no change while waiting to create
}
-
- F32 priority;
+ if(mForceToSaveRawImage)
+ {
+ return maxDecodePriority() ;
+ }
+
S32 cur_discard = getDiscardLevel();
bool have_all_data = (cur_discard >= 0 && (cur_discard <= mDesiredDiscardLevel));
F32 pixel_priority = fsqrtf(mMaxVirtualSize);
@@ -1159,11 +1383,24 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
{
mVisibleFrame = mDecodeFrame;
}
-
+
+ F32 priority;
if (mIsMissingAsset)
{
priority = 0.0f;
}
+ else if(mDesiredDiscardLevel >= cur_discard && cur_discard > -1)
+ {
+ priority = -1.0f ;
+ }
+ else if (!isJustBound() && mCachedRawImageReady && !mBoostLevel)
+ {
+ priority = -1.0f;
+ }
+ else if(mCachedRawDiscardLevel > -1 && mDesiredDiscardLevel >= mCachedRawDiscardLevel)
+ {
+ priority = -1.0f;
+ }
else if (mDesiredDiscardLevel > getMaxDiscardLevel())
{
// Don't decode anything we don't need
@@ -1213,7 +1450,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
{
ddiscard+=2;
}
- else if (mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == 0)
+ else if (ddiscard > 2 && mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == 0)
{
ddiscard-=2;
}
@@ -1222,7 +1459,10 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
}
if (priority > 0.0f)
{
- pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f); // priority range = 100000-900000
+ // priority range = 100000-900000
+ pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f);
+
+ // priority range = [100000.f, 2000000.f]
if ( mBoostLevel > BOOST_HIGH)
{
priority = 1000000.f + pixel_priority + 1000.f * mBoostLevel;
@@ -1231,6 +1471,12 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
{
priority += 0.f + pixel_priority + 1000.f * mBoostLevel;
}
+
+ // priority range = [2100000.f, 5000000.f] if mAdditionalDecodePriority > 1.0
+ if(mAdditionalDecodePriority > 1.0f)
+ {
+ priority += 2000000.f + mAdditionalDecodePriority ;
+ }
}
return priority;
}
@@ -1242,6 +1488,40 @@ void LLViewerFetchedTexture::setDecodePriority(F32 priority)
mDecodePriority = priority;
}
+F32 LLViewerFetchedTexture::maxAdditionalDecodePriority()
+{
+ return 2000000.f;
+}
+void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
+{
+ priority *= maxAdditionalDecodePriority();
+ if(mAdditionalDecodePriority < priority)
+ {
+ mAdditionalDecodePriority = priority;
+ }
+}
+
+void LLViewerFetchedTexture::updateVirtualSize()
+{
+ if(mNeedsResetMaxVirtualSize)
+ {
+ addTextureStats(0.f, FALSE) ;//reset
+ }
+ if(mFaceList.size() > 0)
+ {
+ for(std::list<LLFace*>::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter)
+ {
+ LLFace* facep = *iter ;
+ if(facep->getDrawable()->isRecentlyVisible())
+ {
+ addTextureStats(facep->getVirtualSize()) ;
+ setAdditionalDecodePriority(facep->getImportanceToCamera()) ;
+ }
+ }
+ }
+ mNeedsResetMaxVirtualSize = TRUE ;
+}
+
bool LLViewerFetchedTexture::updateFetch()
{
mFetchState = 0;
@@ -1281,6 +1561,15 @@ bool LLViewerFetchedTexture::updateFetch()
{
// Sets mRawDiscardLevel, mRawImage, mAuxRawImage
S32 fetch_discard = current_discard;
+
+ if(mForceToSaveRawImage)
+ {
+ if(fetch_discard >= 0)
+ {
+ fetch_discard = llmax(fetch_discard, mSavedRawDiscardLevel) ;
+ }
+ }
+
if (mRawImage.notNull()) sRawCount--;
if (mAuxRawImage.notNull()) sAuxCount--;
bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
@@ -1320,11 +1609,24 @@ bool LLViewerFetchedTexture::updateFetch()
(*iter)->dirtyTexture() ;
}
}
- mIsRawImageValid = TRUE;
- gTextureList.mCreateTextureList.insert(this);
- mNeedsCreateTexture = TRUE;
mFullWidth = mRawImage->getWidth() << mRawDiscardLevel;
mFullHeight = mRawImage->getHeight() << mRawDiscardLevel;
+
+ if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE)
+ {
+ //discard all oversized textures.
+ destroyRawImage();
+ setIsMissingAsset();
+ mRawDiscardLevel = INVALID_DISCARD_LEVEL ;
+ mIsFetching = FALSE ;
+ }
+ else
+ {
+ mIsRawImageValid = TRUE;
+ addToCreateTexture() ;
+ }
+
+ return TRUE ;
}
else
{
@@ -1347,13 +1649,13 @@ bool LLViewerFetchedTexture::updateFetch()
}
else
{
- llwarns << mID << ": Setting min discard to " << current_discard << llendl;
+ //llwarns << mID << ": Setting min discard to " << current_discard << llendl;
mMinDiscardLevel = current_discard;
desired_discard = current_discard;
}
destroyRawImage();
}
- else if (mRawImage.isNull())
+ else if (mRawImage.notNull())
{
// We have data, but our fetch failed to return raw data
// *TODO: FIgure out why this is happening and fix it
@@ -1362,12 +1664,29 @@ bool LLViewerFetchedTexture::updateFetch()
}
else
{
+// // Useful debugging code for undesired deprioritization of textures.
+// if (decode_priority <= 0.0f && desired_discard >= 0 && desired_discard < current_discard)
+// {
+// llinfos << "Calling updateRequestPriority() with decode_priority = 0.0f" << llendl;
+// calcDecodePriority();
+// }
LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority);
}
}
- bool make_request = true;
-
+ if (!mDontDiscard)
+ {
+ if (mBoostLevel == 0)
+ {
+ desired_discard = llmax(desired_discard, current_discard-1);
+ }
+ else
+ {
+ desired_discard = llmax(desired_discard, current_discard-2);
+ }
+ }
+
+ bool make_request = true;
if (decode_priority <= 0)
{
make_request = false;
@@ -1380,6 +1699,10 @@ bool LLViewerFetchedTexture::updateFetch()
{
make_request = false;
}
+ else if (!isJustBound() && mCachedRawImageReady)
+ {
+ make_request = false;
+ }
else
{
if (mIsFetching)
@@ -1407,33 +1730,12 @@ bool LLViewerFetchedTexture::updateFetch()
h = mGLTexturep->getHeight(0);
c = mComponents;
}
- if (!mDontDiscard)
- {
- if (mBoostLevel == 0)
- {
- desired_discard = llmax(desired_discard, current_discard-1);
- }
- else
- {
- desired_discard = llmax(desired_discard, current_discard-2);
- }
- }
-
+
// bypass texturefetch directly by pulling from LLTextureCache
bool fetch_request_created = false;
- if (mLocalFileName.empty())
- {
- fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(getID(), getTargetHost(), decode_priority,
- w, h, c, desired_discard,
- needsAux());
- }
- else
- {
- fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mLocalFileName, getID(),getTargetHost(), decode_priority,
- w, h, c, desired_discard,
- needsAux());
- }
-
+ fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), decode_priority,
+ w, h, c, desired_discard, needsAux());
+
if (fetch_request_created)
{
mHasFetcher = TRUE;
@@ -1463,9 +1765,82 @@ bool LLViewerFetchedTexture::updateFetch()
return mIsFetching ? true : false;
}
+//
+//force to fetch a new raw image for this texture
+//
+BOOL LLViewerFetchedTexture::forceFetch()
+{
+ if(!mForceToSaveRawImage)
+ {
+ return false ;
+ }
+ if(mDesiredSavedRawDiscardLevel < getDiscardLevel())
+ {
+ //no need to force fetching. normal fetching flow will do the work.
+ //return false ;
+ }
+ if (mNeedsCreateTexture)
+ {
+ // We may be fetching still (e.g. waiting on write)
+ // but don't check until we've processed the raw data we have
+ //return false;
+ }
+ if(mIsFetching)
+ {
+ return false ;
+ }
+ if (mIsMissingAsset)
+ {
+ mForceToSaveRawImage = false ;
+ llassert_always(!mHasFetcher);
+ return false; // skip
+ }
+ if (!mLoadedCallbackList.empty() && mRawImage.notNull())
+ {
+ return false; // process any raw image data in callbacks before replacing
+ }
+ if(mRawImage.notNull() && mRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
+ {
+ return false ; // mRawImage is enough
+ }
+
+ S32 desired_discard = mDesiredSavedRawDiscardLevel ;
+ S32 current_discard = getDiscardLevel();
+
+ bool fetch_request_created = false;
+ S32 w=0, h=0, c=0;
+ if (current_discard >= 0)
+ {
+ w = getWidth(0);
+ h = getHeight(0);
+ c = getComponents();
+ }
+ fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), maxDecodePriority(),
+ w, h, c, desired_discard, needsAux());
+
+ if (fetch_request_created)
+ {
+ mHasFetcher = TRUE;
+ mIsFetching = TRUE;
+ mRequestedDiscardLevel = desired_discard ;
+
+ mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
+ mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
+ }
+
+ return mIsFetching ? true : false;
+}
+
void LLViewerFetchedTexture::setIsMissingAsset()
{
- llwarns << mLocalFileName << " " << mID << ": Marking image as missing" << llendl;
+ if (mUrl.empty())
+ {
+ llwarns << mID << ": Marking image as missing" << llendl;
+ }
+ else
+ {
+ llwarns << mUrl << ": Marking image as missing" << llendl;
+ }
if (mHasFetcher)
{
LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
@@ -1487,7 +1862,13 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
{
// Put in list to call this->doLoadedCallbacks() periodically
gTextureList.mCallbackList.insert(this);
+ mLoadedCallbackDesiredDiscardLevel = (S8)discard_level;
}
+ else
+ {
+ mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level) ;
+ }
+
LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata);
mLoadedCallbackList.push_back(entryp);
mNeedsAux |= needs_aux;
@@ -1616,7 +1997,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
// We have GL data.
destroyRawImage();
- readBackRawImage(gl_discard);
+ reloadRawImage(mLoadedCallbackDesiredDiscardLevel);
llassert_always(mRawImage.notNull());
llassert_always(!mNeedsAux || mAuxRawImage.notNull());
}
@@ -1725,8 +2106,7 @@ void LLViewerFetchedTexture::forceImmediateUpdate()
return ;
}
-// Was in LLImageGL
-LLImageRaw* LLViewerFetchedTexture::readBackRawImage(S8 discard_level)
+LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level)
{
llassert_always(mGLTexturep.notNull()) ;
llassert_always(discard_level >= 0);
@@ -1736,25 +2116,216 @@ LLImageRaw* LLViewerFetchedTexture::readBackRawImage(S8 discard_level)
llerrs << "called with existing mRawImage" << llendl;
mRawImage = NULL;
}
- mRawImage = new LLImageRaw(mGLTexturep->getWidth(discard_level), mGLTexturep->getHeight(discard_level), mComponents);
- sRawCount++;
- mRawDiscardLevel = discard_level;
- mGLTexturep->readBackRaw(mRawDiscardLevel, mRawImage, false);
- mIsRawImageValid = TRUE;
+
+ if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level)
+ {
+ mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ;
+ mRawImage->copy(getSavedRawImage()) ;
+ mRawDiscardLevel = discard_level ;
+ }
+ else
+ {
+ //force to fetch raw image again if cached raw image is not good enough.
+ if(mCachedRawDiscardLevel > discard_level)
+ {
+ mRawImage = mCachedRawImage ;
+ mRawDiscardLevel = mCachedRawDiscardLevel;
+
+ forceToSaveRawImage(discard_level) ;
+ }
+ else //cached raw image is good enough, copy it.
+ {
+ mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ;
+ mRawImage->copy(mCachedRawImage) ;
+ mRawDiscardLevel = discard_level ;
+ }
+ }
+ mIsRawImageValid = TRUE ;
+ sRawCount++;
return mRawImage;
}
void LLViewerFetchedTexture::destroyRawImage()
-{
- if (mRawImage.notNull()) sRawCount--;
+{
if (mAuxRawImage.notNull()) sAuxCount--;
+
+ if (mRawImage.notNull())
+ {
+ sRawCount--;
+ setCachedRawImage() ;
+
+ if(mForceToSaveRawImage)
+ {
+ saveRawImage() ;
+ }
+ }
+
mRawImage = NULL;
mAuxRawImage = NULL;
mIsRawImageValid = FALSE;
mRawDiscardLevel = INVALID_DISCARD_LEVEL;
+
+ if(mForceToSaveRawImage)
+ {
+ forceFetch() ;
+ }
+}
+
+//use the mCachedRawImage to (re)generate the gl texture.
+//virtual
+void LLViewerFetchedTexture::switchToCachedImage()
+{
+ if(mCachedRawImage.notNull())
+ {
+ mRawImage = mCachedRawImage ;
+
+ if (getComponents() != mRawImage->getComponents())
+ {
+ // We've changed the number of components, so we need to move any
+ // objects using this pool to a different pool.
+ mComponents = mRawImage->getComponents();
+ mGLTexturep->setComponents(mComponents) ;
+ gTextureList.dirtyImage(this);
+ }
+
+ mIsRawImageValid = TRUE;
+ mRawDiscardLevel = mCachedRawDiscardLevel ;
+ gTextureList.mCreateTextureList.insert(this);
+ mNeedsCreateTexture = TRUE;
+ }
}
+void LLViewerFetchedTexture::setCachedRawImage()
+{
+ if(mRawImage == mCachedRawImage)
+ {
+ return ;
+ }
+ if(!mIsRawImageValid)
+ {
+ return ;
+ }
+
+ if(mCachedRawImageReady)
+ {
+ return ;
+ }
+
+ if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel)
+ {
+ S32 i = 0 ;
+ S32 w = mRawImage->getWidth() ;
+ S32 h = mRawImage->getHeight() ;
+
+ S32 max_size = MAX_CACHED_RAW_IMAGE_AREA ;
+ if(LLViewerTexture::BOOST_TERRAIN == mBoostLevel)
+ {
+ max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA ;
+ }
+ if(mForSculpt)
+ {
+ max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA ;
+ mCachedRawImageReady = !mRawDiscardLevel ;
+ }
+ else
+ {
+ mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)) ;
+ }
+
+ while(((w >> i) * (h >> i)) > max_size)
+ {
+ ++i ;
+ }
+
+ if(i)
+ {
+ if(!(w >> i) || !(h >> i))
+ {
+ --i ;
+ }
+ //if(mForSculpt)
+ //{
+ // mRawImage->scaleDownWithoutBlending(w >> i, h >> i) ;
+ //}
+ //else
+ {
+ mRawImage->scale(w >> i, h >> i) ;
+ }
+ }
+ mCachedRawImage = mRawImage ;
+ mCachedRawDiscardLevel = mRawDiscardLevel + i ;
+ }
+}
+
+void LLViewerFetchedTexture::checkCachedRawSculptImage()
+{
+ if(mCachedRawImageReady && mCachedRawDiscardLevel > 0)
+ {
+ if(getDiscardLevel() != 0)
+ {
+ mCachedRawImageReady = FALSE ;
+ }
+ else if(isForSculptOnly())
+ {
+ resetTextureStats() ; //do not update this image any more.
+ }
+ }
+}
+
+void LLViewerFetchedTexture::saveRawImage()
+{
+ if(mRawImage.isNull() || mSavedRawDiscardLevel == mRawDiscardLevel)
+ {
+ return ;
+ }
+
+ mSavedRawDiscardLevel = mRawDiscardLevel ;
+ mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()) ;
+
+ if(mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
+ {
+ mForceToSaveRawImage = FALSE ;
+ }
+
+ mLastReferencedSavedRawImageTime = sCurrentTime ;
+}
+
+void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard)
+{
+ if(!mForceToSaveRawImage && (mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard))
+ {
+ mForceToSaveRawImage = TRUE ;
+ mDesiredSavedRawDiscardLevel = desired_discard ;
+
+ forceFetch() ;
+ }
+}
+void LLViewerFetchedTexture::destroySavedRawImage()
+{
+ mSavedRawImage = NULL ;
+ mForceToSaveRawImage = FALSE ;
+ mSavedRawDiscardLevel = -1 ;
+ mDesiredSavedRawDiscardLevel = -1 ;
+ mLastReferencedSavedRawImageTime = 0.0f ;
+}
+
+LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()
+{
+ mLastReferencedSavedRawImageTime = sCurrentTime ;
+
+ return mSavedRawImage ;
+}
+
+BOOL LLViewerFetchedTexture::hasSavedRawImage() const
+{
+ return mSavedRawImage.notNull() ;
+}
+
+F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const
+{
+ return mLastReferencedSavedRawImageTime - sCurrentTime ;
+}
//----------------------------------------------------------------------------------------------
//atlasing
//----------------------------------------------------------------------------------------------
@@ -1952,14 +2523,14 @@ BOOL LLViewerFetchedTexture::insertToAtlas()
//----------------------------------------------------------------------------------------------
//start of LLViewerLODTexture
//----------------------------------------------------------------------------------------------
-LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, BOOL usemipmaps)
- : LLViewerFetchedTexture(id, usemipmaps)
+LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, const LLHost& host, BOOL usemipmaps)
+ : LLViewerFetchedTexture(id, host, usemipmaps)
{
init(TRUE) ;
}
-LLViewerLODTexture::LLViewerLODTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps)
- : LLViewerFetchedTexture(full_path, id, usemipmaps)
+LLViewerLODTexture::LLViewerLODTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps)
+ : LLViewerFetchedTexture(url, id, usemipmaps)
{
init(TRUE) ;
}
@@ -1977,12 +2548,25 @@ S8 LLViewerLODTexture::getType() const
return LLViewerTexture::LOD_TEXTURE ;
}
+BOOL LLViewerLODTexture::isUpdateFrozen()
+{
+ return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel() ;
+}
+
// This is gauranteed to get called periodically for every texture
//virtual
void LLViewerLODTexture::processTextureStats()
{
+ updateVirtualSize() ;
+
+ static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
+
+ if (textures_fullres)
+ {
+ mDesiredDiscardLevel = 0;
+ }
// Generate the request priority and render priority
- if (mDontDiscard || !mUseMipMaps)
+ else if (mDontDiscard || !mUseMipMaps)
{
mDesiredDiscardLevel = 0;
if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
@@ -2011,13 +2595,7 @@ void LLViewerLODTexture::processTextureStats()
// If we know the output width and height, we can force the discard
// level to the correct value, and thus not decode more texture
// data than we need to.
- /*if (mBoostLevel == LLViewerTexture::BOOST_UI ||
- mBoostLevel == LLViewerTexture::BOOST_PREVIEW ||
- mBoostLevel == LLViewerTexture::BOOST_AVATAR_SELF) // what about AVATAR_BAKED_SELF?
- {
- discard_level = 0; // full res
- }
- else*/ if (mKnownDrawWidth && mKnownDrawHeight)
+ if (mKnownDrawWidth && mKnownDrawHeight)
{
S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight;
@@ -2028,6 +2606,12 @@ void LLViewerLODTexture::processTextureStats()
}
else
{
+ if(isLargeImage() && !isJustBound() && mAdditionalDecodePriority < 1.0f)
+ {
+ //if is a big image and not being used recently, nor close to the view point, do not load hi-res data.
+ mMaxVirtualSize = llmin(mMaxVirtualSize, (F32)LLViewerTexture::sMinLargeImageSize) ;
+ }
+
if ((mCalculatedDiscardLevel >= 0.f) &&
(llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f))
{
@@ -2044,13 +2628,11 @@ void LLViewerLODTexture::processTextureStats()
}
if (mBoostLevel < LLViewerTexture::BOOST_HIGH)
{
- static const F32 discard_bias = -.5f; // Must be < 1 or highest discard will never load!
- discard_level += discard_bias;
discard_level += sDesiredDiscardBias;
discard_level *= sDesiredDiscardScale; // scale
+ discard_level += sCameraMovingDiscardBias ;
}
discard_level = floorf(discard_level);
-// discard_level -= (gTextureList.mVideoMemorySetting>>1); // more video ram = higher detail
F32 min_discard = 0.f;
if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
@@ -2069,46 +2651,39 @@ void LLViewerLODTexture::processTextureStats()
// proper action if we don't.
//
- BOOL increase_discard = FALSE;
S32 current_discard = getDiscardLevel();
if ((sDesiredDiscardBias > 0.0f) &&
(current_discard >= 0 && mDesiredDiscardLevel >= current_discard))
{
- if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale)
+ // Limit the amount of GL memory bound each frame
+ if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale &&
+ (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
{
- // Limit the amount of GL memory bound each frame
- if (mDesiredDiscardLevel > current_discard)
- {
- increase_discard = TRUE;
- }
- }
- if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale)
- {
- // Only allow GL to have 2x the video card memory
- if (!mGLTexturep->getBoundRecently())
- {
- increase_discard = TRUE;
- }
+ scaleDown() ;
}
- if (increase_discard)
+ // Only allow GL to have 2x the video card memory
+ else if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale &&
+ (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
{
- // llinfos << "DISCARDED: " << mID << " Discard: " << current_discard << llendl;
- sBoundTextureMemoryInBytes -= mGLTexturep->mTextureMemory;
- sTotalTextureMemoryInBytes -= mGLTexturep->mTextureMemory;
- // Increase the discard level (reduce the texture res)
- S32 new_discard = current_discard+1;
- mGLTexturep->setDiscardLevel(new_discard);
- sBoundTextureMemoryInBytes += mGLTexturep->mTextureMemory;
- sTotalTextureMemoryInBytes += mGLTexturep->mTextureMemory;
- if(LLViewerTextureManager::sTesterp)
- {
- LLViewerTextureManager::sTesterp->setStablizingTime() ;
- }
+ scaleDown() ;
+
}
}
}
}
+void LLViewerLODTexture::scaleDown()
+{
+ if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())
+ {
+ switchToCachedImage() ;
+
+ if(LLViewerTextureManager::sTesterp)
+ {
+ LLViewerTextureManager::sTesterp->setStablizingTime() ;
+ }
+ }
+}
//----------------------------------------------------------------------------------------------
//end of LLViewerLODTexture
//----------------------------------------------------------------------------------------------
@@ -2189,6 +2764,8 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL
mIsPlaying = FALSE ;
setMediaImpl() ;
+
+ setCategory(LLViewerTexture::MEDIA) ;
}
//virtual
@@ -2723,7 +3300,7 @@ void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTex
mTotalBytesLoadedForLargeImage += data_size ;
}
- if(imagep->isForSculpt())
+ if(imagep->forSculpt())
{
mTotalBytesLoadedForSculpties += data_size ;
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 596bfea670..6620e9fca3 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -121,11 +121,23 @@ public:
BOOST_UI = 15,
BOOST_PREVIEW = 16,
BOOST_MAP = 17,
- BOOST_MAP_LAYER = 18,
+ BOOST_MAP_VISIBLE = 18,
BOOST_AVATAR_SELF = 19, // needed for baking avatar
- BOOST_MAX_LEVEL
+ BOOST_MAX_LEVEL,
+
+ //other texture Categories
+ LOCAL = BOOST_MAX_LEVEL,
+ AVATAR_SCRATCH_TEX,
+ DYNAMIC_TEX,
+ MEDIA,
+ ATLAS,
+ OTHER,
+ MAX_GL_IMAGE_CATEGORY
};
-
+ static S32 getTotalNumOfCategories() ;
+ static S32 getIndexFromCategory(S32 category) ;
+ static S32 getCategoryFromIndex(S32 index) ;
+
typedef std::list<LLFace*> ll_face_list_t ;
protected:
@@ -146,7 +158,7 @@ public:
virtual BOOL isMissingAsset()const ;
virtual void dump(); // debug info to llinfos
- /*virtual*/ bool bindDefaultImage(const S32 stage = 0) const ;
+ /*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
/*virtual*/ void forceImmediateUpdate() ;
const LLUUID& getID() const { return mID; }
@@ -154,9 +166,9 @@ public:
void setBoostLevel(S32 level);
S32 getBoostLevel() { return mBoostLevel; }
- //maxVirtualSize of the texture
- void addTextureStats(F32 virtual_size) const ;
- void resetTextureStats(BOOL zero = FALSE);
+ void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
+ void resetTextureStats();
+
virtual F32 getMaxVirtualSize() ;
LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
@@ -180,7 +192,7 @@ public:
BOOL hasGLTexture() const ;
LLGLuint getTexName() const ;
BOOL createGLTexture() ;
- BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
+ BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLViewerTexture::OTHER);
void setFilteringOption(LLTexUnit::eTextureFilterOptions option);
void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
@@ -188,7 +200,8 @@ public:
BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height);
BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height);
void setGLTextureCreated (bool initialized);
-
+ void setCategory(S32 category) ;
+
LLTexUnit::eTextureAddressMode getAddressMode(void) const ;
S32 getMaxDiscardLevel() const;
S32 getDiscardLevel() const;
@@ -201,8 +214,8 @@ public:
BOOL getMask(const LLVector2 &tc);
F32 getTimePassedSinceLastBound();
BOOL getMissed() const ;
- BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ;
- BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
+ BOOL isJustBound()const ;
+ void forceUpdateBindStats(void) const;
U32 getTexelsInAtlas() const ;
U32 getTexelsInGLTexture() const ;
@@ -220,6 +233,7 @@ public:
BOOL getDontDiscard() const { return mDontDiscard; }
//-----------------
+ BOOL isLargeImage() ;
/*virtual*/ void updateBindStatsForTester() ;
protected:
void cleanup() ;
@@ -228,6 +242,7 @@ protected:
private:
//note: do not make this function public.
/*virtual*/ LLImageGL* getGLTexture() const ;
+ virtual void switchToCachedImage();
protected:
LLUUID mID;
@@ -237,7 +252,9 @@ protected:
BOOL mUseMipMaps ;
S8 mComponents;
mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need?
+ mutable S8 mNeedsGLTexture;
mutable BOOL mNeedsResetMaxVirtualSize ;
+ mutable F32 mAdditionalDecodePriority; // priority add to mDecodePriority.
LLFrameTimer mLastReferencedTimer;
ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture
@@ -270,7 +287,12 @@ public:
static S32 sMaxBoundTextureMemInMegaBytes;
static S32 sMaxTotalTextureMemInMegaBytes;
static S32 sMaxDesiredTextureMemInBytes ;
- static BOOL sDontLoadVolumeTextures;
+ static S8 sCameraMovingDiscardBias;
+ static S32 sMaxSculptRez ;
+ static S32 sMinLargeImageSize ;
+ static S32 sMaxSmallImageSize ;
+ static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
+ static F32 sCurrentTime ;
static BOOL sUseTextureAtlas ;
static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
@@ -290,9 +312,9 @@ class LLViewerFetchedTexture : public LLViewerTexture
protected:
/*virtual*/ ~LLViewerFetchedTexture();
public:
- LLViewerFetchedTexture(const LLUUID& id, BOOL usemipmaps = TRUE);
+ LLViewerFetchedTexture(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemipmaps);
- LLViewerFetchedTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps = TRUE);
+ LLViewerFetchedTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE);
public:
static F32 maxDecodePriority();
@@ -328,6 +350,8 @@ public:
bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }
bool doLoadedCallbacks();
+ void addToCreateTexture();
+
// ONLY call from LLViewerTextureList
BOOL createTexture(S32 usename = 0);
void destroyTexture() ;
@@ -346,7 +370,12 @@ public:
// the priority list, and cause horrible things to happen.
void setDecodePriority(F32 priority = -1.0f);
F32 getDecodePriority() const { return mDecodePriority; };
+
+ void setAdditionalDecodePriority(F32 priority) ;
+ F32 maxAdditionalDecodePriority() ;
+ void updateVirtualSize() ;
+
// setDesiredDiscardLevel is only used by LLViewerTextureList
void setDesiredDiscardLevel(S32 discard) { mDesiredDiscardLevel = discard; }
S32 getDesiredDiscardLevel() { return mDesiredDiscardLevel; }
@@ -370,15 +399,15 @@ public:
BOOL isInImageList() const {return mInImageList ;}
void setInImageList(BOOL flag) {mInImageList = flag ;}
- const std::string& getLocalFileName() const {return mLocalFileName ;}
LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;}
U32 getFetchPriority() const { return mFetchPriority ;}
F32 getDownloadProgress() const {return mDownloadProgress ;}
- LLImageRaw* readBackRawImage(S8 discard_level) ;
+ LLImageRaw* reloadRawImage(S8 discard_level) ;
void destroyRawImage();
+ const std::string& getUrl() const {return mUrl;}
//---------------
BOOL isDeleted() ;
BOOL isInactive() ;
@@ -389,13 +418,36 @@ public:
//---------------
void setForSculpt();
- BOOL isForSculpt() const {return mForSculpt;}
+ BOOL forSculpt() const {return mForSculpt;}
+ BOOL isForSculptOnly() const;
+
+ //raw image management
+ void checkCachedRawSculptImage() ;
+ LLImageRaw* getRawImage()const { return mRawImage ;}
+ S32 getRawImageLevel() const {return mRawDiscardLevel;}
+ LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
+ S32 getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
+ BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;}
+ BOOL isRawImageValid()const { return mIsRawImageValid ; }
+ void forceToSaveRawImage(S32 desired_discard = 0) ;
+ void destroySavedRawImage() ;
+ LLImageRaw* getSavedRawImage() ;
+ BOOL hasSavedRawImage() const ;
+ F32 getElapsedLastReferencedSavedRawImageTime() const ;
+ BOOL isFullyLoaded() const;
+
+protected:
+ /*virtual*/ void switchToCachedImage();
private:
void init(bool firstinit) ;
void cleanup() ;
F32 calcDecodePriorityForUnknownTexture(F32 pixel_priority) ;
+ void saveRawImage() ;
+ BOOL forceFetch() ;
+ void setCachedRawImage() ;
+ BOOL keepReuestedDiscardLevel();
//for atlas
void resetFaceAtlas() ;
@@ -414,12 +466,8 @@ protected:
S32 mKnownDrawWidth;
S32 mKnownDrawHeight;
- std::string mLocalFileName;
-
- S8 mDesiredDiscardLevel; // The discard level we'd LIKE to have - if we have it and there's space
- S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have
- S32 mMinDiscardLevel;
-
+ std::string mUrl;
+
S32 mRequestedDiscardLevel;
F32 mRequestedDownloadPriority;
S32 mFetchState;
@@ -429,6 +477,10 @@ protected:
F32 mRequestDeltaTime;
S32 mDecodeFrame;
S32 mVisibleFrame; // decode frame where image was last visible
+ F32 mDecodePriority; // The priority for decoding this image.
+ S32 mMinDiscardLevel;
+ S8 mDesiredDiscardLevel; // The discard level we'd LIKE to have - if we have it and there's space
+ S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have
S8 mNeedsAux; // We need to decode the auxiliary channels
S8 mDecodingAux; // Are we decoding high components
@@ -436,10 +488,10 @@ protected:
S8 mHasFetcher; // We've made a fecth request
S8 mIsFetching; // Fetch request is active
- mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database.
+ mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database.
- F32 mDecodePriority; // The priority for decoding this image.
typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
+ S8 mLoadedCallbackDesiredDiscardLevel;
callback_list_t mLoadedCallbackList;
LLPointer<LLImageRaw> mRawImage;
@@ -449,6 +501,19 @@ protected:
// doing if you use it for anything else! - djs
LLPointer<LLImageRaw> mAuxRawImage;
+ //keep a copy of mRawImage for some special purposes
+ //when mForceToSaveRawImage is set.
+ BOOL mForceToSaveRawImage ;
+ LLPointer<LLImageRaw> mSavedRawImage;
+ S32 mSavedRawDiscardLevel;
+ S32 mDesiredSavedRawDiscardLevel;
+ F32 mLastReferencedSavedRawImageTime ;
+
+ //a small version of the copy of the raw image (<= 64 * 64)
+ LLPointer<LLImageRaw> mCachedRawImage;
+ S32 mCachedRawDiscardLevel;
+ BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.
+
LLHost mTargetHost; // if LLHost::invalid, just request from agent's simulator
// Timers
@@ -477,15 +542,17 @@ protected:
/*virtual*/ ~LLViewerLODTexture(){}
public:
- LLViewerLODTexture(const LLUUID& id, BOOL usemipmaps = TRUE);
- LLViewerLODTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps = TRUE);
+ LLViewerLODTexture(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
+ LLViewerLODTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE);
/*virtual*/ S8 getType() const;
// Process image stats to determine priority/quality requirements.
/*virtual*/ void processTextureStats();
-
+ BOOL isUpdateFrozen() ;
+
private:
void init(bool firstinit) ;
+ void scaleDown() ;
private:
@@ -608,6 +675,15 @@ public:
const LLUUID& force_id = LLUUID::null
);
+ static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,
+ BOOL usemipmap = TRUE,
+ BOOL level_immediate = FALSE, // Get the requested level immediately upon creation.
+ S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+ LLGLint internal_format = 0,
+ LLGLenum primary_format = 0,
+ const LLUUID& force_id = LLUUID::null
+ );
+
static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) ;
static void init() ;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 4ad4c8e1ea..31aedf666b 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -44,6 +44,7 @@
#include "llimagetga.h"
#include "llimagejpeg.h"
#include "llimagepng.h"
+#include "llimageworker.h"
#include "llsdserialize.h"
#include "llsys.h"
@@ -68,10 +69,15 @@
void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL;
-const S32 IMAGES_PER_REQUEST = 42;
-const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame
-const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame
-const F32 RESEND_IMAGE_REQUEST_TIME = 15.f; // seconds
+U32 LLViewerTextureList::sTextureBits = 0;
+U32 LLViewerTextureList::sTexturePackets = 0;
+S32 LLViewerTextureList::sNumImages = 0;
+LLStat LLViewerTextureList::sNumImagesStat(32, TRUE);
+LLStat LLViewerTextureList::sNumRawImagesStat(32, TRUE);
+LLStat LLViewerTextureList::sGLTexMemStat(32, TRUE);
+LLStat LLViewerTextureList::sGLBoundMemStat(32, TRUE);
+LLStat LLViewerTextureList::sRawMemStat(32, TRUE);
+LLStat LLViewerTextureList::sFormattedMemStat(32, TRUE);
LLViewerTextureList gTextureList;
static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images");
@@ -88,7 +94,7 @@ LLViewerTextureList::LLViewerTextureList()
void LLViewerTextureList::init()
{
- mNumImages = 0;
+ sNumImages = 0;
mMaxResidentTexMemInMegaBytes = 0;
mMaxTotalTextureMemInMegaBytes = 0 ;
if (gNoRender)
@@ -231,6 +237,10 @@ void LLViewerTextureList::shutdown()
{
continue; // avoid UI, baked, and other special images
}
+ if(!image->getBoundRecently())
+ {
+ continue ;
+ }
S32 desired = image->getDesiredDiscardLevel();
if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
{
@@ -321,17 +331,30 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
LLGLenum primary_format,
const LLUUID& force_id)
{
- if (gNoRender)
+ std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename);
+ if (full_path.empty())
{
- // Never mind that this ignores image_set_id;
- // getImage() will handle that later.
+ llwarns << "Failed to find local image file: " << filename << llendl;
return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE);
}
- std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename);
- if (full_path.empty())
+ std::string url = "file://" + full_path;
+
+ return getImageFromUrl(url, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id);
+}
+
+LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url,
+ BOOL usemipmaps,
+ BOOL level_immediate,
+ S8 texture_type,
+ LLGLint internal_format,
+ LLGLenum primary_format,
+ const LLUUID& force_id)
+{
+ if (gNoRender)
{
- llwarns << "Failed to find local image file: " << filename << llendl;
+ // Never mind that this ignores image_set_id;
+ // getImage() will handle that later.
return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE);
}
@@ -343,7 +366,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
}
else
{
- new_id.generate(full_path);
+ new_id.generate(url);
}
LLPointer<LLViewerFetchedTexture> imagep = findImage(new_id);
@@ -353,10 +376,10 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
switch(texture_type)
{
case LLViewerTexture::FETCHED_TEXTURE:
- imagep = new LLViewerFetchedTexture(full_path, new_id, usemipmaps);
+ imagep = new LLViewerFetchedTexture(url, new_id, usemipmaps);
break ;
case LLViewerTexture::LOD_TEXTURE:
- imagep = new LLViewerLODTexture(full_path, new_id, usemipmaps);
+ imagep = new LLViewerLODTexture(url, new_id, usemipmaps);
break ;
default:
llerrs << "Invalid texture type " << texture_type << llendl ;
@@ -372,7 +395,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
if (level_immediate)
{
imagep->dontDiscard();
- imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_UI);
+ imagep->setBoostLevel(LLViewerTexture::BOOST_UI);
}
}
@@ -424,18 +447,15 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
switch(texture_type)
{
case LLViewerTexture::FETCHED_TEXTURE:
- imagep = new LLViewerFetchedTexture(image_id, usemipmaps);
+ imagep = new LLViewerFetchedTexture(image_id, request_from_host, usemipmaps);
break ;
case LLViewerTexture::LOD_TEXTURE:
- imagep = new LLViewerLODTexture(image_id, usemipmaps);
+ imagep = new LLViewerLODTexture(image_id, request_from_host, usemipmaps);
break ;
default:
llerrs << "Invalid texture type " << texture_type << llendl ;
}
- // Might want to request from host other than where the agent is. JC
- imagep->setTargetHost(request_from_host);
-
if (internal_format && primary_format)
{
imagep->setExplicitFormat(internal_format, primary_format);
@@ -446,7 +466,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
if (level_immediate)
{
imagep->dontDiscard();
- imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_UI);
+ imagep->setBoostLevel(LLViewerTexture::BOOST_UI);
}
else
{
@@ -509,7 +529,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image)
{
llwarns << "Image with ID " << image_id << " already in list" << llendl;
}
- mNumImages++;
+ sNumImages++;
addImageToList(new_image);
mUUIDMap[image_id] = new_image;
@@ -526,7 +546,7 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
}
llverify(mUUIDMap.erase(image->getID()) == 1);
- mNumImages--;
+ sNumImages--;
removeImageFromList(image);
}
}
@@ -546,7 +566,9 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images");
void LLViewerTextureList::updateImages(F32 max_time)
{
- LLViewerStats::getInstance()->mNumImagesStat.addValue(mNumImages);
+ LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());
+
+ LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages);
LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
LLViewerStats::getInstance()->mGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes));
LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes));
@@ -554,10 +576,13 @@ void LLViewerTextureList::updateImages(F32 max_time)
LLViewerStats::getInstance()->mFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory));
updateImagesDecodePriorities();
+
+ F32 total_max_time = max_time;
max_time -= updateImagesFetchTextures(max_time);
- max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f);
+
+ max_time = llmax(max_time, total_max_time*.25f); // at least 25% of max_time
max_time -= updateImagesCreateTextures(max_time);
- max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f);
+
if (!mDirtyTextureList.empty())
{
LLFastTimer t(FTM_IMAGE_MARK_DIRTY);
@@ -570,7 +595,7 @@ void LLViewerTextureList::updateImages(F32 max_time)
{
//trigger loaded callbacks on local textures immediately
LLViewerFetchedTexture* image = *iter++;
- if (!image->getLocalFileName().empty())
+ if (!image->getUrl().empty())
{
// Do stuff to handle callbacks, update priorities, etc.
didone = image->doLoadedCallbacks();
@@ -628,6 +653,14 @@ void LLViewerTextureList::updateImagesDecodePriorities()
}
else
{
+ if(imagep->hasSavedRawImage())
+ {
+ if(imagep->getElapsedLastReferencedSavedRawImageTime() > MAX_INACTIVE_TIME)
+ {
+ imagep->destroySavedRawImage() ;
+ }
+ }
+
if(imagep->isDeleted())
{
continue ;
@@ -758,74 +791,76 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256);
// 32 high priority entries
- std::set<LLViewerFetchedTexture*> entries;
+ typedef std::vector<LLViewerFetchedTexture*> entries_list_t;
+ entries_list_t entries;
size_t update_counter = llmin(max_priority_count, mImageList.size());
image_priority_list_t::iterator iter1 = mImageList.begin();
while(update_counter > 0)
{
- // added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad
- if(iter1 == mImageList.end())
- {
- llerrs << "DEV-12002: update_counter not calculated correctly!" << llendl;
- return 0.f;
- }
-
- LLPointer<LLViewerFetchedTexture> const & ptr = *iter1;
-
- LLViewerFetchedTexture * img = ptr.get();
-
- // added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad
- if(img == NULL)
- {
- llwarns << "DEV-12002: image is NULL!" << llendl;
- }
-
- entries.insert(img);
-
+ entries.push_back(*iter1);
+
++iter1;
update_counter--;
}
// 256 cycled entries
- update_counter = llmin(max_update_count, mUUIDMap.size());
- uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
- while(update_counter > 0)
+ update_counter = llmin(max_update_count, mUUIDMap.size());
+ if(update_counter > 0)
{
- if (iter2 == mUUIDMap.end())
+ uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
+ uuid_map_t::iterator iter2p = iter2;
+ while(update_counter > 0)
{
- iter2 = mUUIDMap.begin();
+ if (iter2 == mUUIDMap.end())
+ {
+ iter2 = mUUIDMap.begin();
+ }
+ entries.push_back(iter2->second);
+ iter2p = iter2++;
+ update_counter--;
}
- mLastFetchUUID = iter2->first;
- entries.insert(iter2->second);
- ++iter2;
- update_counter--;
+
+ mLastFetchUUID = iter2p->first;
}
+ S32 fetch_count = 0;
S32 min_count = max_priority_count + max_update_count/4;
- for (std::set<LLViewerFetchedTexture*>::iterator iter3 = entries.begin();
+ for (entries_list_t::iterator iter3 = entries.begin();
iter3 != entries.end(); )
{
LLPointer<LLViewerFetchedTexture> imagep = *iter3++;
- imagep->updateFetch();
+ bool fetching = imagep->updateFetch();
+ if (fetching)
+ {
+ fetch_count++;
+ }
if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
{
break;
}
min_count--;
}
+ if (fetch_count == 0)
+ {
+ gDebugTimers[0].pause();
+ }
+ else
+ {
+ gDebugTimers[0].unpause();
+ }
return image_op_timer.getElapsedTimeF32();
}
void LLViewerTextureList::updateImagesUpdateStats()
{
- if (mUpdateStats)
+ if (mUpdateStats && mForceResetTextureStats)
{
for (image_priority_list_t::iterator iter = mImageList.begin();
iter != mImageList.end(); )
{
LLViewerFetchedTexture* imagep = *iter++;
- imagep->resetTextureStats(mForceResetTextureStats);
+ imagep->resetTextureStats();
}
mUpdateStats = FALSE;
mForceResetTextureStats = FALSE;
@@ -1011,6 +1046,9 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
return compressedImage;
}
+const S32 MIN_VIDEO_RAM = 32;
+const S32 MAX_VIDEO_RAM = 512; // 512MB max for performance reasons.
+
// Returns min setting for TextureMemory (in MB)
S32 LLViewerTextureList::getMinVideoRamSetting()
{
@@ -1129,13 +1167,13 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
if (msg->getReceiveCompressedSize())
{
- gTextureList.mTextureBits += msg->getReceiveCompressedSize() * 8;
+ gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
}
else
{
- gTextureList.mTextureBits += msg->getReceiveSize() * 8;
+ gTextureList.sTextureBits += msg->getReceiveSize() * 8;
}
- gTextureList.mTexturePackets++;
+ gTextureList.sTexturePackets++;
U8 codec;
U16 packets;
@@ -1194,13 +1232,13 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
if (msg->getReceiveCompressedSize())
{
- gTextureList.mTextureBits += msg->getReceiveCompressedSize() * 8;
+ gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
}
else
{
- gTextureList.mTextureBits += msg->getReceiveSize() * 8;
+ gTextureList.sTextureBits += msg->getReceiveSize() * 8;
}
- gTextureList.mTexturePackets++;
+ gTextureList.sTexturePackets++;
//llprintline("Start decode, image header...");
msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
@@ -1385,7 +1423,7 @@ void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_v
// for images grabbed from local files, apply clipping rectangle to restore original dimensions
// from power-of-2 gl image
- if (success && imagep.notNull() && src_vi && !src_vi->getLocalFileName().empty())
+ if (success && imagep.notNull() && src_vi && (src_vi->getUrl().compare(0, 7, "file://")==0))
{
F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getFullWidth();
F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getFullHeight();
@@ -1442,6 +1480,11 @@ bool LLUIImageList::initFromFile()
llwarns << "Unable to parse UI image list file " << base_file_path << llendl;
return false;
}
+ if (!root->hasAttribute("version"))
+ {
+ llwarns << "No valid version number in UI image list file " << base_file_path << llendl;
+ return false;
+ }
std::vector<std::string> paths;
// path to current selected skin
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index 11d1dd855f..2a86b88163 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -53,7 +53,6 @@ const BOOL GL_TEXTURE_NO = FALSE;
const BOOL IMMEDIATE_YES = TRUE;
const BOOL IMMEDIATE_NO = FALSE;
-class LLImageJ2C;
class LLMessageSystem;
class LLTextureView;
@@ -146,6 +145,15 @@ private:
LLGLenum primary_format = 0,
const LLUUID& force_id = LLUUID::null
);
+
+ LLViewerFetchedTexture* getImageFromUrl(const std::string& url,
+ BOOL usemipmap = TRUE,
+ BOOL level_immediate = FALSE, // Get the requested level immediately upon creation.
+ S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+ LLGLint internal_format = 0,
+ LLGLenum primary_format = 0,
+ const LLUUID& force_id = LLUUID::null
+ );
LLViewerFetchedTexture* createImage(const LLUUID &image_id,
BOOL usemipmap = TRUE,
@@ -190,11 +198,18 @@ private:
LLFrameTimer mForceDecodeTimer;
public:
- U32 mTextureBits;
- U32 mTexturePackets;
+ static U32 sTextureBits;
+ static U32 sTexturePackets;
+
+ static LLStat sNumImagesStat;
+ static LLStat sNumRawImagesStat;
+ static LLStat sGLTexMemStat;
+ static LLStat sGLBoundMemStat;
+ static LLStat sRawMemStat;
+ static LLStat sFormattedMemStat;
private:
- S32 mNumImages;
+ static S32 sNumImages;
static void (*sUUIDCallback)(void**, const LLUUID &);
};
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5f95e9ccf1..cee3a2a65b 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -117,6 +117,7 @@
#include "llhudview.h"
#include "llimagebmp.h"
#include "llimagej2c.h"
+#include "llimageworker.h"
#include "llkeyboard.h"
#include "lllineeditor.h"
#include "llmenugl.h"
@@ -157,7 +158,6 @@
#include "lltoolselectland.h"
#include "lltrans.h"
#include "lluictrlfactory.h"
-#include "lluploaddialog.h"
#include "llurldispatcher.h" // SLURL from other app instance
#include "llvieweraudio.h"
#include "llviewercamera.h"
@@ -189,6 +189,7 @@
#include "llbottomtray.h"
#include "llnearbychatbar.h"
#include "llagentui.h"
+#include "llwearablelist.h"
#include "llnotificationmanager.h"
@@ -326,7 +327,9 @@ public:
S32 hours = (S32)(time / (60*60));
S32 mins = (S32)((time - hours*(60*60)) / 60);
S32 secs = (S32)((time - hours*(60*60) - mins*60));
- addText(xpos, ypos, llformat(" Debug %d: %d:%02d:%02d", idx, hours,mins,secs)); ypos += y_inc2;
+ std::string label = gDebugTimerLabel[idx];
+ if (label.empty()) label = llformat("Debug: %d", idx);
+ addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2;
}
F32 time = gFrameTimeSeconds;
@@ -1299,6 +1302,7 @@ LLViewerWindow::LLViewerWindow(
// Init the image list. Must happen after GL is initialized and before the images that
// LLViewerWindow needs are requested.
+ LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
gTextureList.init();
LLViewerTextureManager::init() ;
gBumpImageList.init();
@@ -1657,6 +1661,8 @@ void LLViewerWindow::shutdownGL()
gSky.cleanup();
stop_glerror();
+ LLWearableList::instance().cleanup() ;
+
gTextureList.shutdown();
stop_glerror();
@@ -1670,7 +1676,10 @@ void LLViewerWindow::shutdownGL()
stop_glerror();
LLViewerTextureManager::cleanup() ;
-
+ LLImageGL::cleanupClass() ;
+
+ llinfos << "All texturs and llimagegl images are destroyed!" << llendl ;
+
llinfos << "Cleaning up select manager" << llendl;
LLSelectMgr::getInstance()->cleanup();
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 231b857d1f..a279bd8a68 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -321,7 +321,7 @@ public:
} ESnapshotType;
BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR);
BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE,
- BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_IMAGE_SIZE );
+ BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE );
BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ;
BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); }
void resetSnapshotLoc() const { sSnapshotDir.clear(); }
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index d124cbcdce..999701ece1 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -279,7 +279,6 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
if (mRawImages[i].isNull())
{
// Read back a raw image for this discard level, if it exists
- mRawImages[i] = new LLImageRaw;
S32 min_dim = llmin(mDetailTextures[i]->getFullWidth(), mDetailTextures[i]->getFullHeight());
S32 ddiscard = 0;
while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
@@ -287,12 +286,18 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
ddiscard++;
min_dim /= 2;
}
- if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i], false))
+
+ mDetailTextures[i]->reloadRawImage(ddiscard) ;
+ if(mDetailTextures[i]->getRawImageLevel() != ddiscard)//raw iamge is not ready, will enter here again later.
{
- llwarns << "Unable to read raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl;
- mRawImages[i] = NULL;
+ mDetailTextures[i]->destroyRawImage() ;
+ lldebugs << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << llendl;
return FALSE;
}
+
+ mRawImages[i] = mDetailTextures[i]->getRawImage() ;
+ mDetailTextures[i]->destroyRawImage() ;
+
if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE ||
mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE ||
mDetailTextures[i]->getComponents() != 3)
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 469aef6209..229227c144 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -988,7 +988,7 @@ void LLVOAvatar::resetImpostors()
// static
void LLVOAvatar::deleteCachedImages(bool clearAll)
-{
+{
if (LLTexLayerSet::sHasCaches)
{
lldebugs << "Deleting layer set caches" << llendl;
@@ -3897,7 +3897,7 @@ U32 LLVOAvatar::renderFootShadows()
LLGLDepthTest test(GL_TRUE, GL_FALSE);
//render foot shadows
LLGLEnable blend(GL_BLEND);
- gGL.getTexUnit(0)->bind(mShadowImagep.get());
+ gGL.getTexUnit(0)->bind(mShadowImagep, TRUE);
glColor4fv(mShadow0Facep->getRenderColor().mV);
mShadow0Facep->renderIndexed(foot_mask);
glColor4fv(mShadow1Facep->getRenderColor().mV);
@@ -3945,7 +3945,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
//------------------------------------------------------------------------
// LLVOAvatar::updateTextures()
//------------------------------------------------------------------------
-void LLVOAvatar::updateTextures(LLAgent &agent)
+void LLVOAvatar::updateTextures()
{
BOOL render_avatar = TRUE;
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index e3add8aa78..c4e68064e7 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -125,7 +125,7 @@ public:
virtual BOOL updateLOD();
BOOL updateJointLODs();
virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate.
- virtual void updateTextures(LLAgent &agent);
+ virtual void updateTextures();
virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
virtual void onShift(const LLVector3& shift_vector);
virtual U32 getPartitionType() const;
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 9a115ea4e6..673e699c30 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1142,26 +1142,6 @@ void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *sr
}
// virtual
-/* //unused
-BOOL LLVOAvatarSelf::getLocalTextureRaw(ETextureIndex index, LLImageRaw* image_raw) const
-{
- if (!isIndexLocalTexture(index)) return FALSE;
- if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR) return TRUE;
-
- const LocalTextureData *local_tex_data = getLocalTextureData(index)[0];
- if (local_tex_data->mImage->readBackRaw(-1, image_raw, false))
- {
-
- return TRUE;
- }
-
- // No data loaded yet
- setLocalTexture((ETextureIndex)index, getTEImage(index), FALSE); // <-- non-const, move this elsewhere
- return FALSE;
-}
-*/
-
-// virtual
BOOL LLVOAvatarSelf::getLocalTextureGL(ETextureIndex type, LLViewerTexture** tex_pp, U32 index) const
{
*tex_pp = NULL;
@@ -1812,12 +1792,13 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
if (!covered_by_baked)
{
- if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR)
+ if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR && imagep->getDiscardLevel() != 0)
{
F32 desired_pixels;
desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
imagep->setBoostLevel(getAvatarBoostLevel());
imagep->addTextureStats( desired_pixels / texel_area_ratio );
+ imagep->forceUpdateBindStats() ;
if (imagep->getDiscardLevel() < 0)
{
mHasGrey = TRUE; // for statistics gathering
@@ -2115,6 +2096,49 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
// static
void LLVOAvatarSelf::deleteScratchTextures()
{
+ if(gAuditTexture)
+ {
+ S32 total_tex_size = sScratchTexBytes ;
+ S32 tex_size = SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT ;
+
+ if( sScratchTexNames.checkData( GL_LUMINANCE ) )
+ {
+ LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= tex_size ;
+ }
+ if( sScratchTexNames.checkData( GL_ALPHA ) )
+ {
+ LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= tex_size ;
+ }
+ if( sScratchTexNames.checkData( GL_COLOR_INDEX ) )
+ {
+ LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= tex_size ;
+ }
+ if( sScratchTexNames.checkData( GL_LUMINANCE_ALPHA ) )
+ {
+ LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= 2 * tex_size ;
+ }
+ if( sScratchTexNames.checkData( GL_RGB ) )
+ {
+ LLImageGL::decTextureCounter(tex_size, 3, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= 3 * tex_size ;
+ }
+ if( sScratchTexNames.checkData( GL_RGBA ) )
+ {
+ LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= 4 * tex_size ;
+ }
+ //others
+ while(total_tex_size > 0)
+ {
+ LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ total_tex_size -= 4 * tex_size ;
+ }
+ }
+
for( LLGLuint* namep = sScratchTexNames.getFirstData();
namep;
namep = sScratchTexNames.getNextData() )
@@ -2137,7 +2161,8 @@ void LLVOAvatarSelf::deleteScratchTextures()
BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
{
U32 texture_bytes = 0;
- GLuint gl_name = getScratchTexName( format, &texture_bytes );
+ S32 components = 0;
+ GLuint gl_name = getScratchTexName( format, components, &texture_bytes );
if( gl_name )
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
@@ -2149,12 +2174,12 @@ BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
if( *last_bind_time != LLImageGL::sLastFrameTime )
{
*last_bind_time = LLImageGL::sLastFrameTime;
- LLImageGL::updateBoundTexMem(texture_bytes);
+ LLImageGL::updateBoundTexMem(texture_bytes, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
}
}
else
{
- LLImageGL::updateBoundTexMem(texture_bytes);
+ LLImageGL::updateBoundTexMem(texture_bytes, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) );
}
return TRUE;
@@ -2162,9 +2187,8 @@ BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
return FALSE;
}
-LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, U32* texture_bytes )
-{
- S32 components;
+LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, S32& components, U32* texture_bytes )
+{
GLenum internal_format;
switch( format )
{
@@ -2210,6 +2234,11 @@ LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, U32* texture_bytes
sScratchTexBytes += *texture_bytes;
LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes;
+
+ if(gAuditTexture)
+ {
+ LLImageGL::incTextureCounter(SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+ }
return name;
}
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index a555d04a63..06b3b25eec 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -239,7 +239,7 @@ public:
BOOL bindScratchTexture(LLGLenum format);
static void deleteScratchTextures();
protected:
- LLGLuint getScratchTexName(LLGLenum format, U32* texture_bytes);
+ LLGLuint getScratchTexName(LLGLenum format, S32& components, U32* texture_bytes);
private:
static S32 sScratchTexBytes;
static LLMap< LLGLenum, LLGLuint*> sScratchTexNames;
diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp
index 8d3c8b6f1a..177cb16c50 100644
--- a/indra/newview/llvoclouds.cpp
+++ b/indra/newview/llvoclouds.cpp
@@ -101,7 +101,7 @@ void LLVOClouds::setPixelAreaAndAngle(LLAgent &agent)
mPixelArea = 1500*100;
}
-void LLVOClouds::updateTextures(LLAgent &agent)
+void LLVOClouds::updateTextures()
{
getTEImage(0)->addTextureStats(mPixelArea);
}
diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h
index 95e6b96e4e..c4a75f5b5e 100644
--- a/indra/newview/llvoclouds.h
+++ b/indra/newview/llvoclouds.h
@@ -65,7 +65,7 @@ public:
/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
F32 getPartSize(S32 idx);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
void updateFaceSize(S32 idx) { }
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 570a3334b9..33c10450a1 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -322,7 +322,7 @@ void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent)
// BUG could speed this up by caching the relative_position and range calculations
-void LLVOGrass::updateTextures(LLAgent &agent)
+void LLVOGrass::updateTextures()
{
if (getTEImage(0))
{
diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h
index 124400d356..6a6fcc31c3 100644
--- a/indra/newview/llvograss.h
+++ b/indra/newview/llvograss.h
@@ -72,7 +72,7 @@ public:
LLStrider<U16>& indicesp);
void updateFaceSize(S32 idx) { }
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ BOOL updateLOD();
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp
index ac2484ddfd..221c6b61ec 100644
--- a/indra/newview/llvoground.cpp
+++ b/indra/newview/llvoground.cpp
@@ -70,7 +70,7 @@ BOOL LLVOGround::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
}
-void LLVOGround::updateTextures(LLAgent &agent)
+void LLVOGround::updateTextures()
{
}
diff --git a/indra/newview/llvoground.h b/indra/newview/llvoground.h
index af3fcd65d4..0ccb0834a2 100644
--- a/indra/newview/llvoground.h
+++ b/indra/newview/llvoground.h
@@ -51,7 +51,7 @@ public:
// Graphical stuff for objects - maybe broken out into render class
// later?
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 7585842623..f1e42f9375 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -108,7 +108,7 @@ void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent)
}
}
-void LLVOPartGroup::updateTextures(LLAgent &agent)
+void LLVOPartGroup::updateTextures()
{
// Texture stats for particles need to be updated in a different way...
}
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index 3dc3292992..18583b4be9 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -61,7 +61,7 @@ public:
virtual U32 getPartitionType() const;
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index d44c543266..ddf7ea0382 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -289,7 +289,7 @@ void LLSkyTex::create(const F32 brightness)
void LLSkyTex::createGLImage(S32 which)
{
- mTexture[which]->createGLTexture(0, mImageRaw[which]);
+ mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLViewerTexture::LOCAL);
mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
}
@@ -1180,7 +1180,7 @@ BOOL LLVOSky::updateSky()
return TRUE;
}
-void LLVOSky::updateTextures(LLAgent &agent)
+void LLVOSky::updateTextures()
{
if (mSunTexturep)
{
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 62c934fb41..ef74324e58 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -492,7 +492,7 @@ public:
// Graphical stuff for objects - maybe broken out into render class
// later?
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 164f0f0cad..ef7b161003 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -134,7 +134,7 @@ void LLVOSurfacePatch::setPixelAreaAndAngle(LLAgent &agent)
}
-void LLVOSurfacePatch::updateTextures(LLAgent &agent)
+void LLVOSurfacePatch::updateTextures()
{
}
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index aaf4d41fa1..10a5888526 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -75,7 +75,7 @@ public:
LLStrider<LLVector2> &texCoords1p,
LLStrider<U16> &indicesp);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
/*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp
index f5094c025e..75beab519e 100644
--- a/indra/newview/llvotextbubble.cpp
+++ b/indra/newview/llvotextbubble.cpp
@@ -115,7 +115,7 @@ BOOL LLVOTextBubble::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
}
-void LLVOTextBubble::updateTextures(LLAgent &agent)
+void LLVOTextBubble::updateTextures()
{
// Update the image levels of all textures...
diff --git a/indra/newview/llvotextbubble.h b/indra/newview/llvotextbubble.h
index 45d4df2a7e..7f84dbf631 100644
--- a/indra/newview/llvotextbubble.h
+++ b/indra/newview/llvotextbubble.h
@@ -44,7 +44,7 @@ public:
/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
/*virtual*/ BOOL updateLOD();
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 615ae13bc2..ee0c36eb9a 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -463,7 +463,7 @@ void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
#endif
}
-void LLVOTree::updateTextures(LLAgent &agent)
+void LLVOTree::updateTextures()
{
if (mTreeImagep)
{
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 13817fa111..feac9e0675 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -69,7 +69,7 @@ public:
// Graphical stuff for objects - maybe broken out into render class later?
/*virtual*/ void render(LLAgent &agent);
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvotreenew.h b/indra/newview/llvotreenew.h
index 3fec5855ef..426470101d 100644
--- a/indra/newview/llvotreenew.h
+++ b/indra/newview/llvotreenew.h
@@ -156,7 +156,7 @@ public:
/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
/*virtual*/ void render(LLAgent &agent);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 583246c23e..08b342b978 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -53,12 +53,10 @@
#include "lldrawpoolbump.h"
#include "llface.h"
#include "llspatialpartition.h"
-
-// TEMP HACK ventrella
#include "llhudmanager.h"
#include "llflexibleobject.h"
-
#include "llsky.h"
+#include "lltexturefetch.h"
#include "llviewercamera.h"
#include "llviewertexturelist.h"
#include "llviewerregion.h"
@@ -75,7 +73,6 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30;
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
const F32 FORCE_CULL_AREA = 8.f;
const F32 MAX_LOD_DISTANCE = 24.f;
-const S32 MAX_SCULPT_REZ = 128;
BOOL gAnimateTextures = TRUE;
@@ -100,7 +97,6 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mRelativeXformInvTrans.setIdentity();
mLOD = MIN_LOD;
- mSculptLevel = -2;
mTextureAnimp = NULL;
mVObjRadius = LLVector3(1,1,0.5f).length();
mNumFaces = 0;
@@ -499,28 +495,32 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
return TRUE;
}
-void LLVOVolume::updateTextures(LLAgent &agent)
+void LLVOVolume::updateTextures()
{
const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
- if (mDrawable.notNull() && mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
+ if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
{
- if (mDrawable->isVisible())
- {
- updateTextures();
- }
+ updateTextureVirtualSize();
}
}
-void LLVOVolume::updateTextures()
+void LLVOVolume::updateTextureVirtualSize()
{
// Update the pixel area of all faces
+ if(mDrawable.isNull() || !mDrawable->isVisible())
+ {
+ return ;
+ }
+
if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
{
return;
}
-
- if (LLViewerTexture::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible())
+
+ static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable");
+
+ if (dont_load_textures || LLAppViewer::getTextureFetch()->mDebugPause) // || !mDrawable->isVisible())
{
return;
}
@@ -537,14 +537,15 @@ void LLVOVolume::updateTextures()
LLFace* face = mDrawable->getFace(i);
const LLTextureEntry *te = face->getTextureEntry();
LLViewerTexture *imagep = face->getTexture();
- if (!imagep || !te ||
+ if (!imagep || !te ||
face->mExtents[0] == face->mExtents[1])
{
continue;
}
F32 vsize;
-
+ F32 old_size = face->getVirtualSize();
+
if (isHUDAttachment())
{
F32 area = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
@@ -554,12 +555,10 @@ void LLVOVolume::updateTextures()
}
else
{
- vsize = getTextureVirtualSize(face);
+ vsize = face->getTextureVirtualSize();
}
- mPixelArea = llmax(mPixelArea, face->getPixelArea());
-
- F32 old_size = face->getVirtualSize();
+ mPixelArea = llmax(mPixelArea, face->getPixelArea());
if (face->mTextureMatrix != NULL)
{
@@ -571,7 +570,6 @@ void LLVOVolume::updateTextures()
}
face->setVirtualSize(vsize);
- imagep->addTextureStats(vsize);
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
if (vsize < min_vsize) min_vsize = vsize;
@@ -603,32 +601,44 @@ void LLVOVolume::updateTextures()
mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
if (mSculptTexture.notNull())
{
- S32 lod = llmin(mLOD, 3);
- F32 lodf = ((F32)(lod + 1.0f)/4.f);
- F32 tex_size = lodf * MAX_SCULPT_REZ;
- mSculptTexture->addTextureStats(2.f * tex_size * tex_size);
mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
(S32)LLViewerTexture::BOOST_SCULPTED));
mSculptTexture->setForSculpt() ;
- }
-
- S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
- S32 current_discard = mSculptLevel;
+
+ if(!mSculptTexture->isCachedRawImageReady())
+ {
+ S32 lod = llmin(mLOD, 3);
+ F32 lodf = ((F32)(lod + 1.0f)/4.f);
+ F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ;
+ mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE);
+
+ //if the sculpty very close to the view point, load first
+ {
+ LLVector3 lookAt = getPositionAgent() - LLViewerCamera::getInstance()->getOrigin();
+ F32 dist = lookAt.normVec() ;
+ F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;
+ mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ;
+ }
+ }
+
+ S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
+ S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ;
- if (texture_discard >= 0 && //texture has some data available
- (texture_discard < current_discard || //texture has more data than last rebuild
- current_discard < 0)) //no previous rebuild
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
- mSculptChanged = TRUE;
- }
+ if (texture_discard >= 0 && //texture has some data available
+ (texture_discard < current_discard || //texture has more data than last rebuild
+ current_discard < 0)) //no previous rebuild
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+ mSculptChanged = TRUE;
+ }
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
{
setDebugText(llformat("T%d C%d V%d\n%dx%d",
- texture_discard, current_discard, getVolume()->getSculptLevel(),
- mSculptTexture->getHeight(), mSculptTexture->getWidth()));
+ texture_discard, current_discard, getVolume()->getSculptLevel(),
+ mSculptTexture->getHeight(), mSculptTexture->getWidth()));
}
+ }
}
if (getLightTextureID().notNull())
@@ -649,10 +659,10 @@ void LLVOVolume::updateTextures()
{
setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
}
- else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
- {
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
- }
+ else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ }
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
{
setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
@@ -664,36 +674,6 @@ void LLVOVolume::updateTextures()
}
}
-F32 LLVOVolume::getTextureVirtualSize(LLFace* face)
-{
- //get area of circle around face
- LLVector3 center = face->getPositionAgent();
- LLVector3 size = (face->mExtents[1] - face->mExtents[0]) * 0.5f;
-
- F32 face_area = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
-
- face->setPixelArea(face_area);
-
- if (face_area <= 0)
- {
- return 0.f;
- }
-
- //get area of circle in texture space
- LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0];
- F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f;
- if (texel_area <= 0)
- {
- // Probably animated, use default
- texel_area = 1.f;
- }
-
- //apply texel area to face area to get accurate ratio
- face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
-
- return face_area;
-}
-
BOOL LLVOVolume::isActive() const
{
return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
@@ -770,7 +750,6 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
return mDrawable;
}
-
BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
{
// Check if we need to change implementations
@@ -825,7 +804,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
{
sculpt();
}
- mSculptLevel = getVolume()->getSculptLevel();
}
}
else
@@ -840,32 +818,22 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
// sculpt replaces generate() for sculpted surfaces
void LLVOVolume::sculpt()
-{
- U16 sculpt_height = 0;
- U16 sculpt_width = 0;
- S8 sculpt_components = 0;
- const U8* sculpt_data = NULL;
-
+{
if (mSculptTexture.notNull())
- {
- S32 discard_level;
- S32 desired_discard = 0; // lower discard levels have MUCH less resolution
-
- discard_level = desired_discard;
+ {
+ U16 sculpt_height = 0;
+ U16 sculpt_width = 0;
+ S8 sculpt_components = 0;
+ const U8* sculpt_data = NULL;
+
+ S32 discard_level = mSculptTexture->getDiscardLevel() ;
+ LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ;
S32 max_discard = mSculptTexture->getMaxDiscardLevel();
if (discard_level > max_discard)
discard_level = max_discard; // clamp to the best we can do
- S32 best_discard = mSculptTexture->getDiscardLevel();
- if (discard_level < best_discard)
- discard_level = best_discard; // clamp to what we have
-
- if (best_discard == -1)
- discard_level = -1; // and if we have nothing, set to nothing
-
-
- S32 current_discard = getVolume()->getSculptLevel();
+ S32 current_discard = getVolume()->getSculptLevel() ;
if(current_discard < -2)
{
llwarns << "WARNING!!: Current discard of sculpty at " << current_discard
@@ -886,18 +854,7 @@ void LLVOVolume::sculpt()
if (current_discard == discard_level) // no work to do here
return;
- LLPointer<LLImageRaw> raw_image = new LLImageRaw();
- BOOL is_valid = mSculptTexture->readBackRaw(discard_level, raw_image, FALSE);
-
- sculpt_height = raw_image->getHeight();
- sculpt_width = raw_image->getWidth();
- sculpt_components = raw_image->getComponents();
-
- if(is_valid)
- {
- is_valid = mSculptTexture->isValidForSculpt(discard_level, sculpt_width, sculpt_height, sculpt_components) ;
- }
- if(!is_valid)
+ if(!raw_image)
{
sculpt_width = 0;
sculpt_height = 0;
@@ -909,10 +866,10 @@ void LLVOVolume::sculpt()
}
}
else
- {
- if (raw_image->getDataSize() < sculpt_height * sculpt_width * sculpt_components)
- llerrs << "Sculpt: image data size = " << raw_image->getDataSize()
- << " < " << sculpt_height << " x " << sculpt_width << " x " <<sculpt_components << llendl;
+ {
+ sculpt_height = raw_image->getHeight();
+ sculpt_width = raw_image->getWidth();
+ sculpt_components = raw_image->getComponents();
sculpt_data = raw_image->getData();
@@ -948,12 +905,6 @@ BOOL LLVOVolume::calcLOD()
return FALSE;
}
- //update face texture sizes on lod calculation
- //if (mDrawable->isVisible())
- //{
- // updateTextures();
- //}
-
S32 cur_detail = 0;
F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
@@ -2608,7 +2559,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
if (face == -1)
{
start_face = 0;
- end_face = volume->getNumFaces();
+ end_face = volume->getNumVolumeFaces();
}
else
{
@@ -2623,8 +2574,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit)
{
- LLFace* face = mDrawable->getFace(face_hit);
-
+ LLFace* face = mDrawable->getFace(face_hit);
+
if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))
{
v_end = p;
@@ -2870,7 +2821,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LLVOVolume* vobj = drawablep->getVOVolume();
llassert_always(vobj);
- vobj->updateTextures();
+ vobj->updateTextureVirtualSize();
vobj->preRebuild();
drawablep->clearState(LLDrawable::HAS_ALPHA);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 250c3ed917..6d90de2a6f 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -139,7 +139,7 @@ public:
BOOL getVolumeChanged() const { return mVolumeChanged; }
- F32 getTextureVirtualSize(LLFace* face);
+
/*virtual*/ F32 getRadius() const { return mVObjRadius; };
const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
@@ -187,8 +187,8 @@ public:
/*virtual*/ void updateFaceSize(S32 idx);
/*virtual*/ BOOL updateLOD();
void updateRadius();
- /*virtual*/ void updateTextures(LLAgent &agent);
- void updateTextures();
+ /*virtual*/ void updateTextures();
+ void updateTextureVirtualSize();
void updateFaceFlags();
void regenFaces();
@@ -267,7 +267,6 @@ private:
LLFrameTimer mTextureUpdateTimer;
S32 mLOD;
BOOL mLODChanged;
- S32 mSculptLevel;
BOOL mSculptChanged;
F32 mSpotLightPriority;
LLMatrix4 mRelativeXform;
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 0c967f9020..e5ff62746e 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -100,7 +100,7 @@ void LLVOWater::setPixelAreaAndAngle(LLAgent &agent)
// virtual
-void LLVOWater::updateTextures(LLAgent &agent)
+void LLVOWater::updateTextures()
{
}
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index 28a5633c58..3cc031e589 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -68,7 +68,7 @@ public:
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
/*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
- /*virtual*/ void updateTextures(LLAgent &agent);
+ /*virtual*/ void updateTextures();
/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
virtual U32 getPartitionType() const;
diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp
index da62223aac..9bde85dcaf 100644
--- a/indra/newview/llwearablelist.cpp
+++ b/indra/newview/llwearablelist.cpp
@@ -70,6 +70,11 @@ struct LLWearableArrivedData
LLWearableList::~LLWearableList()
{
+ llassert_always(mList.empty()) ;
+}
+
+void LLWearableList::cleanup()
+{
for_each(mList.begin(), mList.end(), DeletePairedPointer());
mList.clear();
}
diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h
index e5155c66a4..cf1a9bddff 100644
--- a/indra/newview/llwearablelist.h
+++ b/indra/newview/llwearablelist.h
@@ -44,6 +44,7 @@ class LLWearableList : public LLSingleton<LLWearableList>
public:
LLWearableList() {}
~LLWearableList();
+ void cleanup() ;
S32 getLength() const { return mList.size(); }
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 829d631473..5e83ab8c3c 100644
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -34,58 +34,82 @@
#include "llworldmap.h"
-#include "llregionhandle.h"
+#include "llworldmapmessage.h"
#include "message.h"
-
#include "llappviewer.h" // for gPacificDaylightTime
-#include "llagent.h"
-#include "llmapresponders.h"
-#include "llviewercontrol.h"
-#include "llfloaterworldmap.h"
#include "lltracker.h"
#include "llviewertexturelist.h"
-#include "llviewerregion.h"
-#include "llregionflags.h"
#include "lltrans.h"
-const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // 10 minutes
+// Timers to temporise database requests
+const F32 AGENTS_UPDATE_TIMER = 60.0; // Seconds between 2 agent requests for a region
+const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // Seconds before we consider re-requesting item data for the grid
+
+//---------------------------------------------------------------------------
+// LLItemInfo
+//---------------------------------------------------------------------------
-// For DEV-17507, do lazy image loading in llworldmapview.cpp instead,
-// limiting requests to currently visible regions and minimizing the
-// number of textures being requested simultaneously.
-//
-// Uncomment IMMEDIATE_IMAGE_LOAD to restore the old behavior
-//
-//#define IMMEDIATE_IMAGE_LOAD
LLItemInfo::LLItemInfo(F32 global_x, F32 global_y,
const std::string& name,
- LLUUID id,
- S32 extra, S32 extra2)
+ LLUUID id)
: mName(name),
mToolTip(""),
mPosGlobal(global_x, global_y, 40.0),
mID(id),
- mSelected(FALSE),
- mExtra(extra),
- mExtra2(extra2)
+ mCount(1)
+// mSelected(false)
+// mColor()
{
- mRegionHandle = to_region_handle(mPosGlobal);
}
-LLSimInfo::LLSimInfo()
-: mHandle(0),
+//---------------------------------------------------------------------------
+// LLSimInfo
+//---------------------------------------------------------------------------
+
+LLSimInfo::LLSimInfo(U64 handle)
+: mHandle(handle),
mName(),
mAgentsUpdateTime(0),
- mShowAgentLocations(FALSE),
mAccess(0x0),
mRegionFlags(0x0),
- mWaterHeight(0.f),
- mAlpha(-1.f)
+ mFirstAgentRequest(true)
+// mWaterHeight(0.f)
+{
+}
+
+void LLSimInfo::setLandForSaleImage (LLUUID image_id)
{
+ mMapImageID = image_id;
+
+ // Fetch the image
+ if (mMapImageID.notNull())
+ {
+ mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+ mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
+ }
+ else
+ {
+ mOverlayImage = NULL;
+ }
}
+LLPointer<LLViewerFetchedTexture> LLSimInfo::getLandForSaleImage ()
+{
+ if (mOverlayImage.isNull() && mMapImageID.notNull())
+ {
+ // Fetch the image if it hasn't been done yet (unlikely but...)
+ mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+ mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
+ }
+ if (!mOverlayImage.isNull())
+ {
+ // Boost the fetch level when we try to access that image
+ mOverlayImage->setBoostLevel(LLViewerTexture::BOOST_MAP);
+ }
+ return mOverlayImage;
+}
-LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const
+LLVector3d LLSimInfo::getGlobalPos(const LLVector3& local_pos) const
{
LLVector3d pos = from_region_handle(mHandle);
pos.mdV[VX] += local_pos.mV[VX];
@@ -94,128 +118,184 @@ LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const
return pos;
}
+LLVector3d LLSimInfo::getGlobalOrigin() const
+{
+ return from_region_handle(mHandle);
+}
LLVector3 LLSimInfo::getLocalPos(LLVector3d global_pos) const
{
LLVector3d sim_origin = from_region_handle(mHandle);
return LLVector3(global_pos - sim_origin);
}
+void LLSimInfo::clearImage()
+{
+ if (!mOverlayImage.isNull())
+ {
+ mOverlayImage->setBoostLevel(0);
+ mOverlayImage = NULL;
+ }
+}
-
-//---------------------------------------------------------------------------
-// World Map
-//---------------------------------------------------------------------------
-
-LLWorldMap::LLWorldMap() :
- mIsTrackingUnknownLocation( FALSE ),
- mInvalidLocation( FALSE ),
- mIsTrackingDoubleClick( FALSE ),
- mIsTrackingCommit( FALSE ),
- mUnknownLocation( 0, 0, 0 ),
- mRequestLandForSale(true),
- mCurrentMap(0),
- mMinX(U32_MAX),
- mMaxX(U32_MIN),
- mMinY(U32_MAX),
- mMaxY(U32_MIN),
- mNeighborMap(NULL),
- mTelehubCoverageMap(NULL),
- mNeighborMapWidth(0),
- mNeighborMapHeight(0),
- mSLURLRegionName(),
- mSLURLRegionHandle(0),
- mSLURL(),
- mSLURLCallback(0),
- mSLURLTeleport(false)
-{
- for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map)
+void LLSimInfo::dropImagePriority()
+{
+ if (!mOverlayImage.isNull())
{
- mMapLoaded[map] = FALSE;
- mMapBlockLoaded[map] = new BOOL[MAP_BLOCK_RES*MAP_BLOCK_RES];
- for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
- {
- mMapBlockLoaded[map][idx] = FALSE;
- }
+ mOverlayImage->setBoostLevel(0);
}
}
+// Update the agent count for that region
+void LLSimInfo::updateAgentCount(F64 time)
+{
+ if ((time - mAgentsUpdateTime > AGENTS_UPDATE_TIMER) || mFirstAgentRequest)
+ {
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, mHandle);
+ mAgentsUpdateTime = time;
+ mFirstAgentRequest = false;
+ }
+}
-LLWorldMap::~LLWorldMap()
+// Get the total agents count
+const S32 LLSimInfo::getAgentCount() const
{
- reset();
- for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map)
+ S32 total_agent_count = 0;
+ for (LLSimInfo::item_info_list_t::const_iterator it = mAgentLocations.begin(); it != mAgentLocations.end(); ++it)
{
- delete[] mMapBlockLoaded[map];
+ total_agent_count += it->getCount();
}
+ return total_agent_count;
}
+bool LLSimInfo::isName(const std::string& name) const
+{
+ return (LLStringUtil::compareInsensitive(name, mName) == 0);
+}
-void LLWorldMap::reset()
+void LLSimInfo::dump() const
{
- for_each(mSimInfoMap.begin(), mSimInfoMap.end(), DeletePairedPointer());
- mSimInfoMap.clear();
+ U32 x_pos, y_pos;
+ from_region_handle(mHandle, &x_pos, &y_pos);
+
+ LL_INFOS("World Map") << x_pos << "," << y_pos
+ << " " << mName
+ << " " << (S32)mAccess
+ << " " << std::hex << mRegionFlags << std::dec
+// << " " << mWaterHeight
+ << LL_ENDL;
+}
+
+void LLSimInfo::clearItems()
+{
+ mTelehubs.clear();
+ mInfohubs.clear();
+ mPGEvents.clear();
+ mMatureEvents.clear();
+ mAdultEvents.clear();
+ mLandForSale.clear();
+ mLandForSaleAdult.clear();
+// We persist the agent count though as it is updated on a frequent basis
+// mAgentLocations.clear();
+}
+
+void LLSimInfo::insertAgentLocation(const LLItemInfo& item)
+{
+ std::string name = item.getName();
- for (S32 m=0; m<MAP_SIM_IMAGE_TYPES; ++m)
+ // Find the last item in the list with a different name and erase them
+ item_info_list_t::iterator lastiter;
+ for (lastiter = mAgentLocations.begin(); lastiter != mAgentLocations.end(); ++lastiter)
+ {
+ LLItemInfo& info = *lastiter;
+ if (info.isName(name))
+ {
+ break;
+ }
+ }
+ if (lastiter != mAgentLocations.begin())
{
- mMapLoaded[m] = FALSE;
+ mAgentLocations.erase(mAgentLocations.begin(), lastiter);
}
+ // Now append the new location
+ mAgentLocations.push_back(item);
+}
+
+//---------------------------------------------------------------------------
+// World Map
+//---------------------------------------------------------------------------
+
+LLWorldMap::LLWorldMap() :
+ mIsTrackingLocation( false ),
+ mIsTrackingFound( false ),
+ mIsInvalidLocation( false ),
+ mIsTrackingDoubleClick( false ),
+ mIsTrackingCommit( false ),
+ mTrackingLocation( 0, 0, 0 ),
+ mFirstRequest(true)
+{
+ //LL_INFOS("World Map") << "Creating the World Map -> LLWorldMap::LLWorldMap()" << LL_ENDL;
+ mMapBlockLoaded = new bool[MAP_BLOCK_RES*MAP_BLOCK_RES];
clearSimFlags();
-
- eraseItems();
+}
- mMinX = U32_MAX;
- mMaxX = U32_MIN;
- mMinY = U32_MAX;
- mMaxY = U32_MIN;
+LLWorldMap::~LLWorldMap()
+{
+ //LL_INFOS("World Map") << "Destroying the World Map -> LLWorldMap::~LLWorldMap()" << LL_ENDL;
+ reset();
+ delete[] mMapBlockLoaded;
+}
- delete [] mNeighborMap;
- mNeighborMap = NULL;
- delete [] mTelehubCoverageMap;
- mTelehubCoverageMap = NULL;
- mNeighborMapWidth = 0;
- mNeighborMapHeight = 0;
+void LLWorldMap::reset()
+{
+ clearItems(true); // Clear the items lists
+ clearImageRefs(); // Clear the world mipmap and the land for sale tiles
+ clearSimFlags(); // Clear the block info flags array
- for (S32 i=0; i<MAP_SIM_IMAGE_TYPES; i++)
- {
- mMapLayers[i].clear();
- }
+ // Finally, clear the region map itself
+ for_each(mSimInfoMap.begin(), mSimInfoMap.end(), DeletePairedPointer());
+ mSimInfoMap.clear();
}
-void LLWorldMap::eraseItems()
+// Returns true if the items have been cleared
+bool LLWorldMap::clearItems(bool force)
{
- if (mRequestTimer.getElapsedTimeF32() > REQUEST_ITEMS_TIMER)
+ bool clear = false;
+ if ((mRequestTimer.getElapsedTimeF32() > REQUEST_ITEMS_TIMER) || mFirstRequest || force)
{
mRequestTimer.reset();
- mTelehubs.clear();
- mInfohubs.clear();
- mPGEvents.clear();
- mMatureEvents.clear();
- mAdultEvents.clear();
- mLandForSale.clear();
+ LLSimInfo* sim_info = NULL;
+ for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
+ {
+ sim_info = it->second;
+ if (sim_info)
+ {
+ sim_info->clearItems();
+ }
+ }
+ clear = true;
+ mFirstRequest = false;
}
-// mAgentLocationsMap.clear(); // persists
-// mNumAgents.clear(); // persists
+ return clear;
}
-
void LLWorldMap::clearImageRefs()
{
+ // We clear the reference to the images we're holding.
+ // Images hold by the world mipmap first
+ mWorldMipmap.reset();
+
+ // Images hold by the region map
+ LLSimInfo* sim_info = NULL;
for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
{
- LLSimInfo* info = (*it).second;
- if (info->mCurrentImage)
- {
- info->mCurrentImage->setBoostLevel(0);
- info->mCurrentImage = NULL;
- }
- if (info->mOverlayImage)
+ sim_info = it->second;
+ if (sim_info)
{
- info->mOverlayImage->setBoostLevel(0);
- info->mOverlayImage = NULL;
+ sim_info->clearImage();
}
}
}
@@ -223,15 +303,25 @@ void LLWorldMap::clearImageRefs()
// Doesn't clear the already-loaded sim infos, just re-requests them
void LLWorldMap::clearSimFlags()
{
- for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map)
+ for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
{
- for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
- {
- mMapBlockLoaded[map][idx] = FALSE;
- }
+ mMapBlockLoaded[idx] = false;
}
}
+LLSimInfo* LLWorldMap::createSimInfoFromHandle(const U64 handle)
+{
+ LLSimInfo* sim_info = new LLSimInfo(handle);
+ mSimInfoMap[handle] = sim_info;
+ return sim_info;
+}
+
+void LLWorldMap::equalizeBoostLevels()
+{
+ mWorldMipmap.equalizeBoostLevels();
+ return;
+}
+
LLSimInfo* LLWorldMap::simInfoFromPosGlobal(const LLVector3d& pos_global)
{
U64 handle = to_region_handle(pos_global);
@@ -243,11 +333,7 @@ LLSimInfo* LLWorldMap::simInfoFromHandle(const U64 handle)
sim_info_map_t::iterator it = mSimInfoMap.find(handle);
if (it != mSimInfoMap.end())
{
- LLSimInfo* sim_info = (*it).second;
- if (sim_info)
- {
- return sim_info;
- }
+ return it->second;
}
return NULL;
}
@@ -258,762 +344,272 @@ LLSimInfo* LLWorldMap::simInfoFromName(const std::string& sim_name)
LLSimInfo* sim_info = NULL;
if (!sim_name.empty())
{
- for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
+ // Iterate through the entire sim info map and compare the name
+ sim_info_map_t::iterator it;
+ for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
{
- sim_info = (*it).second;
- if (sim_info
- && (0 == LLStringUtil::compareInsensitive(sim_name, sim_info->mName)) )
+ sim_info = it->second;
+ if (sim_info && sim_info->isName(sim_name) )
{
+ // break out of loop if success
break;
}
- sim_info = NULL;
}
+ // If we got to the end, we haven't found the sim. Reset the ouput value to NULL.
+ if (it == mSimInfoMap.end())
+ sim_info = NULL;
}
return sim_info;
}
bool LLWorldMap::simNameFromPosGlobal(const LLVector3d& pos_global, std::string & outSimName )
{
- bool gotSimName = true;
+ LLSimInfo* sim_info = simInfoFromPosGlobal(pos_global);
- U64 handle = to_region_handle(pos_global);
-
- sim_info_map_t::iterator it = mSimInfoMap.find(handle);
- if (it != mSimInfoMap.end())
+ if (sim_info)
{
- LLSimInfo* info = (*it).second;
- outSimName = info->mName;
+ outSimName = sim_info->getName();
}
else
{
- gotSimName = false;
outSimName = "(unknown region)";
}
- return gotSimName;
+ return (sim_info != NULL);
}
-void LLWorldMap::setCurrentLayer(S32 layer, bool request_layer)
+void LLWorldMap::reloadItems(bool force)
{
- mCurrentMap = layer;
- if (!mMapLoaded[layer] || request_layer)
+ //LL_INFOS("World Map") << "LLWorldMap::reloadItems()" << LL_ENDL;
+ if (clearItems(force))
{
- sendMapLayerRequest();
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_TELEHUB);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_PG_EVENT);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT);
+ LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE);
}
-
- if (mTelehubs.size() == 0 ||
- mInfohubs.size() == 0)
- {
- // Request for telehubs
- sendItemRequest(MAP_ITEM_TELEHUB);
- }
-
- if (mPGEvents.size() == 0)
- {
- // Request for events
- sendItemRequest(MAP_ITEM_PG_EVENT);
- }
-
- if (mMatureEvents.size() == 0)
- {
- // Request for events (mature)
- sendItemRequest(MAP_ITEM_MATURE_EVENT);
- }
-
- if (mAdultEvents.size() == 0)
- {
- // Request for events (adult)
- sendItemRequest(MAP_ITEM_ADULT_EVENT);
- }
-
- if (mLandForSale.size() == 0)
- {
- // Request for Land For Sale
- sendItemRequest(MAP_ITEM_LAND_FOR_SALE);
- }
-
- if (mLandForSaleAdult.size() == 0)
- {
- // Request for Land For Sale
- sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT);
- }
-
- clearImageRefs();
- clearSimFlags();
}
-void LLWorldMap::sendItemRequest(U32 type, U64 handle)
+// static public
+// Insert a region in the region map
+// returns true if region inserted, false otherwise
+bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& image_id, U32 accesscode, U32 region_flags)
{
- LLMessageSystem* msg = gMessageSystem;
- S32 layer = mCurrentMap;
-
- msg->newMessageFast(_PREHASH_MapItemRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_Flags, layer);
- msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
- msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
-
- msg->nextBlockFast(_PREHASH_RequestData);
- msg->addU32Fast(_PREHASH_ItemType, type);
- msg->addU64Fast(_PREHASH_RegionHandle, handle); // If zero, filled in on sim
-
- gAgent.sendReliableMessage();
-}
-
-// public
-void LLWorldMap::sendMapLayerRequest()
-{
- if (!gAgent.getRegion()) return;
-
- LLSD body;
- body["Flags"] = mCurrentMap;
- std::string url = gAgent.getRegion()->getCapability(
- gAgent.isGodlike() ? "MapLayerGod" : "MapLayer");
-
- if (!url.empty())
+ // This region doesn't exist
+ if (accesscode == 255)
{
- llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl;
- LLHTTPClient::post(url, body, new LLMapLayerResponder());
+ // Checks if the track point is in it and invalidates it if it is
+ if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS))
+ {
+ LLWorldMap::getInstance()->setTrackingInvalid();
+ }
+ // return failure to insert
+ return false;
}
else
{
- llinfos << "LLWorldMap::sendMapLayerRequest via message system" << llendl;
- LLMessageSystem* msg = gMessageSystem;
- S32 layer = mCurrentMap;
-
- // Request for layer
- msg->newMessageFast(_PREHASH_MapLayerRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_Flags, layer);
- msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
- msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
- gAgent.sendReliableMessage();
-
- if (mRequestLandForSale)
+ U64 handle = to_region_handle(x_world, y_world);
+ //LL_INFOS("World Map") << "Map sim : " << name << ", ID : " << image_id.getString() << LL_ENDL;
+ // Insert the region in the region map of the world map
+ // Loading the LLSimInfo object with what we got and insert it in the map
+ LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+ if (siminfo == NULL)
{
- msg->newMessageFast(_PREHASH_MapLayerRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_Flags, 2);
- msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
- msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
- gAgent.sendReliableMessage();
+ siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);
}
+ siminfo->setName(name);
+ siminfo->setAccess(accesscode);
+ siminfo->setRegionFlags(region_flags);
+ // siminfo->setWaterHeight((F32) water_height);
+ siminfo->setLandForSaleImage(image_id);
+
+ // Handle the location tracking (for teleport, UI feedback and info display)
+ if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS))
+ {
+ if (siminfo->isDown())
+ {
+ // We were tracking this location, but it's no available
+ LLWorldMap::getInstance()->setTrackingInvalid();
+ }
+ else
+ {
+ // We were tracking this location, and it does exist and is available
+ LLWorldMap::getInstance()->setTrackingValid();
+ }
+ }
+ // return insert region success
+ return true;
}
}
-// public
-void LLWorldMap::sendNamedRegionRequest(std::string region_name)
-{
- LLMessageSystem* msg = gMessageSystem;
- S32 layer = mCurrentMap;
-
- // Request for layer
- msg->newMessageFast(_PREHASH_MapNameRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_Flags, layer);
- msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
- msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
- msg->nextBlockFast(_PREHASH_NameData);
- msg->addStringFast(_PREHASH_Name, region_name);
- gAgent.sendReliableMessage();
-}
-// public
-void LLWorldMap::sendNamedRegionRequest(std::string region_name,
- url_callback_t callback,
- const std::string& callback_url,
- bool teleport) // immediately teleport when result returned
-{
- mSLURLRegionName = region_name;
- mSLURLRegionHandle = 0;
- mSLURL = callback_url;
- mSLURLCallback = callback;
- mSLURLTeleport = teleport;
-
- sendNamedRegionRequest(region_name);
-}
-
-void LLWorldMap::sendHandleRegionRequest(U64 region_handle,
- url_callback_t callback,
- const std::string& callback_url,
- bool teleport) // immediately teleport when result returned
-{
- mSLURLRegionName.clear();
- mSLURLRegionHandle = region_handle;
- mSLURL = callback_url;
- mSLURLCallback = callback;
- mSLURLTeleport = teleport;
-
- U32 global_x;
- U32 global_y;
- from_region_handle(region_handle, &global_x, &global_y);
- U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS);
- U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS);
-
- sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true);
-}
-
-// public
-void LLWorldMap::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent)
-{
- S32 layer = mCurrentMap;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_MapBlockRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- U32 flags = layer;
- flags |= (return_nonexistent ? 0x10000 : 0);
- msg->addU32Fast(_PREHASH_Flags, flags);
- msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
- msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
- msg->nextBlockFast(_PREHASH_PositionData);
- msg->addU16Fast(_PREHASH_MinX, min_x);
- msg->addU16Fast(_PREHASH_MinY, min_y);
- msg->addU16Fast(_PREHASH_MaxX, max_x);
- msg->addU16Fast(_PREHASH_MaxY, max_y);
- gAgent.sendReliableMessage();
-
- if (mRequestLandForSale)
- {
- msg->newMessageFast(_PREHASH_MapBlockRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_Flags, 2);
- msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
- msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
- msg->nextBlockFast(_PREHASH_PositionData);
- msg->addU16Fast(_PREHASH_MinX, min_x);
- msg->addU16Fast(_PREHASH_MinY, min_y);
- msg->addU16Fast(_PREHASH_MaxX, max_x);
- msg->addU16Fast(_PREHASH_MaxY, max_y);
- gAgent.sendReliableMessage();
- }
-}
-
-// public static
-void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**)
+// static public
+// Insert an item in the relevant region map
+// returns true if item inserted, false otherwise
+bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 type, S32 extra, S32 extra2)
{
- llinfos << "LLWorldMap::processMapLayerReply from message system" << llendl;
-
- U32 agent_flags;
- msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
-
- if (agent_flags != (U32)LLWorldMap::getInstance()->mCurrentMap)
- {
- llwarns << "Invalid or out of date map image type returned!" << llendl;
- return;
- }
-
- LLUUID image_id;
- //U32 left, right, top, bottom;
-
- S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_LayerData);
-
- LLWorldMap::getInstance()->mMapLayers[agent_flags].clear();
-
- BOOL adjust = FALSE;
- for (S32 block=0; block<num_blocks; ++block)
- {
- LLWorldMapLayer new_layer;
- new_layer.LayerDefined = TRUE;
- msg->getUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block);
- new_layer.LayerImage = LLViewerTextureManager::getFetchedTexture(new_layer.LayerImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-
- gGL.getTexUnit(0)->bind(new_layer.LayerImage);
- new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP);
-
- U32 left, right, top, bottom;
- msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Left, left, block);
- msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Right, right, block);
- msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Top, top, block);
- msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Bottom, bottom, block);
-
- new_layer.LayerExtents.mLeft = left;
- new_layer.LayerExtents.mRight = right;
- new_layer.LayerExtents.mBottom = bottom;
- new_layer.LayerExtents.mTop = top;
-
- F32 x_meters = F32(left*REGION_WIDTH_UNITS);
- F32 y_meters = F32(bottom*REGION_WIDTH_UNITS);
- adjust = LLWorldMap::getInstance()->extendAABB(U32(x_meters), U32(y_meters),
- U32(x_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getWidth()),
- U32(y_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getHeight())) || adjust;
-
- LLWorldMap::getInstance()->mMapLayers[agent_flags].push_back(new_layer);
- }
-
- LLWorldMap::getInstance()->mMapLoaded[agent_flags] = TRUE;
- if(adjust) gFloaterWorldMap->adjustZoomSliderBounds();
-}
+ // Create an item record for the received object
+ LLItemInfo new_item((F32)x_world, (F32)y_world, name, uuid);
-// public static
-void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**)
-{
- U32 agent_flags;
- msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
+ // Compute a region handle based on the objects coordinates
+ LLVector3d pos((F32)x_world, (F32)y_world, 40.0);
+ U64 handle = to_region_handle(pos);
- if ((S32)agent_flags < 0 || agent_flags >= MAP_SIM_IMAGE_TYPES)
+ // Get the region record for that handle or NULL if we haven't browsed it yet
+ LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+ if (siminfo == NULL)
{
- llwarns << "Invalid map image type returned! " << agent_flags << llendl;
- return;
+ siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);
}
- S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data);
-
- bool found_null_sim = false;
-
- BOOL adjust = FALSE;
- for (S32 block=0; block<num_blocks; ++block)
+ //LL_INFOS("World Map") << "Process item : type = " << type << LL_ENDL;
+ switch (type)
{
- U16 x_regions;
- U16 y_regions;
- std::string name;
- U8 accesscode;
- U32 region_flags;
- U8 water_height;
- U8 agents;
- LLUUID image_id;
- msg->getU16Fast(_PREHASH_Data, _PREHASH_X, x_regions, block);
- msg->getU16Fast(_PREHASH_Data, _PREHASH_Y, y_regions, block);
- msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block);
- msg->getU8Fast(_PREHASH_Data, _PREHASH_Access, accesscode, block);
- msg->getU32Fast(_PREHASH_Data, _PREHASH_RegionFlags, region_flags, block);
- msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block);
- msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block);
- msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block);
-
- U32 x_meters = x_regions * REGION_WIDTH_UNITS;
- U32 y_meters = y_regions * REGION_WIDTH_UNITS;
-
- U64 handle = to_region_handle(x_meters, y_meters);
-
- if (accesscode == 255)
- {
- // This region doesn't exist
- if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[0] >= x_meters &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[0] < x_meters + 256 &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[1] >= y_meters &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[1] < y_meters + 256)
- {
- // We were tracking this location, but it doesn't exist
- LLWorldMap::getInstance()->mInvalidLocation = TRUE;
- }
-
- found_null_sim = true;
- }
- else
+ case MAP_ITEM_TELEHUB: // telehubs
{
- adjust = LLWorldMap::getInstance()->extendAABB(x_meters,
- y_meters,
- x_meters+REGION_WIDTH_UNITS,
- y_meters+REGION_WIDTH_UNITS) || adjust;
-
-// llinfos << "Map sim " << name << " image layer " << agent_flags << " ID " << image_id.getString() << llendl;
-
- LLSimInfo* siminfo = new LLSimInfo();
- sim_info_map_t::iterator iter = LLWorldMap::getInstance()->mSimInfoMap.find(handle);
- if (iter != LLWorldMap::getInstance()->mSimInfoMap.end())
- {
- LLSimInfo* oldinfo = iter->second;
- for (S32 image=0; image<MAP_SIM_IMAGE_TYPES; ++image)
- {
- siminfo->mMapImageID[image] = oldinfo->mMapImageID[image];
- }
- delete oldinfo;
- }
- LLWorldMap::getInstance()->mSimInfoMap[handle] = siminfo;
-
- siminfo->mHandle = handle;
- siminfo->mName.assign( name );
- siminfo->mAccess = accesscode;
- siminfo->mRegionFlags = region_flags;
- siminfo->mWaterHeight = (F32) water_height;
- siminfo->mMapImageID[agent_flags] = image_id;
-
-#ifdef IMMEDIATE_IMAGE_LOAD
- siminfo->mCurrentImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
- siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
-#endif
+ /* Merov: we are not using the hub color anymore for display so commenting that out
+ // Telehub color
+ U32 X = x_world / REGION_WIDTH_UNITS;
+ U32 Y = y_world / REGION_WIDTH_UNITS;
+ F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f;
+ F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f;
+ F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f;
+ F32 add_amt = (X % 2) ? 0.15f : -0.15f;
+ add_amt += (Y % 2) ? -0.15f : 0.15f;
+ LLColor4 color(red + add_amt, green + add_amt, blue + add_amt);
+ new_item.setColor(color);
+ */
- if (siminfo->mMapImageID[2].notNull())
+ // extra2 specifies whether this is an infohub or a telehub.
+ if (extra2)
{
-#ifdef IMMEDIATE_IMAGE_LOAD
- siminfo->mOverlayImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-#endif
+ siminfo->insertInfoHub(new_item);
}
else
{
- siminfo->mOverlayImage = NULL;
- }
-
- if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[0] >= x_meters &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[0] < x_meters + 256 &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[1] >= y_meters &&
- LLWorldMap::getInstance()->mUnknownLocation.mdV[1] < y_meters + 256)
- {
- if (siminfo->mAccess == SIM_ACCESS_DOWN)
- {
- // We were tracking this location, but it doesn't exist
- LLWorldMap::getInstance()->mInvalidLocation = true;
- }
- else
- {
- // We were tracking this location, and it does exist
- bool is_tracking_dbl = LLWorldMap::getInstance()->mIsTrackingDoubleClick == TRUE;
- gFloaterWorldMap->trackLocation(LLWorldMap::getInstance()->mUnknownLocation);
- if (is_tracking_dbl)
- {
- LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
- gAgent.teleportViaLocation( pos_global );
- }
- }
+ siminfo->insertTeleHub(new_item);
}
+ break;
}
-
- if(LLWorldMap::getInstance()->mSLURLCallback != NULL)
+ case MAP_ITEM_PG_EVENT: // events
+ case MAP_ITEM_MATURE_EVENT:
+ case MAP_ITEM_ADULT_EVENT:
{
- // Server returns definitive capitalization, SLURL might not have that.
- if ((LLStringUtil::compareInsensitive(LLWorldMap::getInstance()->mSLURLRegionName, name)==0)
- || (LLWorldMap::getInstance()->mSLURLRegionHandle == handle))
+ std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:["
+ +LLTrans::getString ("TimeMin")+"] ["
+ +LLTrans::getString ("TimeAMPM")+"]";
+ LLSD substitution;
+ substitution["datetime"] = (S32) extra;
+ LLStringUtil::format (timeStr, substitution);
+ new_item.setTooltip(timeStr);
+
+ // HACK: store Z in extra2
+ new_item.setElevation((F64)extra2);
+ if (type == MAP_ITEM_PG_EVENT)
{
- url_callback_t callback = LLWorldMap::getInstance()->mSLURLCallback;
-
- LLWorldMap::getInstance()->mSLURLCallback = NULL;
- LLWorldMap::getInstance()->mSLURLRegionName.clear();
- LLWorldMap::getInstance()->mSLURLRegionHandle = 0;
-
- callback(handle, LLWorldMap::getInstance()->mSLURL, image_id, LLWorldMap::getInstance()->mSLURLTeleport);
+ siminfo->insertPGEvent(new_item);
}
- }
- }
-
- if(adjust) gFloaterWorldMap->adjustZoomSliderBounds();
- gFloaterWorldMap->updateSims(found_null_sim);
-}
-
-// public static
-void LLWorldMap::processMapItemReply(LLMessageSystem* msg, void**)
-{
- U32 type;
- msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type);
-
- S32 num_blocks = msg->getNumberOfBlocks("Data");
-
- for (S32 block=0; block<num_blocks; ++block)
- {
- U32 X, Y;
- std::string name;
- S32 extra, extra2;
- LLUUID uuid;
- msg->getU32Fast(_PREHASH_Data, _PREHASH_X, X, block);
- msg->getU32Fast(_PREHASH_Data, _PREHASH_Y, Y, block);
- msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block);
- msg->getUUIDFast(_PREHASH_Data, _PREHASH_ID, uuid, block);
- msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra, extra, block);
- msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra2, extra2, block);
-
- F32 world_x = (F32)X;
- X /= REGION_WIDTH_UNITS;
- F32 world_y = (F32)Y;
- Y /= REGION_WIDTH_UNITS;
-
- LLItemInfo new_item(world_x, world_y, name, uuid, extra, extra2);
- LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(new_item.mRegionHandle);
-
- switch (type)
- {
- case MAP_ITEM_TELEHUB: // telehubs
+ else if (type == MAP_ITEM_MATURE_EVENT)
{
- // Telehub color, store in extra as 4 U8's
- U8 *color = (U8 *)&new_item.mExtra;
-
- F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f;
- F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f;
- F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f;
- F32 add_amt = (X % 2) ? 0.15f : -0.15f;
- add_amt += (Y % 2) ? -0.15f : 0.15f;
- color[0] = U8((red + add_amt) * 255);
- color[1] = U8((green + add_amt) * 255);
- color[2] = U8((blue + add_amt) * 255);
- color[3] = 255;
-
- // extra2 specifies whether this is an infohub or a telehub.
- if (extra2)
- {
- LLWorldMap::getInstance()->mInfohubs.push_back(new_item);
- }
- else
- {
- LLWorldMap::getInstance()->mTelehubs.push_back(new_item);
- }
-
- break;
+ siminfo->insertMatureEvent(new_item);
}
- case MAP_ITEM_PG_EVENT: // events
- case MAP_ITEM_MATURE_EVENT:
- case MAP_ITEM_ADULT_EVENT:
+ else if (type == MAP_ITEM_ADULT_EVENT)
{
- std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:["
- +LLTrans::getString ("TimeMin")+"] ["
- +LLTrans::getString ("TimeAMPM")+"]";
- LLSD substitution;
- substitution["datetime"] = (S32) extra;
- LLStringUtil::format (timeStr, substitution);
- new_item.mToolTip = timeStr;
-
- // HACK: store Z in extra2
- new_item.mPosGlobal.mdV[VZ] = (F64)extra2;
- if (type == MAP_ITEM_PG_EVENT)
- {
- LLWorldMap::getInstance()->mPGEvents.push_back(new_item);
- }
- else if (type == MAP_ITEM_MATURE_EVENT)
- {
- LLWorldMap::getInstance()->mMatureEvents.push_back(new_item);
- }
- else if (type == MAP_ITEM_ADULT_EVENT)
- {
- LLWorldMap::getInstance()->mAdultEvents.push_back(new_item);
- }
-
- break;
+ siminfo->insertAdultEvent(new_item);
}
- case MAP_ITEM_LAND_FOR_SALE: // land for sale
- case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale
+ break;
+ }
+ case MAP_ITEM_LAND_FOR_SALE: // land for sale
+ case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale
+ {
+ std::string tooltip = llformat("%d sq. m. L$%d", extra, extra2);
+ new_item.setTooltip(tooltip);
+ if (type == MAP_ITEM_LAND_FOR_SALE)
{
- new_item.mToolTip = llformat("%d sq. m. L$%d", new_item.mExtra, new_item.mExtra2);
- if (type == MAP_ITEM_LAND_FOR_SALE)
- {
- LLWorldMap::getInstance()->mLandForSale.push_back(new_item);
- }
- else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT)
- {
- LLWorldMap::getInstance()->mLandForSaleAdult.push_back(new_item);
- }
- break;
+ siminfo->insertLandForSale(new_item);
}
- case MAP_ITEM_CLASSIFIED: // classifieds
+ else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT)
{
- //DEPRECATED: no longer used
- break;
+ siminfo->insertLandForSaleAdult(new_item);
}
- case MAP_ITEM_AGENT_LOCATIONS: // agent locations
+ break;
+ }
+ case MAP_ITEM_CLASSIFIED: // classifieds
+ {
+ //DEPRECATED: no longer used
+ break;
+ }
+ case MAP_ITEM_AGENT_LOCATIONS: // agent locations
+ {
+// LL_INFOS("World Map") << "New Location " << new_item.mName << LL_ENDL;
+ if (extra > 0)
{
- if (!siminfo)
- {
- llinfos << "siminfo missing for " << new_item.mPosGlobal.mdV[0] << ", " << new_item.mPosGlobal.mdV[1] << llendl;
- break;
- }
-// llinfos << "New Location " << new_item.mName << llendl;
-
- item_info_list_t& agentcounts = LLWorldMap::getInstance()->mAgentLocationsMap[new_item.mRegionHandle];
-
- // Find the last item in the list with a different name and erase them
- item_info_list_t::iterator lastiter;
- for (lastiter = agentcounts.begin(); lastiter!=agentcounts.end(); ++lastiter)
- {
- const LLItemInfo& info = *lastiter;
- if (info.mName == new_item.mName)
- {
- break;
- }
- }
- if (lastiter != agentcounts.begin())
- {
- agentcounts.erase(agentcounts.begin(), lastiter);
- }
- // Now append the new location
- if (new_item.mExtra > 0)
- {
- agentcounts.push_back(new_item);
- }
- break;
+ new_item.setCount(extra);
+ siminfo->insertAgentLocation(new_item);
}
- default:
- break;
- };
- }
-}
-
-void LLWorldMap::dump()
-{
- for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
- {
- U64 handle = (*it).first;
- LLSimInfo* info = (*it).second;
-
- U32 x_pos, y_pos;
- from_region_handle(handle, &x_pos, &y_pos);
-
- llinfos << x_pos << "," << y_pos
- << " " << info->mName
- << " " << (S32)info->mAccess
- << " " << std::hex << info->mRegionFlags << std::dec
- << " " << info->mWaterHeight
- //<< " " << info->mTelehubName
- //<< " " << info->mTelehubPosition
- << llendl;
-
- if (info->mCurrentImage)
- {
- llinfos << "image discard " << (S32)info->mCurrentImage->getDiscardLevel()
- << " fullwidth " << info->mCurrentImage->getFullWidth()
- << " fullheight " << info->mCurrentImage->getFullHeight()
- << " maxvirt " << info->mCurrentImage->getMaxVirtualSize()
- //<< " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel()
- << llendl;
+ break;
}
+ default:
+ break;
}
+ return true;
}
-
-BOOL LLWorldMap::extendAABB(U32 min_x, U32 min_y, U32 max_x, U32 max_y)
+bool LLWorldMap::isTrackingInRectangle(F64 x0, F64 y0, F64 x1, F64 y1)
{
- BOOL rv = FALSE;
- if (min_x < mMinX)
- {
- rv = TRUE;
- mMinX = min_x;
- }
- if (min_y < mMinY)
- {
- rv = TRUE;
- mMinY = min_y;
- }
- if (max_x > mMaxX)
- {
- rv = TRUE;
- mMaxX = max_x;
- }
- if (max_y > mMaxY)
- {
- rv = TRUE;
- mMaxY = max_y;
- }
- lldebugs << "World map aabb: (" << mMinX << ", " << mMinY << "), ("
- << mMaxX << ", " << mMaxY << ")" << llendl;
- return rv;
+ if (!mIsTrackingLocation)
+ return false;
+ return ((mTrackingLocation[0] >= x0) && (mTrackingLocation[0] < x1) && (mTrackingLocation[1] >= y0) && (mTrackingLocation[1] < y1));
}
-
-U32 LLWorldMap::getWorldWidth() const
+// Drop priority of all images being fetched by the map
+void LLWorldMap::dropImagePriorities()
{
- return mMaxX - mMinX;
-}
-
-
-U32 LLWorldMap::getWorldHeight() const
-{
- return mMaxY - mMinY;
-}
-
-BOOL LLWorldMap::coveredByTelehub(LLSimInfo* infop)
-{
- /*if (!mTelehubCoverageMap)
+ // Drop the download of tiles priority to nil
+ mWorldMipmap.dropBoostLevels();
+ // Same for the "land for sale" tiles per region
+ for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
{
- return FALSE;
+ LLSimInfo* info = it->second;
+ info->dropImagePriority();
}
- U32 x_pos, y_pos;
- from_region_handle(infop->mHandle, &x_pos, &y_pos);
- x_pos /= REGION_WIDTH_UNITS;
- y_pos /= REGION_WIDTH_UNITS;
-
- S32 index = x_pos - (mMinX / REGION_WIDTH_UNITS - 1) + (mNeighborMapWidth * (y_pos - (mMinY / REGION_WIDTH_UNITS - 1)));
- return mTelehubCoverageMap[index] != 0; */
- return FALSE;
}
-void LLWorldMap::updateTelehubCoverage()
+// Load all regions in a given rectangle (in region grid coordinates, i.e. world / 256 meters)
+void LLWorldMap::updateRegions(S32 x0, S32 y0, S32 x1, S32 y1)
{
- /*S32 neighbor_width = getWorldWidth() / REGION_WIDTH_UNITS + 2;
- S32 neighbor_height = getWorldHeight() / REGION_WIDTH_UNITS + 2;
- if (neighbor_width > mNeighborMapWidth || neighbor_height > mNeighborMapHeight)
- {
- mNeighborMapWidth = neighbor_width;
- mNeighborMapHeight = neighbor_height;
- delete mNeighborMap;
- delete mTelehubCoverageMap;
-
- mNeighborMap = new U8[mNeighborMapWidth * mNeighborMapHeight];
- mTelehubCoverageMap = new U8[mNeighborMapWidth * mNeighborMapHeight];
- }
-
- memset(mNeighborMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8));
- memset(mTelehubCoverageMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8));
+ // Convert those boundaries to the corresponding (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) block coordinates
+ x0 = x0 / MAP_BLOCK_SIZE;
+ x1 = x1 / MAP_BLOCK_SIZE;
+ y0 = y0 / MAP_BLOCK_SIZE;
+ y1 = y1 / MAP_BLOCK_SIZE;
- // leave 1 sim border
- S32 min_x = (mMinX / REGION_WIDTH_UNITS) - 1;
- S32 min_y = (mMinY / REGION_WIDTH_UNITS) - 1;
-
- std::map<U64, LLSimInfo*>::const_iterator it;
- for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
+ // Load the region info those blocks
+ for (S32 block_x = llmax(x0, 0); block_x <= llmin(x1, MAP_BLOCK_RES-1); ++block_x)
{
- U64 handle = (*it).first;
- //LLSimInfo* info = (*it).second;
-
- U32 x_pos, y_pos;
- from_region_handle(handle, &x_pos, &y_pos);
- x_pos /= REGION_WIDTH_UNITS;
- y_pos /= REGION_WIDTH_UNITS;
- x_pos -= min_x;
- y_pos -= min_y;
-
- S32 index = x_pos + (mNeighborMapWidth * y_pos);
- mNeighborMap[index - 1]++;
- mNeighborMap[index + 1]++;
- mNeighborMap[index - mNeighborMapWidth]++;
- mNeighborMap[index + mNeighborMapWidth]++;
- }
-
- for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
- {
- U64 handle = (*it).first;
- LLSimInfo* info = (*it).second;
-
- U32 x_pos, y_pos;
- from_region_handle(handle, &x_pos, &y_pos);
- x_pos /= REGION_WIDTH_UNITS;
- y_pos /= REGION_WIDTH_UNITS;
- x_pos -= min_x;
- y_pos -= min_y;
-
- S32 index = x_pos + (mNeighborMapWidth * y_pos);
-
- if (!info->mTelehubName.empty() && mNeighborMap[index])
+ for (S32 block_y = llmax(y0, 0); block_y <= llmin(y1, MAP_BLOCK_RES-1); ++block_y)
{
- S32 x_start = llmax(0, S32(x_pos - 5));
- S32 x_span = llmin(mNeighborMapWidth - 1, (S32)(x_pos + 5)) - x_start + 1;
- S32 y_start = llmax(0, (S32)y_pos - 5);
- S32 y_end = llmin(mNeighborMapHeight - 1, (S32)(y_pos + 5));
- for (S32 y_index = y_start; y_index <= y_end; y_index++)
+ S32 offset = block_x | (block_y * MAP_BLOCK_RES);
+ if (!mMapBlockLoaded[offset])
{
- memset(&mTelehubCoverageMap[x_start + y_index * mNeighborMapWidth], 0xff, sizeof(U8) * x_span);
+ //LL_INFOS("World Map") << "Loading Block (" << block_x << "," << block_y << ")" << LL_ENDL;
+ LLWorldMapMessage::getInstance()->sendMapBlockRequest(block_x * MAP_BLOCK_SIZE, block_y * MAP_BLOCK_SIZE, (block_x * MAP_BLOCK_SIZE) + MAP_BLOCK_SIZE - 1, (block_y * MAP_BLOCK_SIZE) + MAP_BLOCK_SIZE - 1);
+ mMapBlockLoaded[offset] = true;
}
}
}
+}
- for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
+void LLWorldMap::dump()
+{
+ LL_INFOS("World Map") << "LLWorldMap::dump()" << LL_ENDL;
+ for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
{
- U64 handle = (*it).first;
- //LLSimInfo* info = (*it).second;
-
- U32 x_pos, y_pos;
- from_region_handle(handle, &x_pos, &y_pos);
- x_pos /= REGION_WIDTH_UNITS;
- y_pos /= REGION_WIDTH_UNITS;
-
- S32 index = x_pos - min_x + (mNeighborMapWidth * (y_pos - min_y));
- mTelehubCoverageMap[index] *= mNeighborMap[index];
- }*/
+ LLSimInfo* info = it->second;
+ if (info)
+ {
+ info->dump();
+ }
+ }
}
+
diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h
index 366de8f071..7e37727b86 100644
--- a/indra/newview/llworldmap.h
+++ b/indra/newview/llworldmap.h
@@ -33,203 +33,243 @@
#ifndef LL_LLWORLDMAP_H
#define LL_LLWORLDMAP_H
-#include <map>
-#include <string>
-#include <vector>
+#include "llworldmipmap.h"
#include <boost/function.hpp>
-#include "v3math.h"
#include "v3dmath.h"
-#include "llframetimer.h"
-#include "llmapimagetype.h"
#include "lluuid.h"
#include "llpointer.h"
#include "llsingleton.h"
+#include "llviewerregion.h"
#include "llviewertexture.h"
-#include "lleventinfo.h"
-#include "v3color.h"
-
-class LLMessageSystem;
-
+// Description of objects like hubs, events, land for sale, people and more (TBD).
+// Note: we don't store a "type" in there so we need to store instances of this class in
+// well known objects (i.e. list of objects which type is "well known").
class LLItemInfo
{
public:
- LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id, S32 extra = 0, S32 extra2 = 0);
-
- std::string mName;
- std::string mToolTip;
- LLVector3d mPosGlobal;
- LLUUID mID;
- BOOL mSelected;
- S32 mExtra;
- S32 mExtra2;
- U64 mRegionHandle;
-};
+ LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id);
+
+ // Setters
+ void setTooltip(std::string& tooltip) { mToolTip = tooltip; }
+ void setElevation(F64 z) { mPosGlobal.mdV[VZ] = z; }
+ void setCount(S32 count) { mCount = count; }
+// void setSelected(bool selected) { mSelected = selected; }
+// void setColor(LLColor4 color) { mColor = color; }
+
+ // Accessors
+ const LLVector3d& getGlobalPosition() const { return mPosGlobal; }
+ const std::string& getName() const { return mName; }
+ const std::string& getToolTip() const { return mToolTip; }
+ const LLUUID& getUUID() const { return mID; }
+ S32 getCount() const { return mCount; }
+
+ U64 getRegionHandle() const { return to_region_handle(mPosGlobal); } // Build the handle on the fly
-// Map layers, see indra_constants.h
-// 0 - Prim
-// 1 - Terrain Only
-// 2 - Overlay: Land For Sale
+ bool isName(const std::string& name) const { return (mName == name); } // True if name same as item's name
+// bool isSelected() const { return mSelected; }
+private:
+ std::string mName; // Name of the individual item
+ std::string mToolTip; // Tooltip : typically, something to be displayed to the user when selecting this item
+ LLVector3d mPosGlobal; // Global world position
+ LLUUID mID; // UUID of the item
+ S32 mCount; // Number of elements in item (e.g. people count)
+ // Currently not used but might prove useful one day so we comment out
+// bool mSelected; // Selected or not: updated by the viewer UI, not the simulator or asset DB
+// LLColor4 mColor; // Color of the item
+};
+
+// Info per region
+// Such records are stored in a global map hold by the LLWorldMap and indexed by region handles.
+// To avoid creating too many of them, they are requested in "blocks" corresponding to areas covered by the screen.
+// Unfortunately, when the screen covers the whole world (zoomed out), that can translate in requesting info for
+// every sim on the grid... Not good...
+// To avoid this, the code implements a cut-off threshold for overlay graphics and, therefore, all LLSimInfo.
+// In other words, when zooming out too much, we simply stop requesting LLSimInfo and
+// LLItemInfo and just display the map tiles.
+// As they are stored in different structures (LLSimInfo and LLWorldMipmap), this strategy is now workable.
class LLSimInfo
{
public:
- LLSimInfo();
+ LLSimInfo(U64 handle);
- LLVector3d getGlobalPos(LLVector3 local_pos) const;
+ // Convert local region coordinates into world coordinates
+ LLVector3d getGlobalPos(const LLVector3& local_pos) const;
+ // Get the world coordinates of the SW corner of that region
+ LLVector3d getGlobalOrigin() const;
LLVector3 getLocalPos(LLVector3d global_pos) const;
-public:
- U64 mHandle;
- std::string mName;
-
- F64 mAgentsUpdateTime;
- BOOL mShowAgentLocations; // are agents visible?
+ void clearImage(); // Clears the reference to the Land for sale image for that region
+ void dropImagePriority(); // Drops the boost level of the Land for sale image for that region
+ void updateAgentCount(F64 time); // Send an item request for agent count on that region if time's up
- U8 mAccess;
- U32 mRegionFlags;
- F32 mWaterHeight;
+ // Setters
+ void setName(std::string& name) { mName = name; }
+ void setAccess (U32 accesscode) { mAccess = accesscode; }
+ void setRegionFlags (U32 region_flags) { mRegionFlags = region_flags; }
+ void setLandForSaleImage (LLUUID image_id);
+// void setWaterHeight (F32 water_height) { mWaterHeight = water_height; }
- F32 mAlpha;
+ // Accessors
+ std::string getName() const { return mName; }
+ const std::string getFlagsString() const { return LLViewerRegion::regionFlagsToString(mRegionFlags); }
+ const std::string getAccessString() const { return LLViewerRegion::accessToString((U8)mAccess); }
- // Image ID for the current overlay mode.
- LLUUID mMapImageID[MAP_SIM_IMAGE_TYPES];
+ const S32 getAgentCount() const; // Compute the total agents count
+ LLPointer<LLViewerFetchedTexture> getLandForSaleImage(); // Get the overlay image, fetch it if necessary
- // Hold a reference to the currently displayed image.
- LLPointer<LLViewerFetchedTexture> mCurrentImage;
- LLPointer<LLViewerFetchedTexture> mOverlayImage;
-};
+ bool isName(const std::string& name) const;
+ bool isDown() { return (mAccess == SIM_ACCESS_DOWN); }
+ bool isPG() { return (mAccess <= SIM_ACCESS_PG); }
-#define MAP_BLOCK_RES 256
+ // Debug only
+ void dump() const; // Print the region info to the standard output
-struct LLWorldMapLayer
-{
- BOOL LayerDefined;
- LLPointer<LLViewerFetchedTexture> LayerImage;
- LLUUID LayerImageID;
- LLRect LayerExtents;
+ // Items lists handling
+ typedef std::vector<LLItemInfo> item_info_list_t;
+ void clearItems();
+
+ void insertTeleHub(const LLItemInfo& item) { mTelehubs.push_back(item); }
+ void insertInfoHub(const LLItemInfo& item) { mInfohubs.push_back(item); }
+ void insertPGEvent(const LLItemInfo& item) { mPGEvents.push_back(item); }
+ void insertMatureEvent(const LLItemInfo& item) { mMatureEvents.push_back(item); }
+ void insertAdultEvent(const LLItemInfo& item) { mAdultEvents.push_back(item); }
+ void insertLandForSale(const LLItemInfo& item) { mLandForSale.push_back(item); }
+ void insertLandForSaleAdult(const LLItemInfo& item) { mLandForSaleAdult.push_back(item); }
+ void insertAgentLocation(const LLItemInfo& item);
+
+ const LLSimInfo::item_info_list_t& getTeleHub() const { return mTelehubs; }
+ const LLSimInfo::item_info_list_t& getInfoHub() const { return mInfohubs; }
+ const LLSimInfo::item_info_list_t& getPGEvent() const { return mPGEvents; }
+ const LLSimInfo::item_info_list_t& getMatureEvent() const { return mMatureEvents; }
+ const LLSimInfo::item_info_list_t& getAdultEvent() const { return mAdultEvents; }
+ const LLSimInfo::item_info_list_t& getLandForSale() const { return mLandForSale; }
+ const LLSimInfo::item_info_list_t& getLandForSaleAdult() const { return mLandForSaleAdult; }
+ const LLSimInfo::item_info_list_t& getAgentLocation() const { return mAgentLocations; }
- LLWorldMapLayer() : LayerDefined(FALSE) { }
+private:
+ U64 mHandle; // This is a hash of the X and Y world coordinates of the SW corner of the sim
+ std::string mName; // Region name
+
+ F64 mAgentsUpdateTime; // Time stamp giving the last time the agents information was requested for that region
+ bool mFirstAgentRequest; // Init agent request flag
+
+ U32 mAccess; // Down/up and maturity rating of the region
+ U32 mRegionFlags; // Tell us if the siminfo has been received (if non 0) and what kind of region it is (Sandbox, allow damage)
+ // Currently not used but might prove useful one day so we comment out
+// F32 mWaterHeight; // Water height on the region (not actively used)
+
+ // Handling the "land for sale / land for auction" overlay image
+ LLUUID mMapImageID; // Image ID of the overlay image
+ LLPointer<LLViewerFetchedTexture> mOverlayImage; // Reference to the overlay image
+
+ // Items for this region
+ // Those are data received through item requests (as opposed to block requests for the rest of the data)
+ item_info_list_t mTelehubs; // List of tele hubs in the region
+ item_info_list_t mInfohubs; // List of info hubs in the region
+ item_info_list_t mPGEvents; // List of PG events in the region
+ item_info_list_t mMatureEvents; // List of Mature events in the region
+ item_info_list_t mAdultEvents; // List of Adult events in the region (AO)
+ item_info_list_t mLandForSale; // List of Land for sales in the region
+ item_info_list_t mLandForSaleAdult; // List of Adult Land for sales in the region (AO)
+ item_info_list_t mAgentLocations; // List of agents in the region
};
+// We request region data on the world by "blocks" of (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) regions
+// This is to reduce the number of requests to the asset DB and get things in big "blocks"
+const S32 MAP_MAX_SIZE = 2048;
+const S32 MAP_BLOCK_SIZE = 4;
+const S32 MAP_BLOCK_RES = (MAP_MAX_SIZE / MAP_BLOCK_SIZE);
class LLWorldMap : public LLSingleton<LLWorldMap>
{
public:
- typedef boost::function<void(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)>
- url_callback_t;
-
LLWorldMap();
~LLWorldMap();
- // clears the list
+ // Clear all: list of region info, tiles, blocks and items
void reset();
- // clear the visible items
- void eraseItems();
+ void clearImageRefs(); // Clears the image references
+ void dropImagePriorities(); // Drops the priority of the images being fetched
+ void reloadItems(bool force = false); // Reload the items (people, hub, etc...)
- // Removes references to cached images
- void clearImageRefs();
+ // Region Map access
+ typedef std::map<U64, LLSimInfo*> sim_info_map_t;
+ const LLWorldMap::sim_info_map_t& getRegionMap() const { return mSimInfoMap; }
+ void updateRegions(S32 x0, S32 y0, S32 x1, S32 y1); // Requests region info for a rectangle of regions (in grid coordinates)
- // Clears the flags indicating that we've received sim infos
- // Causes a re-request of the sim info without erasing extisting info
- void clearSimFlags();
+ // Insert a region and items in the map global instance
+ // Note: x_world and y_world in world coordinates (meters)
+ static bool insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 accesscode, U32 region_flags);
+ static bool insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 type, S32 extra, S32 extra2);
- // Returns simulator information, or NULL if out of range
+ // Get info on sims (region) : note that those methods only search the range of loaded sims (the one that are being browsed)
+ // *not* the entire world. So a NULL return does not mean a down or unexisting region, just an out of range region.
LLSimInfo* simInfoFromHandle(const U64 handle);
-
- // Returns simulator information, or NULL if out of range
LLSimInfo* simInfoFromPosGlobal(const LLVector3d& pos_global);
-
- // Returns simulator information for named sim, or NULL if non-existent
LLSimInfo* simInfoFromName(const std::string& sim_name);
- // Gets simulator name for a global position, returns true if it was found
+ // Gets simulator name from a global position, returns true if found
bool simNameFromPosGlobal(const LLVector3d& pos_global, std::string& outSimName );
- // Sets the current layer
- void setCurrentLayer(S32 layer, bool request_layer = false);
-
- void sendMapLayerRequest();
- void sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent = false);
- void sendNamedRegionRequest(std::string region_name);
- void sendNamedRegionRequest(std::string region_name,
- url_callback_t callback,
- const std::string& callback_url,
- bool teleport);
- void sendHandleRegionRequest(U64 region_handle,
- url_callback_t callback,
- const std::string& callback_url,
- bool teleport);
- void sendItemRequest(U32 type, U64 handle = 0);
-
- static void processMapLayerReply(LLMessageSystem*, void**);
- static void processMapBlockReply(LLMessageSystem*, void**);
- static void processMapItemReply(LLMessageSystem*, void**);
-
- void dump();
-
- // Extend the bounding box of the list of simulators. Returns true
- // if the extents changed.
- BOOL extendAABB(U32 x_min, U32 y_min, U32 x_max, U32 y_max);
-
- // build coverage maps for telehub region visualization
- void updateTelehubCoverage();
- BOOL coveredByTelehub(LLSimInfo* infop);
-
- // Bounds of the world, in meters
- U32 getWorldWidth() const;
- U32 getWorldHeight() const;
-public:
- // Map from region-handle to simulator info
- typedef std::map<U64, LLSimInfo*> sim_info_map_t;
- sim_info_map_t mSimInfoMap;
+ // Debug only
+ void dump(); // Print the world info to the standard output
- BOOL mIsTrackingUnknownLocation, mInvalidLocation, mIsTrackingDoubleClick, mIsTrackingCommit;
- LLVector3d mUnknownLocation;
+ // Track handling
+ void cancelTracking() { mIsTrackingLocation = false; mIsTrackingFound = false; mIsInvalidLocation = false; mIsTrackingDoubleClick = false; mIsTrackingCommit = false; }
- bool mRequestLandForSale;
+ void setTracking(const LLVector3d& loc) { mIsTrackingLocation = true; mTrackingLocation = loc; mIsTrackingFound = false; mIsInvalidLocation = false; mIsTrackingDoubleClick = false; mIsTrackingCommit = false;}
+ void setTrackingInvalid() { mIsTrackingFound = true; mIsInvalidLocation = true; }
+ void setTrackingValid() { mIsTrackingFound = true; mIsInvalidLocation = false; }
+ void setTrackingDoubleClick() { mIsTrackingDoubleClick = true; }
+ void setTrackingCommit() { mIsTrackingCommit = true; }
- typedef std::vector<LLItemInfo> item_info_list_t;
- item_info_list_t mTelehubs;
- item_info_list_t mInfohubs;
- item_info_list_t mPGEvents;
- item_info_list_t mMatureEvents;
- item_info_list_t mAdultEvents;
- item_info_list_t mLandForSale;
- item_info_list_t mLandForSaleAdult;
-
- std::map<U64,S32> mNumAgents;
-
- typedef std::map<U64, item_info_list_t> agent_list_map_t;
- agent_list_map_t mAgentLocationsMap;
-
- std::vector<LLWorldMapLayer> mMapLayers[MAP_SIM_IMAGE_TYPES];
- BOOL mMapLoaded[MAP_SIM_IMAGE_TYPES];
- BOOL * mMapBlockLoaded[MAP_SIM_IMAGE_TYPES];
- S32 mCurrentMap;
-
- // AABB of the list of simulators
- U32 mMinX;
- U32 mMaxX;
- U32 mMinY;
- U32 mMaxY;
-
- U8* mNeighborMap;
- U8* mTelehubCoverageMap;
- S32 mNeighborMapWidth;
- S32 mNeighborMapHeight;
+ bool isTracking() { return mIsTrackingLocation; }
+ bool isTrackingValidLocation() { return mIsTrackingFound && !mIsInvalidLocation; }
+ bool isTrackingInvalidLocation() { return mIsTrackingFound && mIsInvalidLocation; }
+ bool isTrackingDoubleClick() { return mIsTrackingDoubleClick; }
+ bool isTrackingCommit() { return mIsTrackingCommit; }
+ bool isTrackingInRectangle(F64 x0, F64 y0, F64 x1, F64 y1);
+
+ LLVector3d getTrackedPositionGlobal() const { return mTrackingLocation; }
+
+ // World Mipmap delegation: currently used when drawing the mipmap
+ void equalizeBoostLevels();
+ LLPointer<LLViewerFetchedTexture> getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load = true) { return mWorldMipmap.getObjectsTile(grid_x, grid_y, level, load); }
private:
- LLTimer mRequestTimer;
-
- // search for named region for url processing
- std::string mSLURLRegionName;
- U64 mSLURLRegionHandle;
- std::string mSLURL;
- url_callback_t mSLURLCallback;
- bool mSLURLTeleport;
+ bool clearItems(bool force = false); // Clears the item lists
+ void clearSimFlags(); // Clears the block flags indicating that we've already requested region infos
+
+ // Create a region record corresponding to the handle, insert it in the region map and returns a pointer
+ LLSimInfo* createSimInfoFromHandle(const U64 handle);
+
+ // Map from region-handle to region info
+ sim_info_map_t mSimInfoMap;
+
+ // Holds the tiled mipmap of the world. This is the structure that contains the images used for rendering.
+ LLWorldMipmap mWorldMipmap;
+
+ // The World is divided in "blocks" of (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) regions that get requested at once.
+ // This boolean table avoids "blocks" to be requested multiple times.
+ // Issue: Not sure this scheme is foolproof though as I've seen
+ // cases where a block is never retrieved and, because of this boolean being set, never re-requested
+ bool * mMapBlockLoaded; // Telling us if the block of regions has been requested or not
+
+ // Track location data : used while there's nothing tracked yet by LLTracker
+ bool mIsTrackingLocation; // True when we're tracking a point
+ bool mIsTrackingFound; // True when the tracking position has been found, valid or not
+ bool mIsInvalidLocation; // The region is down or the location does not correspond to an existing region
+ bool mIsTrackingDoubleClick; // User double clicked to set the location (i.e. teleport when found please...)
+ bool mIsTrackingCommit; // User used the search or landmark fields to set the location
+ LLVector3d mTrackingLocation; // World global position being tracked
+
+ // General grid items request timing flags (used for events,hubs and land for sale)
+ LLTimer mRequestTimer;
+ bool mFirstRequest;
};
#endif
diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp
new file mode 100644
index 0000000000..6a074d9697
--- /dev/null
+++ b/indra/newview/llworldmapmessage.cpp
@@ -0,0 +1,261 @@
+/**
+ * @file llworldmapmessage.cpp
+ * @brief Handling of the messages to the DB made by and for the world map.
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llworldmapmessage.h"
+
+#include "llworldmap.h"
+#include "llagent.h"
+#include "llfloaterworldmap.h"
+
+const U32 LAYER_FLAG = 2;
+
+//---------------------------------------------------------------------------
+// World Map Message Handling
+//---------------------------------------------------------------------------
+
+LLWorldMapMessage::LLWorldMapMessage() :
+ mSLURLRegionName(),
+ mSLURLRegionHandle(0),
+ mSLURL(),
+ mSLURLCallback(0),
+ mSLURLTeleport(false)
+{
+}
+
+LLWorldMapMessage::~LLWorldMapMessage()
+{
+}
+
+void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle)
+{
+ //LL_INFOS("World Map") << "Send item request : type = " << type << LL_ENDL;
+ LLMessageSystem* msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_MapItemRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addU32Fast(_PREHASH_Flags, LAYER_FLAG);
+ msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
+ msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
+
+ msg->nextBlockFast(_PREHASH_RequestData);
+ msg->addU32Fast(_PREHASH_ItemType, type);
+ msg->addU64Fast(_PREHASH_RegionHandle, handle); // If zero, filled in on sim
+
+ gAgent.sendReliableMessage();
+}
+
+void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name)
+{
+ //LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL;
+ LLMessageSystem* msg = gMessageSystem;
+
+ // Request for region data
+ msg->newMessageFast(_PREHASH_MapNameRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addU32Fast(_PREHASH_Flags, LAYER_FLAG);
+ msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
+ msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
+ msg->nextBlockFast(_PREHASH_NameData);
+ msg->addStringFast(_PREHASH_Name, region_name);
+ gAgent.sendReliableMessage();
+}
+
+void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name,
+ url_callback_t callback,
+ const std::string& callback_url,
+ bool teleport) // immediately teleport when result returned
+{
+ //LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL;
+ mSLURLRegionName = region_name;
+ mSLURLRegionHandle = 0;
+ mSLURL = callback_url;
+ mSLURLCallback = callback;
+ mSLURLTeleport = teleport;
+
+ sendNamedRegionRequest(region_name);
+}
+
+void LLWorldMapMessage::sendHandleRegionRequest(U64 region_handle,
+ url_callback_t callback,
+ const std::string& callback_url,
+ bool teleport) // immediately teleport when result returned
+{
+ //LL_INFOS("World Map") << "LLWorldMap::sendHandleRegionRequest()" << LL_ENDL;
+ mSLURLRegionName.clear();
+ mSLURLRegionHandle = region_handle;
+ mSLURL = callback_url;
+ mSLURLCallback = callback;
+ mSLURLTeleport = teleport;
+
+ U32 global_x;
+ U32 global_y;
+ from_region_handle(region_handle, &global_x, &global_y);
+ U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS);
+ U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS);
+
+ sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true);
+}
+
+void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent)
+{
+ //LL_INFOS("World Map") << "LLWorldMap::sendMapBlockRequest()" << ", min = (" << min_x << ", " << min_y << "), max = (" << max_x << ", " << max_y << "), nonexistent = " << return_nonexistent << LL_ENDL;
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_MapBlockRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ U32 flags = LAYER_FLAG;
+ flags |= (return_nonexistent ? 0x10000 : 0);
+ msg->addU32Fast(_PREHASH_Flags, flags);
+ msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim
+ msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim
+ msg->nextBlockFast(_PREHASH_PositionData);
+ msg->addU16Fast(_PREHASH_MinX, min_x);
+ msg->addU16Fast(_PREHASH_MinY, min_y);
+ msg->addU16Fast(_PREHASH_MaxX, max_x);
+ msg->addU16Fast(_PREHASH_MaxY, max_y);
+ gAgent.sendReliableMessage();
+}
+
+// public static
+void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**)
+{
+ U32 agent_flags;
+ msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
+
+ // There's only one flag that we ever use here
+ if (agent_flags != LAYER_FLAG)
+ {
+ llwarns << "Invalid map image type returned! layer = " << agent_flags << llendl;
+ return;
+ }
+
+ S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data);
+ //LL_INFOS("World Map") << "LLWorldMap::processMapBlockReply(), num_blocks = " << num_blocks << LL_ENDL;
+
+ bool found_null_sim = false;
+
+ for (S32 block=0; block<num_blocks; ++block)
+ {
+ U16 x_regions;
+ U16 y_regions;
+ std::string name;
+ U8 accesscode;
+ U32 region_flags;
+// U8 water_height;
+// U8 agents;
+ LLUUID image_id;
+ msg->getU16Fast(_PREHASH_Data, _PREHASH_X, x_regions, block);
+ msg->getU16Fast(_PREHASH_Data, _PREHASH_Y, y_regions, block);
+ msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block);
+ msg->getU8Fast(_PREHASH_Data, _PREHASH_Access, accesscode, block);
+ msg->getU32Fast(_PREHASH_Data, _PREHASH_RegionFlags, region_flags, block);
+// msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block);
+// msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block);
+ msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block);
+
+ U32 x_world = (U32)(x_regions) * REGION_WIDTH_UNITS;
+ U32 y_world = (U32)(y_regions) * REGION_WIDTH_UNITS;
+
+ // Insert that region in the world map, if failure, flag it as a "null_sim"
+ if (!(LLWorldMap::getInstance()->insertRegion(x_world, y_world, name, image_id, (U32)accesscode, region_flags)))
+ {
+ found_null_sim = true;
+ }
+
+ // If we hit a valid tracking location, do what needs to be done app level wise
+ if (LLWorldMap::getInstance()->isTrackingValidLocation())
+ {
+ LLVector3d pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal();
+ if (LLWorldMap::getInstance()->isTrackingDoubleClick())
+ {
+ // Teleport if the user double clicked
+ gAgent.teleportViaLocation(pos_global);
+ }
+ // Update the "real" tracker information
+ gFloaterWorldMap->trackLocation(pos_global);
+ }
+
+ // Handle the SLURL callback if any
+ if(LLWorldMapMessage::getInstance()->mSLURLCallback != NULL)
+ {
+ U64 handle = to_region_handle(x_world, y_world);
+ // Check if we reached the requested region
+ if ((LLStringUtil::compareInsensitive(LLWorldMapMessage::getInstance()->mSLURLRegionName, name)==0)
+ || (LLWorldMapMessage::getInstance()->mSLURLRegionHandle == handle))
+ {
+ url_callback_t callback = LLWorldMapMessage::getInstance()->mSLURLCallback;
+
+ LLWorldMapMessage::getInstance()->mSLURLCallback = NULL;
+ LLWorldMapMessage::getInstance()->mSLURLRegionName.clear();
+ LLWorldMapMessage::getInstance()->mSLURLRegionHandle = 0;
+
+ callback(handle, LLWorldMapMessage::getInstance()->mSLURL, image_id, LLWorldMapMessage::getInstance()->mSLURLTeleport);
+ }
+ }
+ }
+ // Tell the UI to update itself
+ gFloaterWorldMap->updateSims(found_null_sim);
+}
+
+// public static
+void LLWorldMapMessage::processMapItemReply(LLMessageSystem* msg, void**)
+{
+ //LL_INFOS("World Map") << "LLWorldMap::processMapItemReply()" << LL_ENDL;
+ U32 type;
+ msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type);
+
+ S32 num_blocks = msg->getNumberOfBlocks("Data");
+
+ for (S32 block=0; block<num_blocks; ++block)
+ {
+ U32 X, Y;
+ std::string name;
+ S32 extra, extra2;
+ LLUUID uuid;
+ msg->getU32Fast(_PREHASH_Data, _PREHASH_X, X, block);
+ msg->getU32Fast(_PREHASH_Data, _PREHASH_Y, Y, block);
+ msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block);
+ msg->getUUIDFast(_PREHASH_Data, _PREHASH_ID, uuid, block);
+ msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra, extra, block);
+ msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra2, extra2, block);
+
+ LLWorldMap::getInstance()->insertItem(X, Y, name, uuid, type, extra, extra2);
+ }
+}
+
diff --git a/indra/newview/llworldmapmessage.h b/indra/newview/llworldmapmessage.h
new file mode 100644
index 0000000000..2c8fedcb10
--- /dev/null
+++ b/indra/newview/llworldmapmessage.h
@@ -0,0 +1,83 @@
+/**
+ * @file llworldmapmessage.h
+ * @brief Handling of the messages to the DB made by and for the world map.
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLWORLDMAPMESSAGE_H
+#define LL_LLWORLDMAPMESSAGE_H
+
+// Handling of messages (send and process) as well as SLURL callback if necessary
+class LLMessageSystem;
+
+class LLWorldMapMessage : public LLSingleton<LLWorldMapMessage>
+{
+public:
+ typedef boost::function<void(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)>
+ url_callback_t;
+
+ LLWorldMapMessage();
+ ~LLWorldMapMessage();
+
+ // Process incoming answers to map stuff requests
+ static void processMapBlockReply(LLMessageSystem*, void**);
+ static void processMapItemReply(LLMessageSystem*, void**);
+
+ // Request data for all regions in a rectangular area. Coordinates in grids (i.e. meters / 256).
+ void sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent = false);
+
+ // Various methods to request LLSimInfo data to the simulator and asset DB
+ void sendNamedRegionRequest(std::string region_name);
+ void sendNamedRegionRequest(std::string region_name,
+ url_callback_t callback,
+ const std::string& callback_url,
+ bool teleport);
+ void sendHandleRegionRequest(U64 region_handle,
+ url_callback_t callback,
+ const std::string& callback_url,
+ bool teleport);
+
+ // Request item data for regions
+ // Note: the handle works *only* when requesting agent count (type = MAP_ITEM_AGENT_LOCATIONS). In that case,
+ // the request will actually be transitting through the spaceserver (all that is done on the sim).
+ // All other values of type do create a global grid request to the asset DB. So no need to try to get, say,
+ // the events for one particular region. For such a request, the handle is ignored.
+ void sendItemRequest(U32 type, U64 handle = 0);
+
+private:
+ // Search for region (by name or handle) for SLURL processing and teleport
+ // None of this relies explicitly on the LLWorldMap instance so better handle it here
+ std::string mSLURLRegionName;
+ U64 mSLURLRegionHandle;
+ std::string mSLURL;
+ url_callback_t mSLURLCallback;
+ bool mSLURLTeleport;
+};
+
+#endif // LL_LLWORLDMAPMESSAGE_H
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 3aad5c7378..ede9ddb837 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -46,7 +46,6 @@
#include "llagent.h"
#include "llcallingcard.h"
#include "llviewercontrol.h"
-#include "llcylinder.h"
#include "llfloatermap.h"
#include "llfloaterworldmap.h"
#include "llfocusmgr.h"
@@ -57,25 +56,29 @@
#include "llviewercamera.h"
#include "llviewertexture.h"
#include "llviewertexturelist.h"
-#include "llviewermenu.h"
-#include "llviewerparceloverlay.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
-#include "llworldmap.h"
-#include "lltexturefetch.h"
-#include "llappviewer.h" // Only for constants!
#include "lltrans.h"
#include "llglheaders.h"
+// Basically a C++ implementation of the OCEAN_COLOR defined in mapstitcher.py
+// Please ensure consistency between those 2 files (TODO: would be better to get that color from an asset source...)
+// # Constants
+// OCEAN_COLOR = "#1D475F"
+const F32 OCEAN_RED = (F32)(0x1D)/255.f;
+const F32 OCEAN_GREEN = (F32)(0x47)/255.f;
+const F32 OCEAN_BLUE = (F32)(0x5F)/255.f;
+
const F32 GODLY_TELEPORT_HEIGHT = 200.f;
const S32 SCROLL_HINT_WIDTH = 65;
const F32 BIG_DOT_RADIUS = 5.f;
BOOL LLWorldMapView::sHandledLastClick = FALSE;
-LLUIImagePtr LLWorldMapView::sAvatarYouSmallImage = NULL;
LLUIImagePtr LLWorldMapView::sAvatarSmallImage = NULL;
-LLUIImagePtr LLWorldMapView::sAvatarLargeImage = NULL;
+LLUIImagePtr LLWorldMapView::sAvatarYouImage = NULL;
+LLUIImagePtr LLWorldMapView::sAvatarYouLargeImage = NULL;
+LLUIImagePtr LLWorldMapView::sAvatarLevelImage = NULL;
LLUIImagePtr LLWorldMapView::sAvatarAboveImage = NULL;
LLUIImagePtr LLWorldMapView::sAvatarBelowImage = NULL;
@@ -93,35 +96,34 @@ LLUIImagePtr LLWorldMapView::sClassifiedsImage = NULL;
LLUIImagePtr LLWorldMapView::sForSaleImage = NULL;
LLUIImagePtr LLWorldMapView::sForSaleAdultImage = NULL;
-F32 LLWorldMapView::sThresholdA = 48.f;
-F32 LLWorldMapView::sThresholdB = 96.f;
F32 LLWorldMapView::sPanX = 0.f;
F32 LLWorldMapView::sPanY = 0.f;
F32 LLWorldMapView::sTargetPanX = 0.f;
F32 LLWorldMapView::sTargetPanY = 0.f;
S32 LLWorldMapView::sTrackingArrowX = 0;
S32 LLWorldMapView::sTrackingArrowY = 0;
-F32 LLWorldMapView::sPixelsPerMeter = 1.f;
-F32 CONE_SIZE = 0.6f;
+bool LLWorldMapView::sVisibleTilesLoaded = false;
+F32 LLWorldMapView::sMapScale = 128.f;
std::map<std::string,std::string> LLWorldMapView::sStringsMap;
-#define SIM_NULL_MAP_SCALE 1 // width in pixels, where we start drawing "null" sims
-#define SIM_MAP_AGENT_SCALE 2 // width in pixels, where we start drawing agents
-#define SIM_MAP_SCALE 1 // width in pixels, where we start drawing sim tiles
-
-// Updates for agent locations.
-#define AGENTS_UPDATE_TIME 60.0 // in seconds
+// Fetch and draw info thresholds
+const F32 DRAW_TEXT_THRESHOLD = 96.f; // Don't draw text under that resolution value (res = width region in meters)
+const S32 DRAW_SIMINFO_THRESHOLD = 3; // Max level for which we load or display sim level information (level in LLWorldMipmap sense)
+const S32 DRAW_LANDFORSALE_THRESHOLD = 2; // Max level for which we load or display land for sale picture data (level in LLWorldMipmap sense)
+// When on, draw an outline for each mipmap tile gotten from S3
+#define DEBUG_DRAW_TILE 0
void LLWorldMapView::initClass()
{
- sAvatarYouSmallImage = LLUI::getUIImage("map_avatar_you_8.tga");
- sAvatarSmallImage = LLUI::getUIImage("map_avatar_8.tga");
- sAvatarLargeImage = LLUI::getUIImage("map_avatar_16.tga");
- sAvatarAboveImage = LLUI::getUIImage("map_avatar_above_8.tga");
- sAvatarBelowImage = LLUI::getUIImage("map_avatar_below_8.tga");
+ sAvatarSmallImage = LLUI::getUIImage("map_avatar_8.tga");
+ sAvatarYouImage = LLUI::getUIImage("map_avatar_16.tga");
+ sAvatarYouLargeImage = LLUI::getUIImage("map_avatar_you_32.tga");
+ sAvatarLevelImage = LLUI::getUIImage("map_avatar_32.tga");
+ sAvatarAboveImage = LLUI::getUIImage("map_avatar_above_32.tga");
+ sAvatarBelowImage = LLUI::getUIImage("map_avatar_below_32.tga");
sHomeImage = LLUI::getUIImage("map_home.tga");
sTelehubImage = LLUI::getUIImage("map_telehub.tga");
@@ -145,9 +147,10 @@ void LLWorldMapView::initClass()
// static
void LLWorldMapView::cleanupClass()
{
- sAvatarYouSmallImage = NULL;
sAvatarSmallImage = NULL;
- sAvatarLargeImage = NULL;
+ sAvatarYouImage = NULL;
+ sAvatarYouLargeImage = NULL;
+ sAvatarLevelImage = NULL;
sAvatarAboveImage = NULL;
sAvatarBelowImage = NULL;
@@ -167,7 +170,7 @@ void LLWorldMapView::cleanupClass()
LLWorldMapView::LLWorldMapView()
: LLPanel(),
- mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ),
+ mBackgroundColor( LLColor4( OCEAN_RED, OCEAN_GREEN, OCEAN_BLUE, 1.f ) ),
mItemPicked(FALSE),
mPanning( FALSE ),
mMouseDownPanX( 0 ),
@@ -176,7 +179,8 @@ LLWorldMapView::LLWorldMapView()
mMouseDownY( 0 ),
mSelectIDStart(0)
{
- sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
+ //LL_INFOS("World Map") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
+
clearLastClick();
}
@@ -215,6 +219,7 @@ BOOL LLWorldMapView::postBuild()
LLWorldMapView::~LLWorldMapView()
{
+ //LL_INFOS("World Map") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL;
cleanupTextures();
}
@@ -228,14 +233,14 @@ void LLWorldMapView::cleanupTextures()
// static
void LLWorldMapView::setScale( F32 scale )
{
- if (scale != gMapScale)
+ if (scale != sMapScale)
{
- F32 old_scale = gMapScale;
+ F32 old_scale = sMapScale;
- gMapScale = scale;
- if (gMapScale == 0.f)
+ sMapScale = scale;
+ if (sMapScale <= 0.f)
{
- gMapScale = 0.1f;
+ sMapScale = 0.1f;
}
F32 ratio = (scale / old_scale);
@@ -243,8 +248,7 @@ void LLWorldMapView::setScale( F32 scale )
sPanY *= ratio;
sTargetPanX = sPanX;
sTargetPanY = sPanY;
-
- sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
+ sVisibleTilesLoaded = false;
}
}
@@ -256,6 +260,7 @@ void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y )
sPanY += delta_y;
sTargetPanX = sPanX;
sTargetPanY = sPanY;
+ sVisibleTilesLoaded = false;
}
@@ -269,18 +274,22 @@ void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
sPanX = sTargetPanX;
sPanY = sTargetPanY;
}
+ sVisibleTilesLoaded = false;
}
+bool LLWorldMapView::showRegionInfo()
+{
+ return (LLWorldMipmap::scaleToLevel(sMapScale) <= DRAW_SIMINFO_THRESHOLD ? true : false);
+}
///////////////////////////////////////////////////////////////////////////////////
// HELPERS
BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
{
- return ((region && info) && (info->mName == region->getName()));
+ return (region && info && info->isName(region->getName()));
}
-
///////////////////////////////////////////////////////////////////////////////////
void LLWorldMapView::draw()
@@ -292,7 +301,7 @@ void LLWorldMapView::draw()
F64 current_time = LLTimer::getElapsedSeconds();
mVisibleRegions.clear();
-
+
// animate pan if necessary
sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
@@ -303,10 +312,12 @@ void LLWorldMapView::draw()
const F32 half_height = F32(height) / 2.0f;
LLVector3d camera_global = gAgent.getCameraPositionGlobal();
+ S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+
LLLocalClipRect clip(getLocalRect());
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
+
glMatrixMode(GL_MODELVIEW);
// Clear the background alpha to 0
@@ -319,307 +330,58 @@ void LLWorldMapView::draw()
}
gGL.flush();
+
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
gGL.setColorMask(true, true);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- F32 layer_alpha = 1.f;
-
- // Draw one image per layer
- for (U32 layer_idx=0; layer_idx<LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap].size(); ++layer_idx)
- {
- if (!LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx].LayerDefined)
- {
- continue;
- }
- LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx];
- LLViewerFetchedTexture *current_image = layer->LayerImage;
-
- if (current_image->isMissingAsset())
- {
- continue; // better to draw nothing than the missing asset image
- }
-
- LLVector3d origin_global((F64)layer->LayerExtents.mLeft * REGION_WIDTH_METERS, (F64)layer->LayerExtents.mBottom * REGION_WIDTH_METERS, 0.f);
-
- // Find x and y position relative to camera's center.
- LLVector3d rel_region_pos = origin_global - camera_global;
- F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale;
- F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale;
-
- F32 pix_width = gMapScale*(layer->LayerExtents.getWidth() + 1);
- F32 pix_height = gMapScale*(layer->LayerExtents.getHeight() + 1);
-
- // When the view isn't panned, 0,0 = center of rectangle
- F32 bottom = sPanY + half_height + relative_y;
- F32 left = sPanX + half_width + relative_x;
- F32 top = bottom + pix_height;
- F32 right = left + pix_width;
- F32 pixel_area = pix_width*pix_height;
- // discard layers that are outside the rectangle
- // and discard small layers
- if (top < 0.f ||
- bottom > height ||
- right < 0.f ||
- left > width ||
- (pixel_area < 4*4))
- {
- current_image->setBoostLevel(0);
- continue;
- }
-
- current_image->setBoostLevel(LLViewerTexture::BOOST_MAP_LAYER);
- current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY]));
-
- if (!current_image->hasGLTexture())
- {
- continue; // better to draw nothing than the default image
- }
-
-// LLTextureView::addDebugImage(current_image);
-
- // Draw using the texture. If we don't clamp we get artifact at
- // the edge.
- gGL.getTexUnit(0)->bind(current_image);
-
- // Draw map image into RGB
- //gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- gGL.flush();
- gGL.setColorMask(true, false);
- gGL.color4f(1.f, 1.f, 1.f, layer_alpha);
-
- gGL.begin(LLRender::QUADS);
- gGL.texCoord2f(0.0f, 1.0f);
- gGL.vertex3f(left, top, -1.0f);
- gGL.texCoord2f(0.0f, 0.0f);
- gGL.vertex3f(left, bottom, -1.0f);
- gGL.texCoord2f(1.0f, 0.0f);
- gGL.vertex3f(right, bottom, -1.0f);
- gGL.texCoord2f(1.0f, 1.0f);
- gGL.vertex3f(right, top, -1.0f);
- gGL.end();
-
- // draw an alpha of 1 where the sims are visible
- gGL.flush();
- gGL.setColorMask(false, true);
- gGL.color4f(1.f, 1.f, 1.f, 1.f);
-
- gGL.begin(LLRender::QUADS);
- gGL.texCoord2f(0.0f, 1.0f);
- gGL.vertex2f(left, top);
- gGL.texCoord2f(0.0f, 0.0f);
- gGL.vertex2f(left, bottom);
- gGL.texCoord2f(1.0f, 0.0f);
- gGL.vertex2f(right, bottom);
- gGL.texCoord2f(1.0f, 1.0f);
- gGL.vertex2f(right, top);
- gGL.end();
- }
+#if 1
+ // Draw the image tiles
+ drawMipmap(width, height);
gGL.flush();
+
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
gGL.setColorMask(true, true);
- // there used to be an #if 1 here, but it was uncommented; perhaps marking a block of code?
- F32 sim_alpha = 1.f;
-
- // Draw one image per region, centered on the camera position.
- const S32 MAX_SIMULTANEOUS_TEX = 100;
- const S32 MAX_REQUEST_PER_TICK = 5;
- const S32 MIN_REQUEST_PER_TICK = 1;
- S32 textures_requested_this_tick = 0;
-
- for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin();
- it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
+ // Draw per sim overlayed information (names, mature, offline...)
+ for (LLWorldMap::sim_info_map_t::const_iterator it = LLWorldMap::getInstance()->getRegionMap().begin();
+ it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
{
- U64 handle = (*it).first;
- LLSimInfo* info = (*it).second;
+ U64 handle = it->first;
+ LLSimInfo* info = it->second;
- LLViewerFetchedTexture* simimage = info->mCurrentImage;
- LLViewerFetchedTexture* overlayimage = info->mOverlayImage;
-
- if (gMapScale < SIM_MAP_SCALE)
- {
- if (simimage != NULL) simimage->setBoostLevel(0);
- if (overlayimage != NULL) overlayimage->setBoostLevel(0);
- continue;
- }
-
LLVector3d origin_global = from_region_handle(handle);
- LLVector3d camera_global = gAgent.getCameraPositionGlobal();
// Find x and y position relative to camera's center.
LLVector3d rel_region_pos = origin_global - camera_global;
- F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale;
- F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale;
+ F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * sMapScale;
+ F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * sMapScale;
+ // Coordinates of the sim in pixels in the UI panel
// When the view isn't panned, 0,0 = center of rectangle
- F32 bottom = sPanY + half_height + relative_y;
- F32 left = sPanX + half_width + relative_x;
- F32 top = bottom + gMapScale ;
- F32 right = left + gMapScale ;
-
- // Switch to world map texture (if available for this region) if either:
- // 1. Tiles are zoomed out small enough, or
- // 2. Sim's texture has not been loaded yet
- F32 map_scale_cutoff = SIM_MAP_SCALE;
- if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0)
- {
- map_scale_cutoff = SIM_NULL_MAP_SCALE;
- }
-
- info->mShowAgentLocations = (gMapScale >= SIM_MAP_AGENT_SCALE);
-
- bool sim_visible =
- (gMapScale >= map_scale_cutoff) &&
- (simimage != NULL) &&
- (simimage->hasGLTexture());
-
- if (sim_visible)
- {
- // Fade in
- if (info->mAlpha < 0.0f)
- info->mAlpha = 1.f; // don't fade initially
- else
- info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f));
- }
- else
- {
- // Fade out
- if (info->mAlpha < 0.0f)
- info->mAlpha = 0.f; // don't fade initially
- else
- info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
- }
-
- // discard regions that are outside the rectangle
- // and discard small regions
- if (top < 0.f ||
- bottom > height ||
- right < 0.f ||
- left > width )
+ F32 bottom = sPanY + half_height + relative_y;
+ F32 left = sPanX + half_width + relative_x;
+ F32 top = bottom + sMapScale ;
+ F32 right = left + sMapScale ;
+
+ // Discard if region is outside the screen rectangle (not visible on screen)
+ if ((top < 0.f) || (bottom > height) ||
+ (right < 0.f) || (left > width) )
{
- if (simimage != NULL) simimage->setBoostLevel(0);
- if (overlayimage != NULL) overlayimage->setBoostLevel(0);
+ // Drop the "land for sale" fetching priority since it's outside the view rectangle
+ info->dropImagePriority();
continue;
}
- if (info->mCurrentImage.isNull())
- {
- if ((textures_requested_this_tick < MIN_REQUEST_PER_TICK) ||
- ((LLAppViewer::getTextureFetch()->getNumRequests() < MAX_SIMULTANEOUS_TEX) &&
- (textures_requested_this_tick < MAX_REQUEST_PER_TICK)))
- {
- textures_requested_this_tick++;
- info->mCurrentImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
- info->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
- simimage = info->mCurrentImage;
- gGL.getTexUnit(0)->bind(simimage);
- }
- }
- if (info->mOverlayImage.isNull() && info->mMapImageID[2].notNull())
- {
- if ((textures_requested_this_tick < MIN_REQUEST_PER_TICK) ||
- ((LLAppViewer::getTextureFetch()->getNumRequests() < MAX_SIMULTANEOUS_TEX) &&
- (textures_requested_this_tick < MAX_REQUEST_PER_TICK)))
- {
- textures_requested_this_tick++;
- info->mOverlayImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
- info->mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
- overlayimage = info->mOverlayImage;
- gGL.getTexUnit(0)->bind(overlayimage);
- }
- }
-
+ // This list is used by other methods to know which regions are indeed displayed on screen
mVisibleRegions.push_back(handle);
- // See if the agents need updating
- if (current_time - info->mAgentsUpdateTime > AGENTS_UPDATE_TIME)
- {
- LLWorldMap::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle);
- info->mAgentsUpdateTime = current_time;
- }
-
- // Bias the priority escalation for images nearer
- LLVector3d center_global = origin_global;
- center_global.mdV[VX] += 128.0;
- center_global.mdV[VY] += 128.0;
-
- S32 draw_size = llround(gMapScale);
- if (simimage != NULL)
- {
- simimage->setBoostLevel(LLViewerTexture::BOOST_MAP);
- simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
- }
- if (overlayimage != NULL)
+ // Update the agent count for that region if we're not too zoomed out already
+ if (level <= DRAW_SIMINFO_THRESHOLD)
{
- overlayimage->setBoostLevel(LLViewerTexture::BOOST_MAP);
- overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
- }
-
-// LLTextureView::addDebugImage(simimage);
-
- if (sim_visible && info->mAlpha > 0.001f)
- {
- // Draw using the texture. If we don't clamp we get artifact at
- // the edge.
- LLGLSUIDefault gls_ui;
- if (simimage != NULL)
- gGL.getTexUnit(0)->bind(simimage);
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- F32 alpha = sim_alpha * info->mAlpha;
- gGL.color4f(1.f, 1.0f, 1.0f, alpha);
-
- gGL.begin(LLRender::QUADS);
- gGL.texCoord2f(0.f, 1.f);
- gGL.vertex3f(left, top, 0.f);
- gGL.texCoord2f(0.f, 0.f);
- gGL.vertex3f(left, bottom, 0.f);
- gGL.texCoord2f(1.f, 0.f);
- gGL.vertex3f(right, bottom, 0.f);
- gGL.texCoord2f(1.f, 1.f);
- gGL.vertex3f(right, top, 0.f);
- gGL.end();
-
- if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->hasGLTexture())
- {
- gGL.getTexUnit(0)->bind(overlayimage);
- gGL.color4f(1.f, 1.f, 1.f, alpha);
- gGL.begin(LLRender::QUADS);
- gGL.texCoord2f(0.f, 1.f);
- gGL.vertex3f(left, top, -0.5f);
- gGL.texCoord2f(0.f, 0.f);
- gGL.vertex3f(left, bottom, -0.5f);
- gGL.texCoord2f(1.f, 0.f);
- gGL.vertex3f(right, bottom, -0.5f);
- gGL.texCoord2f(1.f, 1.f);
- gGL.vertex3f(right, top, -0.5f);
- gGL.end();
- }
-
- if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0)
- {
- // draw an alpha of 1 where the sims are visible (except NULL sims)
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- gGL.setColorMask(false, true);
- gGL.color4f(1.f, 1.f, 1.f, 1.f);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.begin(LLRender::QUADS);
- gGL.vertex2f(left, top);
- gGL.vertex2f(left, bottom);
- gGL.vertex2f(right, bottom);
- gGL.vertex2f(right, top);
- gGL.end();
-
- gGL.flush();
- gGL.setColorMask(true, true);
- }
+ info->updateAgentCount(current_time);
}
- if (info->mAccess == SIM_ACCESS_DOWN)
+ if (info->isDown())
{
// Draw a transparent red square over down sims
gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_SOURCE_ALPHA);
@@ -633,18 +395,15 @@ void LLWorldMapView::draw()
gGL.vertex2f(right, top);
gGL.end();
}
-
- // As part of the AO project, we no longer want to draw access indicators;
- // it's too complicated to get all the rules straight and will only
+ // As part of the AO project, we no longer want to draw access indicators;
+ // it's too complicated to get all the rules straight and will only
// cause confusion.
/**********************
- // If this is mature, and you are not, draw a line across it
- if (info->mAccess != SIM_ACCESS_DOWN
- && info->mAccess > SIM_ACCESS_PG
- && gAgent.isTeen())
+ else if (!info->isPG() && gAgent.isTeen())
{
+ // If this is a mature region, and you are not, draw a line across it
gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
-
+
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color3f(1.f, 0.f, 0.f);
gGL.begin(LLRender::LINES);
@@ -655,68 +414,67 @@ void LLWorldMapView::draw()
gGL.end();
}
**********************/
-
- // Draw the region name in the lower left corner
- LLFontGL* font = LLFontGL::getFontSansSerifSmall();
-
- std::string mesg;
- if (gMapScale < sThresholdA)
+ else if (gSavedSettings.getBOOL("MapShowLandForSale") && (level <= DRAW_LANDFORSALE_THRESHOLD))
{
+ // Draw the overlay image "Land for Sale / Land for Auction"
+ LLViewerFetchedTexture* overlayimage = info->getLandForSaleImage();
+ if (overlayimage)
+ {
+ // Inform the fetch mechanism of the size we need
+ S32 draw_size = llround(sMapScale);
+ overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
+ // Draw something whenever we have enough info
+ if (overlayimage->hasGLTexture())
+ {
+ gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
+ gGL.getTexUnit(0)->bind(overlayimage);
+ gGL.color4f(1.f, 1.f, 1.f, 1.f);
+ gGL.begin(LLRender::QUADS);
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex3f(left, top, -0.5f);
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex3f(left, bottom, -0.5f);
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex3f(right, bottom, -0.5f);
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex3f(right, top, -0.5f);
+ gGL.end();
+ }
+ }
}
- else if (gMapScale < sThresholdB)
+ else
{
- // mesg = llformat( info->mAgents);
+ // If we're not displaying the "land for sale", drop its fetching priority
+ info->dropImagePriority();
}
- else
+
+ // Draw the region name in the lower left corner
+ if (sMapScale >= DRAW_TEXT_THRESHOLD)
{
- //mesg = llformat("%d / %s (%s)",
- // info->mAgents,
- // info->mName.c_str(),
- // LLViewerRegion::accessToShortString(info->mAccess).c_str() );
- if (info->mAccess == SIM_ACCESS_DOWN)
+ LLFontGL* font = LLFontGL::getFontSansSerifSmall();
+ std::string mesg;
+ if (info->isDown())
{
- mesg = llformat( "%s (%s)", info->mName.c_str(), sStringsMap["offline"].c_str());
+ mesg = llformat( "%s (%s)", info->getName().c_str(), sStringsMap["offline"].c_str());
}
else
{
- mesg = info->mName;
+ mesg = info->getName();
}
- }
-
- if (!mesg.empty())
- {
- font->renderUTF8(
- mesg, 0,
- llfloor(left + 3),
- llfloor(bottom + 2),
- LLColor4::white,
- LLFontGL::LEFT,
- LLFontGL::BASELINE,
- LLFontGL::NORMAL,
- LLFontGL::DROP_SHADOW);
-
- // If map texture is still loading,
- // display "Loading" placeholder text.
- if ((simimage != NULL) &&
- simimage->getDiscardLevel() != 1 &&
- simimage->getDiscardLevel() != 0)
+ if (!mesg.empty())
{
font->renderUTF8(
- sStringsMap["loading"], 0,
- llfloor(left + 18),
- llfloor(top - 25),
+ mesg, 0,
+ llfloor(left + 3), llfloor(bottom + 2),
LLColor4::white,
- LLFontGL::LEFT,
- LLFontGL::BASELINE,
- LLFontGL::NORMAL,
- LLFontGL::DROP_SHADOW);
+ LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
}
}
}
- // #endif used to be here
+ #endif
- // there used to be an #if 1 here, but it was uncommented; perhaps marking a block of code?
+ #if 1
// Draw background rectangle
LLGLSUIDefault gls_ui;
{
@@ -726,69 +484,49 @@ void LLWorldMapView::draw()
gGL.color4fv( mBackgroundColor.mV );
gl_rect_2d(0, height, width, 0);
}
-
+
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
gGL.setSceneBlendType(LLRender::BT_ALPHA);
- // Infohubs
- if (gSavedSettings.getBOOL("MapShowInfohubs")) //(gMapScale >= sThresholdB)
+ // Draw item infos if we're not zoomed out too much and there's something to draw
+ if ((level <= DRAW_SIMINFO_THRESHOLD) && (gSavedSettings.getBOOL("MapShowInfohubs") ||
+ gSavedSettings.getBOOL("MapShowTelehubs") ||
+ gSavedSettings.getBOOL("MapShowLandForSale") ||
+ gSavedSettings.getBOOL("MapShowEvents") ||
+ gSavedSettings.getBOOL("ShowMatureEvents") ||
+ gSavedSettings.getBOOL("ShowAdultEvents")))
{
- drawGenericItems(LLWorldMap::getInstance()->mInfohubs, sInfohubImage);
+ drawItems();
}
- // Telehubs
- if (gSavedSettings.getBOOL("MapShowTelehubs")) //(gMapScale >= sThresholdB)
- {
- drawGenericItems(LLWorldMap::getInstance()->mTelehubs, sTelehubImage);
- }
-
- // Home Sweet Home
+ // Draw the Home location (always)
LLVector3d home;
if (gAgent.getHomePosGlobal(&home))
{
drawImage(home, sHomeImage);
}
- if (gSavedSettings.getBOOL("MapShowLandForSale"))
- {
- drawGenericItems(LLWorldMap::getInstance()->mLandForSale, sForSaleImage);
- // for 1.23, we're showing normal land and adult land in the same UI; you don't
- // get a choice about which ones you want. If you're currently asking for adult
- // content and land you'll get the adult land.
- if (gAgent.canAccessAdult())
- {
- drawGenericItems(LLWorldMap::getInstance()->mLandForSaleAdult, sForSaleAdultImage);
- }
- }
-
- if (gSavedSettings.getBOOL("MapShowEvents") ||
- gSavedSettings.getBOOL("ShowMatureEvents") ||
- gSavedSettings.getBOOL("ShowAdultEvents") )
- {
- drawEvents();
- }
-
- // Now draw your avatar after all that other stuff.
+ // Draw the current agent after all that other stuff.
LLVector3d pos_global = gAgent.getPositionGlobal();
- drawImage(pos_global, sAvatarLargeImage);
+ drawImage(pos_global, sAvatarYouImage);
LLVector3 pos_map = globalPosToView(pos_global);
if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY])))
{
- drawTracking(pos_global,
- lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
- TRUE,
- "You are here",
- "",
- llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
+ drawTracking(pos_global,
+ lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
+ TRUE,
+ "You are here",
+ "",
+ llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
}
- // Show your viewing angle
+ // Draw the current agent viewing angle
drawFrustum();
// Draw icons for the avatars in each region.
- // Drawn after your avatar so you can see nearby people.
- if (gSavedSettings.getBOOL("MapShowPeople"))
+ // Drawn this after the current agent avatar so one can see nearby people
+ if (gSavedSettings.getBOOL("MapShowPeople") && (level <= DRAW_SIMINFO_THRESHOLD))
{
drawAgents();
}
@@ -798,9 +536,9 @@ void LLWorldMapView::draw()
if ( LLTracker::TRACKING_AVATAR == tracking_status )
{
drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color, TRUE, LLTracker::getLabel(), "" );
- }
- else if ( LLTracker::TRACKING_LANDMARK == tracking_status
- || LLTracker::TRACKING_LOCATION == tracking_status )
+ }
+ else if ( LLTracker::TRACKING_LANDMARK == tracking_status
+ || LLTracker::TRACKING_LOCATION == tracking_status )
{
// While fetching landmarks, will have 0,0,0 location for a while,
// so don't draw. JC
@@ -810,31 +548,33 @@ void LLWorldMapView::draw()
drawTracking( pos_global, map_track_color, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() );
}
}
- else if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation)
+ else if (LLWorldMap::getInstance()->isTracking())
{
- if (LLWorldMap::getInstance()->mInvalidLocation)
+ if (LLWorldMap::getInstance()->isTrackingInvalidLocation())
{
- // We know this location to be invalid
+ // We know this location to be invalid, draw a blue circle
LLColor4 loading_color(0.0, 0.5, 1.0, 1.0);
- drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("InvalidLocation"), "");
+ drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("InvalidLocation"), "");
}
else
{
+ // We don't know yet what that location is, draw a throbing blue circle
double value = fmod(current_time, 2);
value = 0.5 + 0.5*cos(value * 3.14159f);
LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
- drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("Loading"), "");
+ drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("Loading"), "");
}
}
- // #endif used to be here
-
+ #endif
+
// turn off the scissor
LLGLDisable no_scissor(GL_SCISSOR_TEST);
-
+
updateDirections();
LLView::draw();
+ // Get sim info for all sims in view
updateVisibleBlocks();
} // end draw()
@@ -845,36 +585,182 @@ void LLWorldMapView::setVisible(BOOL visible)
LLPanel::setVisible(visible);
if (!visible)
{
- for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; map++)
+ // Drop the download of tiles and images priority to nil if we hide the map
+ LLWorldMap::getInstance()->dropImagePriorities();
+ }
+}
+
+void LLWorldMapView::drawMipmap(S32 width, S32 height)
+{
+ // Compute the level of the mipmap to use for the current scale level
+ S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+ // Set the tile boost level so that unused tiles get to 0
+ LLWorldMap::getInstance()->equalizeBoostLevels();
+
+ // Render whatever we already have loaded if we haven't the current level
+ // complete and use it as a background (scaled up or scaled down)
+ if (!sVisibleTilesLoaded)
+ {
+ // Note: the (load = false) parameter avoids missing tiles to be fetched (i.e. we render what we have, no more)
+ // Check all the lower res levels and render them in reverse order (worse to best)
+ // We need to traverse all the levels as the user can zoom in very fast
+ for (S32 l = LLWorldMipmap::MAP_LEVELS; l > level; l--)
{
- for (U32 layer_idx=0; layer_idx<LLWorldMap::getInstance()->mMapLayers[map].size(); ++layer_idx)
- {
- if (LLWorldMap::getInstance()->mMapLayers[map][layer_idx].LayerDefined)
- {
- LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[map][layer_idx];
- layer->LayerImage->setBoostLevel(0);
- }
- }
+ drawMipmapLevel(width, height, l, false);
+ }
+ // Skip the current level, as we'll do it anyway here under...
+
+ // Just go one level down in res as it can really get too much stuff
+ // when zooming out and too small to see anyway...
+ if (level > 1)
+ {
+ drawMipmapLevel(width, height, level - 1, false);
}
- for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin();
- it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
+ }
+ else
+ {
+ //LL_INFOS("World Map") << "Render complete, don't draw background..." << LL_ENDL;
+ }
+
+ // Render the current level
+ sVisibleTilesLoaded = drawMipmapLevel(width, height, level);
+
+ return;
+}
+
+// Return true if all the tiles required to render that level have been fetched or are truly missing
+bool LLWorldMapView::drawMipmapLevel(S32 width, S32 height, S32 level, bool load)
+{
+ // Check input level
+ llassert (level > 0);
+ if (level <= 0)
+ return false;
+
+ // Count tiles hit and completed
+ S32 completed_tiles = 0;
+ S32 total_tiles = 0;
+
+ // Size in meters (global) of each tile of that level
+ S32 tile_width = LLWorldMipmap::MAP_TILE_SIZE * (1 << (level - 1));
+ // Dimension of the screen in meter at that scale
+ LLVector3d pos_SW = viewPosToGlobal(0, 0);
+ LLVector3d pos_NE = viewPosToGlobal(width, height);
+ // Add external band of tiles on the outskirt so to hit the partially displayed tiles right and top
+ pos_NE[VX] += tile_width;
+ pos_NE[VY] += tile_width;
+
+ // Iterate through the tiles on screen: we just need to ask for one tile every tile_width meters
+ U32 grid_x, grid_y;
+ for (F64 index_y = pos_SW[VY]; index_y < pos_NE[VY]; index_y += tile_width)
+ {
+ for (F64 index_x = pos_SW[VX]; index_x < pos_NE[VX]; index_x += tile_width)
{
- LLSimInfo* info = (*it).second;
- if (info->mCurrentImage.notNull())
+ // Compute the world coordinates of the current point
+ LLVector3d pos_global(index_x, index_y, pos_SW[VZ]);
+ // Convert to the mipmap level coordinates for that point (i.e. which tile to we hit)
+ LLWorldMipmap::globalToMipmap(pos_global[VX], pos_global[VY], level, &grid_x, &grid_y);
+ // Get the tile. Note: NULL means that the image does not exist (so it's considered "complete" as far as fetching is concerned)
+ LLPointer<LLViewerFetchedTexture> simimage = LLWorldMap::getInstance()->getObjectsTile(grid_x, grid_y, level, load);
+ if (simimage)
{
- info->mCurrentImage->setBoostLevel(0);
+ // Checks that the image has a valid texture
+ if (simimage->hasGLTexture())
+ {
+ // Increment the number of completly fetched tiles
+ completed_tiles++;
+
+ // Convert those coordinates (SW corner of the mipmap tile) into world (meters) coordinates
+ pos_global[VX] = grid_x * REGION_WIDTH_METERS;
+ pos_global[VY] = grid_y * REGION_WIDTH_METERS;
+ // Now to screen coordinates for SW corner of that tile
+ LLVector3 pos_screen = globalPosToView (pos_global);
+ F32 left = pos_screen[VX];
+ F32 bottom = pos_screen[VY];
+ // Compute the NE corner coordinates of the tile now
+ pos_global[VX] += tile_width;
+ pos_global[VY] += tile_width;
+ pos_screen = globalPosToView (pos_global);
+ F32 right = pos_screen[VX];
+ F32 top = pos_screen[VY];
+
+ // Draw the tile
+ LLGLSUIDefault gls_ui;
+ gGL.getTexUnit(0)->bind(simimage.get());
+ simimage->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gGL.color4f(1.f, 1.0f, 1.0f, 1.0f);
+
+ gGL.begin(LLRender::QUADS);
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex3f(left, top, 0.f);
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex3f(left, bottom, 0.f);
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex3f(right, bottom, 0.f);
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex3f(right, top, 0.f);
+ gGL.end();
+#if DEBUG_DRAW_TILE
+ drawTileOutline(level, top, left, bottom, right);
+#endif // DEBUG_DRAW_TILE
+ }
+ //else
+ //{
+ // Waiting for a tile -> the level is not complete
+ // LL_INFOS("World Map") << "Unfetched tile. level = " << level << LL_ENDL;
+ //}
}
- if (info->mOverlayImage.notNull())
+ else
{
- info->mOverlayImage->setBoostLevel(0);
+ // Unexistent tiles are counted as "completed"
+ completed_tiles++;
}
+ // Increment the number of tiles in that level / screen
+ total_tiles++;
}
}
+ return (completed_tiles == total_tiles);
+}
+
+// Draw lines (rectangle outline and cross) to visualize the position of the tile
+// Used for debug only
+void LLWorldMapView::drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right)
+{
+ gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ if (level == 1)
+ gGL.color3f(1.f, 0.f, 0.f); // red
+ else if (level == 2)
+ gGL.color3f(0.f, 1.f, 0.f); // green
+ else if (level == 3)
+ gGL.color3f(0.f, 0.f, 1.f); // blue
+ else if (level == 4)
+ gGL.color3f(1.f, 1.f, 0.f); // yellow
+ else if (level == 5)
+ gGL.color3f(1.f, 0.f, 1.f); // magenta
+ else if (level == 6)
+ gGL.color3f(0.f, 1.f, 1.f); // cyan
+ else if (level == 7)
+ gGL.color3f(1.f, 1.f, 1.f); // white
+ else
+ gGL.color3f(0.f, 0.f, 0.f); // black
+ gGL.begin(LLRender::LINE_STRIP);
+ gGL.vertex2f(left, top);
+ gGL.vertex2f(right, bottom);
+ gGL.vertex2f(left, bottom);
+ gGL.vertex2f(right, top);
+ gGL.vertex2f(left, top);
+ gGL.vertex2f(left, bottom);
+ gGL.vertex2f(right, bottom);
+ gGL.vertex2f(right, top);
+ gGL.end();
}
-void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLUIImagePtr image)
+void LLWorldMapView::drawGenericItems(const LLSimInfo::item_info_list_t& items, LLUIImagePtr image)
{
- LLWorldMap::item_info_list_t::const_iterator e;
+ LLSimInfo::item_info_list_t::const_iterator e;
for (e = items.begin(); e != items.end(); ++e)
{
drawGenericItem(*e, image);
@@ -883,7 +769,7 @@ void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items,
void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLUIImagePtr image)
{
- drawImage(item.mPosGlobal, image);
+ drawImage(item.getGlobalPosition(), image);
}
@@ -906,137 +792,91 @@ void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr i
}
}
-
-void LLWorldMapView::drawAgents()
+void LLWorldMapView::drawItems()
{
- static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
- static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white);
-
- F32 agents_scale = (gMapScale * 0.9f) / 256.f;
+ bool mature_enabled = gAgent.canAccessMature();
+ bool adult_enabled = gAgent.canAccessAdult();
+
+ BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents");
+ BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents");
for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
{
U64 handle = *iter;
- LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
- if (siminfo && (siminfo->mAccess == SIM_ACCESS_DOWN))
+ LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+ if ((info == NULL) || (info->isDown()))
{
continue;
}
- LLWorldMap::agent_list_map_t::iterator counts_iter = LLWorldMap::getInstance()->mAgentLocationsMap.find(handle);
- if (siminfo && siminfo->mShowAgentLocations && counts_iter != LLWorldMap::getInstance()->mAgentLocationsMap.end())
+ // Infohubs
+ if (gSavedSettings.getBOOL("MapShowInfohubs"))
{
- // Show Individual agents (or little stacks where real agents are)
- LLWorldMap::item_info_list_t& agentcounts = counts_iter->second;
- S32 sim_agent_count = 0;
- for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin();
- iter != agentcounts.end(); ++iter)
- {
- const LLItemInfo& info = *iter;
- S32 agent_count = info.mExtra;
- sim_agent_count += info.mExtra;
- // Here's how we'd choose the color if info.mID were available but it's not being sent:
- //LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? map_avatar_friend_color : map_avatar_color;
- drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, map_avatar_color);
- }
- LLWorldMap::getInstance()->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim
+ drawGenericItems(info->getInfoHub(), sInfohubImage);
}
- else
+ // Telehubs
+ if (gSavedSettings.getBOOL("MapShowTelehubs"))
{
- // Show agent 'stack' at center of sim
- S32 num_agents = LLWorldMap::getInstance()->mNumAgents[handle];
- if (num_agents > 0)
+ drawGenericItems(info->getTeleHub(), sTelehubImage);
+ }
+ // Land for sale
+ if (gSavedSettings.getBOOL("MapShowLandForSale"))
+ {
+ drawGenericItems(info->getLandForSale(), sForSaleImage);
+ // for 1.23, we're showing normal land and adult land in the same UI; you don't
+ // get a choice about which ones you want. If you're currently asking for adult
+ // content and land you'll get the adult land.
+ if (gAgent.canAccessAdult())
{
- LLVector3d region_center = from_region_handle(handle);
- region_center[VX] += REGION_WIDTH_METERS / 2;
- region_center[VY] += REGION_WIDTH_METERS / 2;
- // Reduce the stack size as you zoom out - always display at lease one agent where there is one or more
- S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1;
- drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, map_avatar_color);
+ drawGenericItems(info->getLandForSaleAdult(), sForSaleAdultImage);
}
}
+ // PG Events
+ if (gSavedSettings.getBOOL("MapShowEvents"))
+ {
+ drawGenericItems(info->getPGEvent(), sEventImage);
+ }
+ // Mature Events
+ if (show_mature)
+ {
+ drawGenericItems(info->getMatureEvent(), sEventMatureImage);
+ }
+ // Adult Events
+ if (show_adult)
+ {
+ drawGenericItems(info->getAdultEvent(), sEventAdultImage);
+ }
}
}
-
-void LLWorldMapView::drawEvents()
+void LLWorldMapView::drawAgents()
{
- bool mature_enabled = gAgent.canAccessMature();
- bool adult_enabled = gAgent.canAccessAdult();
-
- BOOL show_pg = gSavedSettings.getBOOL("MapShowEvents");
- BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents");
- BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents");
+ static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
- // First the non-selected events
- LLWorldMap::item_info_list_t::const_iterator e;
- if (show_pg)
+ for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
{
- for (e = LLWorldMap::getInstance()->mPGEvents.begin(); e != LLWorldMap::getInstance()->mPGEvents.end(); ++e)
+ U64 handle = *iter;
+ LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+ if ((siminfo == NULL) || (siminfo->isDown()))
{
- if (!e->mSelected)
- {
- drawGenericItem(*e, sEventImage);
- }
+ continue;
}
- }
- if (show_mature)
- {
- for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e)
- {
- if (!e->mSelected)
- {
- drawGenericItem(*e, sEventMatureImage);
- }
- }
- }
- if (show_adult)
- {
- for (e = LLWorldMap::getInstance()->mAdultEvents.begin(); e != LLWorldMap::getInstance()->mAdultEvents.end(); ++e)
- {
- if (!e->mSelected)
- {
- drawGenericItem(*e, sEventAdultImage);
- }
- }
- }
- // Then the selected events
- if (show_pg)
- {
- for (e = LLWorldMap::getInstance()->mPGEvents.begin(); e != LLWorldMap::getInstance()->mPGEvents.end(); ++e)
+ LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAgentLocation().begin();
+ while (it != siminfo->getAgentLocation().end())
{
- if (e->mSelected)
- {
- drawGenericItem(*e, sEventImage);
- }
+ // Show Individual agents (or little stacks where real agents are)
+
+ // Here's how we'd choose the color if info.mID were available but it's not being sent:
+ // LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? friend_color : avatar_color;
+ drawImageStack(it->getGlobalPosition(), sAvatarSmallImage, it->getCount(), 3.f, map_avatar_color);
+ ++it;
}
}
- if (show_mature)
- {
- for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e)
- {
- if (e->mSelected)
- {
- drawGenericItem(*e, sEventMatureImage);
- }
- }
- }
- if (show_adult)
- {
- for (e = LLWorldMap::getInstance()->mAdultEvents.begin(); e != LLWorldMap::getInstance()->mAdultEvents.end(); ++e)
- {
- if (e->mSelected)
- {
- drawGenericItem(*e, sEventAdultImage);
- }
- }
- }
}
-
void LLWorldMapView::drawFrustum()
{
// Draw frustum
- F32 meters_to_pixels = gMapScale/ REGION_WIDTH_METERS;
+ F32 meters_to_pixels = sMapScale/ REGION_WIDTH_METERS;
F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
@@ -1077,8 +917,8 @@ LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos )
LLVector3 pos_local;
pos_local.setVec(relative_pos_global); // convert to floats from doubles
- pos_local.mV[VX] *= sPixelsPerMeter;
- pos_local.mV[VY] *= sPixelsPerMeter;
+ pos_local.mV[VX] *= sMapScale / REGION_WIDTH_METERS;
+ pos_local.mV[VY] *= sMapScale / REGION_WIDTH_METERS;
// leave Z component in meters
@@ -1162,7 +1002,7 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
LLVector3 pos_local( (F32)x, (F32)y, 0.f );
- pos_local *= ( REGION_WIDTH_METERS / gMapScale );
+ pos_local *= ( REGION_WIDTH_METERS / sMapScale );
LLVector3d pos_global;
pos_global.setVec( pos_local );
@@ -1183,23 +1023,20 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
{
LLVector3d pos_global = viewPosToGlobal(x, y);
-
+ U64 handle = to_region_handle(pos_global);
std::string tooltip_msg;
- LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
+ LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
if (info)
{
LLViewerRegion *region = gAgent.getRegion();
- std::string message =
- llformat("%s (%s)",
- info->mName.c_str(),
- LLViewerRegion::accessToString(info->mAccess).c_str());
+ std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
- if (info->mAccess != SIM_ACCESS_DOWN)
+ if (!info->isDown())
{
- S32 agent_count = LLWorldMap::getInstance()->mNumAgents[info->mHandle];
- if (region && region->getHandle() == info->mHandle)
+ S32 agent_count = info->getAgentCount();
+ if (region && (region->getHandle() == handle))
{
++agent_count; // Bump by 1 if we're here
}
@@ -1208,6 +1045,8 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
// zoomed out, so don't display anything about the count. JC
if (agent_count > 0)
{
+ // Merov: i18n horror!!! Even using gettext(), concatenating strings is not localizable.
+ // The singular/plural switch form here under might make no sense in some languages. Don't do that.
message += llformat("\n%d ", agent_count);
if (agent_count == 1)
@@ -1223,7 +1062,7 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
tooltip_msg.assign( message );
// Optionally show region flags
- std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags);
+ std::string region_flags = info->getFlagsString();
if (!region_flags.empty())
{
@@ -1263,6 +1102,9 @@ static void drawDot(F32 x_pixels, F32 y_pixels,
}
else
{
+ // Draw V indicator for above or below
+ // *TODO: Replace this vector drawing with icons
+
F32 left = x_pixels - dot_radius;
F32 right = x_pixels + dot_radius;
F32 center = (left + right) * 0.5f;
@@ -1271,13 +1113,14 @@ static void drawDot(F32 x_pixels, F32 y_pixels,
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color4fv( color.mV );
- LLUI::setLineWidth(1.5f);
- F32 h_bar = relative_z > HEIGHT_THRESHOLD ? top : bottom; // horizontal bar Y
+ LLUI::setLineWidth(3.0f);
+ F32 point = relative_z > HEIGHT_THRESHOLD ? top : bottom; // Y pos of the point of the V
+ F32 back = relative_z > HEIGHT_THRESHOLD ? bottom : top; // Y pos of the ends of the V
gGL.begin( LLRender::LINES );
- gGL.vertex2f(center, top);
- gGL.vertex2f(left, h_bar);
- gGL.vertex2f(right, h_bar);
- gGL.vertex2f(right, bottom);
+ gGL.vertex2f(left, back);
+ gGL.vertex2f(center, point);
+ gGL.vertex2f(center, point);
+ gGL.vertex2f(right, back);
gGL.end();
LLUI::setLineWidth(1.0f);
}
@@ -1292,7 +1135,7 @@ void LLWorldMapView::drawAvatar(F32 x_pixels,
F32 dot_radius)
{
const F32 HEIGHT_THRESHOLD = 7.f;
- LLUIImagePtr dot_image = sAvatarSmallImage;
+ LLUIImagePtr dot_image = sAvatarLevelImage;
if(relative_z < -HEIGHT_THRESHOLD)
{
dot_image = sAvatarBelowImage;
@@ -1301,10 +1144,12 @@ void LLWorldMapView::drawAvatar(F32 x_pixels,
{
dot_image = sAvatarAboveImage;
}
- dot_image->draw(
- llround(x_pixels) - dot_image->getWidth()/2,
- llround(y_pixels) - dot_image->getHeight()/2,
- color);
+ S32 dot_width = llround(dot_radius * 2.f);
+ dot_image->draw(llround(x_pixels - dot_radius),
+ llround(y_pixels - dot_radius),
+ dot_width,
+ dot_width,
+ color);
}
// Pass relative Z of 0 to draw at same level.
@@ -1565,7 +1410,7 @@ void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent )
bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track)
{
- LLVector3 pos_view = globalPosToView(item.mPosGlobal);
+ LLVector3 pos_view = globalPosToView(item.getGlobalPosition());
S32 item_x = llround(pos_view.mV[VX]);
S32 item_y = llround(pos_view.mV[VY]);
@@ -1574,12 +1419,12 @@ bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bo
if (y < item_y - BIG_DOT_RADIUS) return false;
if (y > item_y + BIG_DOT_RADIUS) return false;
- LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.mRegionHandle);
+ LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.getRegionHandle());
if (sim_info)
{
if (track)
{
- gFloaterWorldMap->trackLocation(item.mPosGlobal);
+ gFloaterWorldMap->trackLocation(item.getGlobalPosition());
}
}
@@ -1588,8 +1433,8 @@ bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bo
gFloaterWorldMap->trackGenericItem(item);
}
- item.mSelected = TRUE;
- *id = item.mID;
+// item.setSelected(true);
+ *id = item.getUUID();
return true;
}
@@ -1612,108 +1457,116 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask,
*hit_type = 0; // hit nothing
- LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
- LLWorldMap::getInstance()->mIsTrackingDoubleClick = FALSE;
- LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
-
- LLWorldMap::item_info_list_t::iterator it;
-
- // clear old selected stuff
- for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it)
- {
- (*it).mSelected = FALSE;
- }
- for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it)
- {
- (*it).mSelected = FALSE;
- }
- for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it)
- {
- (*it).mSelected = FALSE;
- }
- for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it)
- {
- (*it).mSelected = FALSE;
- }
-
- // Select event you clicked on
- if (gSavedSettings.getBOOL("MapShowEvents"))
- {
- for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it)
- {
- LLItemInfo& event = *it;
-
- if (checkItemHit(x, y, event, id, false))
- {
- *hit_type = MAP_ITEM_PG_EVENT;
- mItemPicked = TRUE;
- gFloaterWorldMap->trackEvent(event);
- return;
- }
- }
- }
- if (gSavedSettings.getBOOL("ShowMatureEvents"))
- {
- for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it)
- {
- LLItemInfo& event = *it;
-
- if (checkItemHit(x, y, event, id, false))
- {
- *hit_type = MAP_ITEM_MATURE_EVENT;
- mItemPicked = TRUE;
- gFloaterWorldMap->trackEvent(event);
- return;
- }
- }
- }
- if (gSavedSettings.getBOOL("ShowAdultEvents"))
- {
- for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it)
- {
- LLItemInfo& event = *it;
-
- if (checkItemHit(x, y, event, id, false))
- {
- *hit_type = MAP_ITEM_ADULT_EVENT;
- mItemPicked = TRUE;
- gFloaterWorldMap->trackEvent(event);
- return;
- }
- }
- }
+ LLWorldMap::getInstance()->cancelTracking();
- if (gSavedSettings.getBOOL("MapShowLandForSale"))
+ S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+ // If the zoom level is not too far out already, test hits
+ if (level <= DRAW_SIMINFO_THRESHOLD)
{
- for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it)
- {
- LLItemInfo& land = *it;
+ bool show_mature = gAgent.canAccessMature() && gSavedSettings.getBOOL("ShowMatureEvents");
+ bool show_adult = gAgent.canAccessAdult() && gSavedSettings.getBOOL("ShowAdultEvents");
- if (checkItemHit(x, y, land, id, true))
- {
- *hit_type = MAP_ITEM_LAND_FOR_SALE;
- mItemPicked = TRUE;
- return;
- }
- }
-
- for (it = LLWorldMap::getInstance()->mLandForSaleAdult.begin(); it != LLWorldMap::getInstance()->mLandForSaleAdult.end(); ++it)
+ // Test hits if trackable data are displayed, otherwise, we don't even bother
+ if (gSavedSettings.getBOOL("MapShowEvents") || show_mature || show_adult || gSavedSettings.getBOOL("MapShowLandForSale"))
{
- LLItemInfo& land = *it;
-
- if (checkItemHit(x, y, land, id, true))
+ // Iterate through the visible regions
+ for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
{
- *hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT;
- mItemPicked = TRUE;
- return;
+ U64 handle = *iter;
+ LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+ if ((siminfo == NULL) || (siminfo->isDown()))
+ {
+ continue;
+ }
+ // If on screen check hits with the visible item lists
+ if (gSavedSettings.getBOOL("MapShowEvents"))
+ {
+ LLSimInfo::item_info_list_t::const_iterator it = siminfo->getPGEvent().begin();
+ while (it != siminfo->getPGEvent().end())
+ {
+ LLItemInfo event = *it;
+ if (checkItemHit(x, y, event, id, false))
+ {
+ *hit_type = MAP_ITEM_PG_EVENT;
+ mItemPicked = TRUE;
+ gFloaterWorldMap->trackEvent(event);
+ return;
+ }
+ ++it;
+ }
+ }
+ if (show_mature)
+ {
+ LLSimInfo::item_info_list_t::const_iterator it = siminfo->getMatureEvent().begin();
+ while (it != siminfo->getMatureEvent().end())
+ {
+ LLItemInfo event = *it;
+ if (checkItemHit(x, y, event, id, false))
+ {
+ *hit_type = MAP_ITEM_MATURE_EVENT;
+ mItemPicked = TRUE;
+ gFloaterWorldMap->trackEvent(event);
+ return;
+ }
+ ++it;
+ }
+ }
+ if (show_adult)
+ {
+ LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAdultEvent().begin();
+ while (it != siminfo->getAdultEvent().end())
+ {
+ LLItemInfo event = *it;
+ if (checkItemHit(x, y, event, id, false))
+ {
+ *hit_type = MAP_ITEM_ADULT_EVENT;
+ mItemPicked = TRUE;
+ gFloaterWorldMap->trackEvent(event);
+ return;
+ }
+ ++it;
+ }
+ }
+ if (gSavedSettings.getBOOL("MapShowLandForSale"))
+ {
+ LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSale().begin();
+ while (it != siminfo->getLandForSale().end())
+ {
+ LLItemInfo event = *it;
+ if (checkItemHit(x, y, event, id, true))
+ {
+ *hit_type = MAP_ITEM_LAND_FOR_SALE;
+ mItemPicked = TRUE;
+ return;
+ }
+ ++it;
+ }
+ // for 1.23, we're showing normal land and adult land in the same UI; you don't
+ // get a choice about which ones you want. If you're currently asking for adult
+ // content and land you'll get the adult land.
+ if (gAgent.canAccessAdult())
+ {
+ LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSaleAdult().begin();
+ while (it != siminfo->getLandForSaleAdult().end())
+ {
+ LLItemInfo event = *it;
+ if (checkItemHit(x, y, event, id, true))
+ {
+ *hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT;
+ mItemPicked = TRUE;
+ return;
+ }
+ ++it;
+ }
+ }
+ }
}
}
}
- // If we get here, we haven't clicked on an icon
+ // If we get here, we haven't clicked on anything
gFloaterWorldMap->trackLocation(pos_global);
mItemPicked = FALSE;
-
*id = LLUUID::null;
return;
}
@@ -1774,59 +1627,36 @@ BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
return FALSE;
}
-U32 LLWorldMapView::updateBlock(S32 block_x, S32 block_y)
+void LLWorldMapView::updateVisibleBlocks()
{
- U32 blocks_requested = 0;
- S32 offset = block_x | (block_y * MAP_BLOCK_RES);
- if (!LLWorldMap::getInstance()->mMapBlockLoaded[LLWorldMap::getInstance()->mCurrentMap][offset])
+ if (LLWorldMipmap::scaleToLevel(sMapScale) > DRAW_SIMINFO_THRESHOLD)
{
-// llinfos << "Loading Block (" << block_x << "," << block_y << ")" << llendl;
- LLWorldMap::getInstance()->sendMapBlockRequest(block_x << 3, block_y << 3, (block_x << 3) + 7, (block_y << 3) + 7);
- LLWorldMap::getInstance()->mMapBlockLoaded[LLWorldMap::getInstance()->mCurrentMap][offset] = TRUE;
- blocks_requested++;
+ // If we're zoomed out too much, we just don't load all those sim info: too much!
+ return;
}
- return blocks_requested;
-}
-U32 LLWorldMapView::updateVisibleBlocks()
-{
- if (gMapScale < SIM_MAP_SCALE)
- {
- // We don't care what is loaded if we're zoomed out
- return 0;
- }
+ // Load the blocks visible in the current World Map view
+ // Get the World Map view coordinates and boundaries
LLVector3d camera_global = gAgent.getCameraPositionGlobal();
-
- F32 pixels_per_region = gMapScale;
const S32 width = getRect().getWidth();
const S32 height = getRect().getHeight();
- // Convert pan to sim coordinates
- S32 world_center_x_lo = S32(((-sPanX - width/2) / pixels_per_region) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
- S32 world_center_x_hi = S32(((-sPanX + width/2) / pixels_per_region) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
- S32 world_center_y_lo = S32(((-sPanY - height/2) / pixels_per_region) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
- S32 world_center_y_hi = S32(((-sPanY + height/2)/ pixels_per_region) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
-
- // Find the corresponding 8x8 block
- S32 world_block_x_lo = world_center_x_lo >> 3;
- S32 world_block_x_hi = world_center_x_hi >> 3;
- S32 world_block_y_lo = world_center_y_lo >> 3;
- S32 world_block_y_hi = world_center_y_hi >> 3;
-
- U32 blocks_requested = 0;
- const U32 max_blocks_requested = 9;
+ const F32 half_width = F32(width) / 2.0f;
+ const F32 half_height = F32(height) / 2.0f;
- for (S32 block_x = llmax(world_block_x_lo, 0); block_x <= llmin(world_block_x_hi, MAP_BLOCK_RES-1); ++block_x)
- {
- for (S32 block_y = llmax(world_block_y_lo, 0); block_y <= llmin(world_block_y_hi, MAP_BLOCK_RES-1); ++block_y)
- {
- blocks_requested += updateBlock(block_x, block_y);
- if (blocks_requested >= max_blocks_requested)
- return blocks_requested;
- }
- }
- return blocks_requested;
-}
+ // Compute center into sim grid coordinates
+ S32 world_center_x = S32((-sPanX / sMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
+ S32 world_center_y = S32((-sPanY / sMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
+
+ // Compute the boundaries into sim grid coordinates
+ S32 world_left = world_center_x - S32(half_width / sMapScale) - 1;
+ S32 world_right = world_center_x + S32(half_width / sMapScale) + 1;
+ S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1;
+ S32 world_top = world_center_y + S32(half_height / sMapScale) + 1;
+
+ //LL_INFOS("World Map") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom = " << world_bottom << ", top = " << world_top << LL_ENDL;
+ LLWorldMap::getInstance()->updateRegions(world_left, world_bottom, world_right, world_top);
+}
BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask )
{
@@ -1915,16 +1745,16 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
}
default:
{
- if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation)
+ if (LLWorldMap::getInstance()->isTracking())
{
- LLWorldMap::getInstance()->mIsTrackingDoubleClick = TRUE;
+ LLWorldMap::getInstance()->setTrackingDoubleClick();
}
else
{
// Teleport if we got a valid location
LLVector3d pos_global = viewPosToGlobal(x,y);
LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
- if (sim_info && sim_info->mAccess != SIM_ACCESS_DOWN)
+ if (sim_info && !sim_info->isDown())
{
gAgent.teleportViaLocation( pos_global );
}
diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h
index 66793f0101..9eecacb2d8 100644
--- a/indra/newview/llworldmapview.h
+++ b/indra/newview/llworldmapview.h
@@ -30,27 +30,23 @@
* $/LicenseInfo$
*/
-// Global map of the world.
+// View of the global map of the world
+
+// The data (model) for the global map (a singleton, unique to the application instance) is
+// in LLWorldMap and is typically accessed using LLWorldMap::getInstance()
#ifndef LL_LLWORLDMAPVIEW_H
#define LL_LLWORLDMAPVIEW_H
#include "llpanel.h"
-#include "v3math.h"
-#include "v3dmath.h"
-#include "v4color.h"
-#include "llviewertexture.h"
-#include "llmapimagetype.h"
#include "llworldmap.h"
-
-class LLItemInfo;
+#include "v4color.h"
const S32 DEFAULT_TRACKING_ARROW_SIZE = 16;
-class LLColor4;
-class LLColor4U;
-class LLCoordGL;
-class LLViewerTexture;
+class LLUUID;
+class LLVector3d;
+class LLVector3;
class LLTextBox;
@@ -77,22 +73,26 @@ public:
bool checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track);
void handleClick(S32 x, S32 y, MASK mask, S32* hit_type, LLUUID* id);
- // Scale and pan are shared across all instances.
+ // Scale and pan are shared across all instances! (i.e. Terrain and Objects maps are always registered)
static void setScale( F32 scale );
static void translatePan( S32 delta_x, S32 delta_y );
static void setPan( S32 x, S32 y, BOOL snap = TRUE );
+ // Return true if the current scale level is above the threshold for accessing region info
+ static bool showRegionInfo();
LLVector3 globalPosToView(const LLVector3d& global_pos);
LLVector3d viewPosToGlobal(S32 x,S32 y);
virtual void draw();
- void drawGenericItems(const LLWorldMap::item_info_list_t& items, LLUIImagePtr image);
+ void drawGenericItems(const LLSimInfo::item_info_list_t& items, LLUIImagePtr image);
void drawGenericItem(const LLItemInfo& item, LLUIImagePtr image);
void drawImage(const LLVector3d& global_pos, LLUIImagePtr image, const LLColor4& color = LLColor4::white);
void drawImageStack(const LLVector3d& global_pos, LLUIImagePtr image, U32 count, F32 offset, const LLColor4& color);
void drawAgents();
- void drawEvents();
+ void drawItems();
void drawFrustum();
+ void drawMipmap(S32 width, S32 height);
+ bool drawMipmapLevel(S32 width, S32 height, S32 level, bool load = true);
static void cleanupTextures();
@@ -108,7 +108,7 @@ public:
F32 y_pixels,
const LLColor4& color,
F32 relative_z = 0.f,
- F32 dot_radius = 3.f);
+ F32 dot_radius = 5.f);
static void drawTrackingCircle( const LLRect& rect, S32 x, S32 y,
const LLColor4& color,
@@ -129,9 +129,7 @@ public:
static void clearLastClick() { sHandledLastClick = FALSE; }
// if the view changes, download additional sim info as needed
- // return value is number of blocks newly requested.
- U32 updateBlock(S32 block_x, S32 block_y);
- U32 updateVisibleBlocks();
+ void updateVisibleBlocks();
protected:
void setDirectionPos( LLTextBox* text_box, F32 rotation );
@@ -140,11 +138,13 @@ protected:
public:
LLColor4 mBackgroundColor;
- static LLUIImagePtr sAvatarYouSmallImage;
static LLUIImagePtr sAvatarSmallImage;
- static LLUIImagePtr sAvatarLargeImage;
+ static LLUIImagePtr sAvatarYouImage;
+ static LLUIImagePtr sAvatarYouLargeImage;
+ static LLUIImagePtr sAvatarLevelImage;
static LLUIImagePtr sAvatarAboveImage;
static LLUIImagePtr sAvatarBelowImage;
+
static LLUIImagePtr sTelehubImage;
static LLUIImagePtr sInfohubImage;
static LLUIImagePtr sHomeImage;
@@ -157,9 +157,7 @@ public:
static LLUIImagePtr sForSaleImage;
static LLUIImagePtr sForSaleAdultImage;
- static F32 sThresholdA;
- static F32 sThresholdB;
- static F32 sPixelsPerMeter; // world meters to map pixels
+ static F32 sMapScale; // scale = size of a region in pixels
BOOL mItemPicked;
@@ -169,6 +167,7 @@ public:
static F32 sTargetPanY; // in pixels
static S32 sTrackingArrowX;
static S32 sTrackingArrowY;
+ static bool sVisibleTilesLoaded;
// Are we mid-pan from a user drag?
BOOL mPanning;
@@ -191,10 +190,14 @@ public:
static BOOL sHandledLastClick;
S32 mSelectIDStart;
+ // Keep the list of regions that are displayed on screen. Avoids iterating through the whole region map after draw().
typedef std::vector<U64> handle_list_t;
handle_list_t mVisibleRegions; // set every frame
static std::map<std::string,std::string> sStringsMap;
+
+private:
+ void drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right);
};
#endif
diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp
new file mode 100644
index 0000000000..8d3165b98c
--- /dev/null
+++ b/indra/newview/llworldmipmap.cpp
@@ -0,0 +1,275 @@
+/**
+ * @file llworldmipmap.cpp
+ * @brief Data storage for the S3 mipmap of the entire world.
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llworldmipmap.h"
+
+#include "llviewertexturelist.h"
+#include "math.h" // log()
+
+// Turn this on to output tile stats in the standard output
+#define DEBUG_TILES_STAT 0
+
+LLWorldMipmap::LLWorldMipmap() :
+ mCurrentLevel(0)
+{
+}
+
+LLWorldMipmap::~LLWorldMipmap()
+{
+ reset();
+}
+
+// Delete all sublevel maps and clean them
+void LLWorldMipmap::reset()
+{
+ for (int level = 0; level < MAP_LEVELS; level++)
+ {
+ mWorldObjectsMipMap[level].clear();
+ }
+}
+
+// This method should be called before each use of the mipmap (typically, before each draw), so that to let
+// the boost level of unused tiles to drop to 0 (BOOST_NONE).
+// Tiles that are accessed have had their boost level pushed to BOOST_MAP_VISIBLE so we can identify them.
+// The result of this strategy is that if a tile is not used during 2 consecutive loops, its boost level drops to 0.
+void LLWorldMipmap::equalizeBoostLevels()
+{
+#if DEBUG_TILES_STAT
+ S32 nb_missing = 0;
+ S32 nb_tiles = 0;
+ S32 nb_visible = 0;
+#endif // DEBUG_TILES_STAT
+ // For each level
+ for (S32 level = 0; level < MAP_LEVELS; level++)
+ {
+ sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level];
+ // For each tile
+ for (sublevel_tiles_t::iterator iter = level_mipmap.begin(); iter != level_mipmap.end(); iter++)
+ {
+ LLPointer<LLViewerFetchedTexture> img = iter->second;
+ S32 current_boost_level = img->getBoostLevel();
+ if (current_boost_level == LLViewerTexture::BOOST_MAP_VISIBLE)
+ {
+ // If level was BOOST_MAP_VISIBLE, the tile has been used in the last draw so keep it high
+ img->setBoostLevel(LLViewerTexture::BOOST_MAP);
+ }
+ else
+ {
+ // If level was BOOST_MAP only (or anything else...), the tile wasn't used in the last draw
+ // so we drop its boost level to BOOST_NONE.
+ img->setBoostLevel(LLViewerTexture::BOOST_NONE);
+ }
+#if DEBUG_TILES_STAT
+ // Increment some stats if compile option on
+ nb_tiles++;
+ if (current_boost_level == LLViewerTexture::BOOST_MAP_VISIBLE)
+ {
+ nb_visible++;
+ }
+ if (img->isMissingAsset())
+ {
+ nb_missing++;
+ }
+#endif // DEBUG_TILES_STAT
+ }
+ }
+#if DEBUG_TILES_STAT
+ LL_INFOS("World Map") << "LLWorldMipmap tile stats : total requested = " << nb_tiles << ", visible = " << nb_visible << ", missing = " << nb_missing << LL_ENDL;
+#endif // DEBUG_TILES_STAT
+}
+
+// This method should be used when the mipmap is not actively used for a while, e.g., the map UI is hidden
+void LLWorldMipmap::dropBoostLevels()
+{
+ // For each level
+ for (S32 level = 0; level < MAP_LEVELS; level++)
+ {
+ sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level];
+ // For each tile
+ for (sublevel_tiles_t::iterator iter = level_mipmap.begin(); iter != level_mipmap.end(); iter++)
+ {
+ LLPointer<LLViewerFetchedTexture> img = iter->second;
+ img->setBoostLevel(LLViewerTexture::BOOST_NONE);
+ }
+ }
+}
+
+LLPointer<LLViewerFetchedTexture> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load)
+{
+ // Check the input data
+ llassert(level <= MAP_LEVELS);
+ llassert(level >= 1);
+
+ // If the *loading* level changed, cleared the new level from "missed" tiles
+ // so that we get a chance to reload them
+ if (load && (level != mCurrentLevel))
+ {
+ cleanMissedTilesFromLevel(level);
+ mCurrentLevel = level;
+ }
+
+ // Build the region handle
+ U64 handle = convertGridToHandle(grid_x, grid_y);
+
+ // Check if the image is around already
+ sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level-1];
+ sublevel_tiles_t::iterator found = level_mipmap.find(handle);
+
+ // If not there and load on, go load it
+ if (found == level_mipmap.end())
+ {
+ if (load)
+ {
+ // Load it
+ LLPointer<LLViewerFetchedTexture> img = loadObjectsTile(grid_x, grid_y, level);
+ // Insert the image in the map
+ level_mipmap.insert(sublevel_tiles_t::value_type( handle, img ));
+ // Find the element again in the map (it's there now...)
+ found = level_mipmap.find(handle);
+ }
+ else
+ {
+ // Return with NULL if not found and we're not trying to load
+ return NULL;
+ }
+ }
+
+ // Get the image pointer and check if this asset is missing
+ LLPointer<LLViewerFetchedTexture> img = found->second;
+ if (img->isMissingAsset())
+ {
+ // Return NULL if asset missing
+ return NULL;
+ }
+ else
+ {
+ // Boost the tile level so to mark it's in use *if* load on
+ if (load)
+ {
+ img->setBoostLevel(LLViewerTexture::BOOST_MAP_VISIBLE);
+ }
+ return img;
+ }
+}
+
+LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
+{
+ // Get the grid coordinates
+// std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/%d/%05d/%05d/map-%d-%d-%d-objects.jpg",
+ std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/map-%d-%d-%d-objects.jpg",
+ level, grid_x, grid_y, level, grid_x, grid_y);
+
+ // DO NOT COMMIT!! DEBUG ONLY!!!
+ // Use a local jpeg for every tile to test map speed without S3 access
+ //imageurl = "file://C:\\Develop\\mapserver-distribute-3\\indra\\build-vc80\\mapserver\\relwithdebinfo\\regions\\00995\\01001\\region-995-1001-prims.jpg";
+ // END DEBUG
+ //LL_INFOS("World Map") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL;
+
+ LLPointer<LLViewerFetchedTexture> img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+ img->setBoostLevel(LLViewerTexture::BOOST_MAP);
+
+ // Return the smart pointer
+ return img;
+}
+
+// This method is used to clean up a level from tiles marked as "missing".
+// The idea is to allow tiles that have been improperly marked missing to be reloaded when retraversing the level again.
+// When zooming in and out rapidly, some tiles are never properly loaded and, eventually marked missing.
+// This creates "blue" areas in a subresolution that never got a chance to reload if we don't clean up the level.
+void LLWorldMipmap::cleanMissedTilesFromLevel(S32 level)
+{
+ // Check the input data
+ llassert(level <= MAP_LEVELS);
+ llassert(level >= 0);
+
+ // This happens when the object is first initialized
+ if (level == 0)
+ {
+ return;
+ }
+
+ // Iterate through the subresolution level and suppress the tiles that are marked as missing
+ // Note: erasing in a map while iterating through it is bug prone. Using a postfix increment is mandatory here.
+ sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level-1];
+ sublevel_tiles_t::iterator it = level_mipmap.begin();
+ while (it != level_mipmap.end())
+ {
+ LLPointer<LLViewerFetchedTexture> img = it->second;
+ if (img->isMissingAsset())
+ {
+ level_mipmap.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ return;
+}
+
+// static methods
+// Compute the level in the world mipmap (between 1 and MAP_LEVELS, as in the URL) given the scale (size of a sim in screen pixels)
+S32 LLWorldMipmap::scaleToLevel(F32 scale)
+{
+ // If scale really small, picks up the higest level there is (lowest resolution)
+ if (scale <= F32_MIN)
+ return MAP_LEVELS;
+ // Compute the power of two resolution level knowing the base level
+ S32 level = llfloor((log(REGION_WIDTH_METERS/scale)/log(2.0f)) + 1.0f);
+ // Check bounds and return the value
+ if (level > MAP_LEVELS)
+ return MAP_LEVELS;
+ else if (level < 1)
+ return 1;
+ else
+ return level;
+}
+
+// Convert world coordinates to mipmap grid coordinates at a given level (between 1 and MAP_LEVELS)
+void LLWorldMipmap::globalToMipmap(F64 global_x, F64 global_y, S32 level, U32* grid_x, U32* grid_y)
+{
+ // Check the input data
+ llassert(level <= MAP_LEVELS);
+ llassert(level >= 1);
+
+ // Convert world coordinates into grid coordinates
+ *grid_x = lltrunc(global_x/REGION_WIDTH_METERS);
+ *grid_y = lltrunc(global_y/REGION_WIDTH_METERS);
+ // Compute the valid grid coordinates at that level of the mipmap
+ S32 regions_in_tile = 1 << (level - 1);
+ *grid_x = *grid_x - (*grid_x % regions_in_tile);
+ *grid_y = *grid_y - (*grid_y % regions_in_tile);
+}
+
+
diff --git a/indra/newview/llworldmipmap.h b/indra/newview/llworldmipmap.h
new file mode 100644
index 0000000000..ecf1003468
--- /dev/null
+++ b/indra/newview/llworldmipmap.h
@@ -0,0 +1,100 @@
+/**
+ * @file llworldmipmap.h
+ * @brief Data storage for the S3 mipmap of the entire world.
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLWORLDMIPMAP_H
+#define LL_LLWORLDMIPMAP_H
+
+#include <map>
+
+#include "llmemory.h" // LLPointer
+#include "indra_constants.h" // REGION_WIDTH_UNITS
+#include "llregionhandle.h" // to_region_handle()
+
+class LLViewerFetchedTexture;
+
+// LLWorldMipmap : Mipmap handling of all the tiles used to render the world at any resolution.
+// This class provides a clean structured access to the hierarchy of tiles stored in the
+// Amazon S3 repository and abstracts its directory/file structure.
+// The interface of this class though still assumes that the caller knows the general level/tiles
+// structure (at least, that it exists...) but doesn't requite the caller to know the details of it.
+// IOW, you need to know that rendering levels exists as well as grid coordinates for regions,
+// but you can ignore where those tiles are located, how to get them, etc...
+// The class API gives you back LLPointer<LLViewerFetchedTexture> per tile.
+
+// See llworldmipmapview.cpp for the implementation of a class who knows how to render an LLWorldMipmap.
+
+// Implementation notes:
+// - On the S3 servers, the tiles are rendered in 2 flavors: Objects and Terrain.
+// - For the moment, LLWorldMipmap implements access only to the Objects tiles.
+class LLWorldMipmap
+{
+public:
+ // Parameters of the mipmap
+ static const S32 MAP_LEVELS = 8; // Number of subresolution levels computed by the mapserver
+ static const S32 MAP_TILE_SIZE = 256; // Width in pixels of the tiles computed by the mapserver
+
+ LLWorldMipmap();
+ ~LLWorldMipmap();
+
+ // Clear up the maps and release all image handles
+ void reset();
+ // Manage the boost levels between loops (typically draw() loops)
+ void equalizeBoostLevels();
+ // Drop the boost levels to none (used when hiding the map)
+ void dropBoostLevels();
+ // Get the tile smart pointer, does the loading if necessary
+ LLPointer<LLViewerFetchedTexture> getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load = true);
+
+ // Helper functions: those are here as they depend solely on the topology of the mipmap though they don't access it
+ // Convert sim scale (given in sim width in display pixels) into a mipmap level
+ static S32 scaleToLevel(F32 scale);
+ // Convert world coordinates to mipmap grid coordinates at a given level
+ static void globalToMipmap(F64 global_x, F64 global_y, S32 level, U32* grid_x, U32* grid_y);
+
+private:
+ // Get a handle (key) from grid coordinates
+ U64 convertGridToHandle(U32 grid_x, U32 grid_y) { return to_region_handle(grid_x * REGION_WIDTH_UNITS, grid_y * REGION_WIDTH_UNITS); }
+ // Load the relevant tile from S3
+ LLPointer<LLViewerFetchedTexture> loadObjectsTile(U32 grid_x, U32 grid_y, S32 level);
+ // Clear a level from its "missing" tiles
+ void cleanMissedTilesFromLevel(S32 level);
+
+ // The mipmap is organized by resolution level (MAP_LEVELS of them). Each resolution level is an std::map
+ // using a region_handle as a key and storing a smart pointer to the image as a value.
+ typedef std::map<U64, LLPointer<LLViewerFetchedTexture> > sublevel_tiles_t;
+ sublevel_tiles_t mWorldObjectsMipMap[MAP_LEVELS];
+// sublevel_tiles_t mWorldTerrainMipMap[MAP_LEVELS];
+
+ S32 mCurrentLevel; // The level last accessed by a getObjectsTile()
+};
+
+#endif // LL_LLWORLDMIPMAP_H
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index b01a4f5161..17c04a81c2 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1464,6 +1464,7 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera
F32 dist = lookAt.length();
//ramp down distance for nearby objects
+ //shrink dist by dist/16.
if (dist < 16.f)
{
dist /= 16.f;
@@ -3001,15 +3002,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
- //by bao
- //fake vertex buffer updating
- //to guaranttee at least updating one VBO buffer every frame
- //to walk around the bug caused by ATI card --> DEV-3855
- //
- if(forceVBOUpdate)
- gSky.mVOSkyp->updateDummyVertexBuffer() ;
-
-
// Initialize lots of GL state to "safe" values
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
diff --git a/indra/newview/skins/default/textures/map_avatar_32.tga b/indra/newview/skins/default/textures/map_avatar_32.tga
new file mode 100644
index 0000000000..aebeab4093
--- /dev/null
+++ b/indra/newview/skins/default/textures/map_avatar_32.tga
Binary files differ
diff --git a/indra/newview/skins/default/textures/map_avatar_above_32.tga b/indra/newview/skins/default/textures/map_avatar_above_32.tga
new file mode 100644
index 0000000000..65bd0561a7
--- /dev/null
+++ b/indra/newview/skins/default/textures/map_avatar_above_32.tga
Binary files differ
diff --git a/indra/newview/skins/default/textures/map_avatar_below_32.tga b/indra/newview/skins/default/textures/map_avatar_below_32.tga
new file mode 100644
index 0000000000..496c44b369
--- /dev/null
+++ b/indra/newview/skins/default/textures/map_avatar_below_32.tga
Binary files differ
diff --git a/indra/newview/skins/default/textures/map_avatar_you_32.tga b/indra/newview/skins/default/textures/map_avatar_you_32.tga
new file mode 100644
index 0000000000..782207efd6
--- /dev/null
+++ b/indra/newview/skins/default/textures/map_avatar_you_32.tga
Binary files differ
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index f37c0e9022..14fdbeaaa1 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -14,38 +14,15 @@
single_instance="true"
title="World Map"
width="800">
- <tab_container
+ <panel
+ filename="panel_world_map.xml"
follows="left|top|right|bottom"
height="565"
layout="topleft"
left="15"
- name="maptab"
- tab_position="top"
+ name="objects_mapview"
top="25"
- width="542">
- <panel
- filename="panel_world_map.xml"
- follows="left|top|right|bottom"
- height="550"
- label="Objects"
- layout="topleft"
- left="1"
- help_topic="worldmap_objects_tab"
- name="objects_mapview"
- top="19"
- width="540" />
- <panel
- filename="panel_world_map.xml"
- follows="left|top|right|bottom"
- height="550"
- label="Terrain"
- layout="topleft"
- left_delta="0"
- help_topic="worldmap_terrain_tab"
- name="terrain_mapview"
- top_delta="3"
- width="540" />
- </tab_container>
+ width="542" />
<icon
follows="top|right"
height="16"
@@ -209,7 +186,7 @@
label="Telehub"
layout="topleft"
left_pad="4"
- name="telehubchk"
+ name="telehub_chk"
top_delta="0"
width="110" />
<icon
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 284594426c..6ebb5f8681 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1673,6 +1673,42 @@
parameter="debug" />
</menu_item_check>
<menu_item_check
+ label="Notifications Console"
+ layout="topleft"
+ name="Notifications"
+ shortcut="control|shift|5">
+ <menu_item_check.on_check
+ function="Advanced.CheckConsole"
+ parameter="notifications" />
+ <menu_item_check.on_click
+ function="Floater.Show"
+ parameter="notifications_console" />
+ </menu_item_check>
+ <menu_item_check
+ label="Texture Size Console"
+ layout="topleft"
+ name="Texture Size"
+ shortcut="control|shift|6">
+ <menu_item_check.on_check
+ function="Advanced.CheckConsole"
+ parameter="texture size" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleConsole"
+ parameter="texture size" />
+ </menu_item_check>
+ <menu_item_check
+ label="Texture Category Console"
+ layout="topleft"
+ name="Texture Category"
+ shortcut="control|shift|7">
+ <menu_item_check.on_check
+ function="Advanced.CheckConsole"
+ parameter="texture category" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleConsole"
+ parameter="texture category" />
+ </menu_item_check>
+ <menu_item_check
label="Fast Timers"
layout="topleft"
name="Fast Timers"
@@ -2229,19 +2265,43 @@
label="Disable Textures"
name="Disable Textures">
<menu_item_check.on_check
- function="Advanced.CheckDisableTextures"
- parameter="DisableTextures" />
+ function="CheckControl"
+ parameter="TextureDisable" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="TextureDisable" />
+ </menu_item_check>
+ <menu_item_check
+ label="Full Res Textures"
+ layout="topleft"
+ name="Rull Res Textures">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="TextureLoadFullRes" />
<menu_item_check.on_click
- function="Advanced.ToggleDisableTextures" />
+ function="ToggleControl"
+ parameter="TextureLoadFullRes" />
+ </menu_item_check>
+ <menu_item_check
+ label="Audit Textures"
+ layout="topleft"
+ name="Audit Textures">
+ <menu_item_check.on_check
+ function="CheckControl"
+ parameter="AuditTexture" />
+ <menu_item_check.on_click
+ function="ToggleControl"
+ parameter="AuditTexture" />
</menu_item_check>
<menu_item_check
label="Texture Atlas"
name="Texture Atlas">
<menu_item_check.on_check
- function="Advanced.CheckTextureAtlas"
+ function="CheckControl"
parameter="TextureAtlas" />
<menu_item_check.on_click
- function="Advanced.ToggleTextureAtlas" />
+ function="ToggleControl"
+ parameter="TextureAtlas" />
</menu_item_check>
<menu_item_check
label="Render Attached Lights"
diff --git a/indra/newview/tests/lltextureinfo_test.cpp b/indra/newview/tests/lltextureinfo_test.cpp
new file mode 100644
index 0000000000..8dfba46262
--- /dev/null
+++ b/indra/newview/tests/lltextureinfo_test.cpp
@@ -0,0 +1,284 @@
+/**
+ * @file llwtextureinfo_test.cpp
+ * @author Si & Gabriel
+ * @date 2009-03-30
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltextureinfo.h"
+// Dependencies
+#include "../lltextureinfodetails.cpp"
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct textureinfo_test
+ {
+ // Constructor and destructor of the test wrapper
+ textureinfo_test()
+ {
+ }
+ ~textureinfo_test()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<textureinfo_test> textureinfo_t;
+ typedef textureinfo_t::object textureinfo_object_t;
+ tut::textureinfo_t tut_textureinfo("textureinfo");
+
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLTextureInfo
+ // ---------------------------------------------------------------------------------------
+
+
+ // Test instantiation
+ template<> template<>
+ void textureinfo_object_t::test<1>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+ ensure("have we crashed?", true);
+ }
+
+ // Check lltextureinfo does not contain UUIDs we haven't added
+ template<> template<>
+ void textureinfo_object_t::test<2>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+ ensure(!tex_info.has(nonExistant));
+ }
+
+ // Check we can add a request time for a texture
+ template<> template<>
+ void textureinfo_object_t::test<3>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id, 200);
+
+ ensure_equals(tex_info.getRequestStartTime(id), 200);
+ }
+
+ // Check time for non-existant texture
+ template<> template<>
+ void textureinfo_object_t::test<4>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+ ensure_equals(tex_info.getRequestStartTime(nonExistant), 0);
+ }
+
+ // Check download complete time for non existant texture
+ template<> template<>
+ void textureinfo_object_t::test<5>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+ ensure_equals(tex_info.getRequestCompleteTime(nonExistant), 0);
+ }
+
+ // requested size is passed in correctly
+ template<> template<>
+ void textureinfo_object_t::test<6>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestSize(id, 600);
+
+ ensure_equals(tex_info.getRequestSize(id), 600);
+ }
+
+ // transport type is recorded correctly (http)
+ template<> template<>
+ void textureinfo_object_t::test<7>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+
+ ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ }
+
+ // transport type is recorded correctly (udp)
+ template<> template<>
+ void textureinfo_object_t::test<8>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_UDP);
+
+ ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_UDP);
+ }
+
+ // request offset is recorded correctly
+ template<> template<>
+ void textureinfo_object_t::test<9>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestOffset(id, 1234);
+
+ ensure_equals(tex_info.getRequestOffset(id), 1234);
+ }
+
+ // ask for averages gives us correct figure
+ template<> template<>
+ void textureinfo_object_t::test<10>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ S32 requestStartTimeOne = 200;
+ S32 requestEndTimeOne = 400;
+ S32 requestSizeOne = 1024;
+ S32 requestSizeOneBits = requestSizeOne * 8;
+ LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id1, requestStartTimeOne);
+ tex_info.setRequestSize(id1, requestSizeOne);
+ tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+ U32 requestStartTimeTwo = 100;
+ U32 requestEndTimeTwo = 500;
+ U32 requestSizeTwo = 2048;
+ S32 requestSizeTwoBits = requestSizeTwo * 8;
+ LLUUID id2("10e65d70-46fd-429f-841a-bf698e9424d4");
+ tex_info.setRequestStartTime(id2, requestStartTimeTwo);
+ tex_info.setRequestSize(id2, requestSizeTwo);
+ tex_info.setRequestType(id2, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ tex_info.setRequestCompleteTimeAndLog(id2, requestEndTimeTwo);
+
+ S32 averageBitRate = ((requestSizeOneBits/(requestEndTimeOne - requestStartTimeOne)) +
+ (requestSizeTwoBits/(requestEndTimeTwo - requestStartTimeTwo))) / 2;
+
+ S32 totalBytes = requestSizeOne + requestSizeTwo;
+
+ LLSD results = tex_info.getAverages();
+ ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), averageBitRate);
+ ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), totalBytes);
+ ensure_equals("is transport correct", results["transport"].asString(), std::string("HTTP"));
+ }
+
+ // make sure averages cleared when reset is called
+ template<> template<>
+ void textureinfo_object_t::test<11>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ S32 requestStartTimeOne = 200;
+ S32 requestEndTimeOne = 400;
+ S32 requestSizeOne = 1024;
+ LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id1, requestStartTimeOne);
+ tex_info.setRequestSize(id1, requestSizeOne);
+ tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+ tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+ tex_info.getAverages();
+ tex_info.reset();
+ LLSD results = tex_info.getAverages();
+ ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), 0);
+ ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), 0);
+ ensure_equals("is transport correct", results["transport"].asString(), std::string("NONE"));
+ }
+
+ // make sure map item removed when expired
+ template<> template<>
+ void textureinfo_object_t::test<12>()
+ {
+ LLTextureInfo tex_info;
+ tex_info.setUpLogging(true, true);
+
+ S32 requestStartTimeOne = 200;
+ S32 requestEndTimeOne = 400;
+ S32 requestSizeOne = 1024;
+ LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+ tex_info.setRequestStartTime(id1, requestStartTimeOne);
+ tex_info.setRequestSize(id1, requestSizeOne);
+ tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+
+ ensure_equals("map item created", tex_info.getTextureInfoMapSize(), 1);
+
+ tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+ ensure_equals("map item removed when consumed", tex_info.getTextureInfoMapSize(), 0);
+ }
+}
+
diff --git a/indra/newview/tests/lltextureinfodetails_test.cpp b/indra/newview/tests/lltextureinfodetails_test.cpp
new file mode 100644
index 0000000000..aa2697fb8e
--- /dev/null
+++ b/indra/newview/tests/lltextureinfodetails_test.cpp
@@ -0,0 +1,98 @@
+/**
+ * @file llwtextureinfodetails_test.cpp
+ * @author Si & Gabriel
+ * @date 2009-03-30
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltextureinfodetails.h"
+// Dependencies
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct textureinfodetails_test
+ {
+ // Constructor and destructor of the test wrapper
+ textureinfodetails_test()
+ {
+ }
+ ~textureinfodetails_test()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<textureinfodetails_test> textureinfodetails_t;
+ typedef textureinfodetails_t::object textureinfodetails_object_t;
+ tut::textureinfodetails_t tut_textureinfodetails("textureinfodetails");
+
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLTextureInfo
+ // ---------------------------------------------------------------------------------------
+
+
+ // Test instantiation
+ template<> template<>
+ void textureinfodetails_object_t::test<1>()
+ {
+ ensure("have we crashed?", true);
+ }
+}
diff --git a/indra/newview/tests/lltexturestatsuploader_test.cpp b/indra/newview/tests/lltexturestatsuploader_test.cpp
new file mode 100644
index 0000000000..77a3e2c3d8
--- /dev/null
+++ b/indra/newview/tests/lltexturestatsuploader_test.cpp
@@ -0,0 +1,156 @@
+/**
+ * @file lltexturestatsuploader_test.cpp
+ * @author Si
+ * @date 2009-05-27
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltexturestatsuploader.h"
+// Dependencies
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+#include "boost/intrusive_ptr.hpp"
+void boost::intrusive_ptr_add_ref(LLCurl::Responder*){}
+void boost::intrusive_ptr_release(LLCurl::Responder* p){}
+const F32 HTTP_REQUEST_EXPIRY_SECS = 0.0f;
+
+static std::string most_recent_url;
+static LLSD most_recent_body;
+
+void LLHTTPClient::post(
+ const std::string& url,
+ const LLSD& body,
+ ResponderPtr,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ // set some sensor code
+ most_recent_url = url;
+ most_recent_body = body;
+ return;
+}
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct texturestatsuploader_test
+ {
+ // Constructor and destructor of the test wrapper
+ texturestatsuploader_test()
+ {
+ most_recent_url = "some sort of default text that should never match anything the tests are expecting!";
+ LLSD blank_llsd;
+ most_recent_body = blank_llsd;
+ }
+ ~texturestatsuploader_test()
+ {
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<texturestatsuploader_test> texturestatsuploader_t;
+ typedef texturestatsuploader_t::object texturestatsuploader_object_t;
+ tut::texturestatsuploader_t tut_texturestatsuploader("texturestatsuploader");
+
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLTextureInfo
+ // ---------------------------------------------------------------------------------------
+
+
+ // Test instantiation
+ template<> template<>
+ void texturestatsuploader_object_t::test<1>()
+ {
+ LLTextureStatsUploader tsu;
+ llinfos << &tsu << llendl;
+ ensure("have we crashed?", true);
+ }
+
+ // does it call out to the provided url if we ask it to?
+ template<> template<>
+ void texturestatsuploader_object_t::test<2>()
+ {
+ LLTextureStatsUploader tsu;
+ std::string url = "http://blahblahblah";
+ LLSD texture_stats;
+ tsu.uploadStatsToSimulator(url, texture_stats);
+ ensure_equals("did the right url get called?", most_recent_url, url);
+ ensure_equals("did the right body get sent?", most_recent_body, texture_stats);
+ }
+
+ // does it not call out to the provided url if we send it an ungranted cap?
+ template<> template<>
+ void texturestatsuploader_object_t::test<3>()
+ {
+ LLTextureStatsUploader tsu;
+
+ // this url left intentionally blank to mirror
+ // not getting a cap in the caller.
+ std::string url_for_ungranted_cap = "";
+
+ LLSD texture_stats;
+ std::string most_recent_url_before_test = most_recent_url;
+ tsu.uploadStatsToSimulator(url_for_ungranted_cap, texture_stats);
+
+ ensure_equals("hopefully no url got called!", most_recent_url, most_recent_url_before_test);
+ }
+
+ // does it call out if the data is empty?
+ // should it even do that?
+}
+
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
new file mode 100644
index 0000000000..56cf86f6df
--- /dev/null
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -0,0 +1,523 @@
+/**
+ * @file llworldmap_test.cpp
+ * @author Merov Linden
+ * @date 2009-03-09
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../llworldmap.h"
+// Dependencies
+#include "../llviewerimagelist.h"
+#include "../llworldmapmessage.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+// Stub image calls
+LLViewerImageList::LLViewerImageList() { }
+LLViewerImageList::~LLViewerImageList() { }
+LLViewerImageList gImageList;
+LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
+ BOOL usemipmaps,
+ BOOL level_immediate,
+ LLGLint internal_format,
+ LLGLenum primary_format,
+ LLHost request_from_host)
+{ return NULL; }
+void LLViewerImage::setBoostLevel(S32 level) { }
+void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { }
+
+// Stub related map calls
+LLWorldMapMessage::LLWorldMapMessage() { }
+LLWorldMapMessage::~LLWorldMapMessage() { }
+void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) { }
+void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { }
+LLWorldMipmap::LLWorldMipmap() { }
+LLWorldMipmap::~LLWorldMipmap() { }
+void LLWorldMipmap::reset() { }
+void LLWorldMipmap::dropBoostLevels() { }
+void LLWorldMipmap::equalizeBoostLevels() { }
+LLPointer<LLViewerImage> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load)
+{ return NULL; }
+
+// Stub other stuff
+BOOL gPacificDaylightTime;
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+const F32 X_WORLD_TEST = 1000.0f * REGION_WIDTH_METERS;
+const F32 Y_WORLD_TEST = 2000.0f * REGION_WIDTH_METERS;
+const F32 Z_WORLD_TEST = 240.0f;
+const std::string ITEM_NAME_TEST = "Item Foo";
+const std::string TOOLTIP_TEST = "Tooltip Foo";
+
+const std::string SIM_NAME_TEST = "Sim Foo";
+
+namespace tut
+{
+ // Test wrapper declarations
+ struct iteminfo_test
+ {
+ // Instance to be tested
+ LLItemInfo* mItem;
+
+ // Constructor and destructor of the test wrapper
+ iteminfo_test()
+ {
+ LLUUID id;
+ mItem = new LLItemInfo(X_WORLD_TEST, Y_WORLD_TEST, ITEM_NAME_TEST, id);
+ }
+ ~iteminfo_test()
+ {
+ delete mItem;
+ }
+ };
+
+ struct siminfo_test
+ {
+ // Instance to be tested
+ LLSimInfo* mSim;
+
+ // Constructor and destructor of the test wrapper
+ siminfo_test()
+ {
+ U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+ mSim = new LLSimInfo(handle);
+ }
+ ~siminfo_test()
+ {
+ delete mSim;
+ }
+ };
+
+ struct worldmap_test
+ {
+ // Instance to be tested
+ LLWorldMap* mWorld;
+
+ // Constructor and destructor of the test wrapper
+ worldmap_test()
+ {
+ mWorld = LLWorldMap::getInstance();
+ }
+ ~worldmap_test()
+ {
+ mWorld = NULL;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<iteminfo_test> iteminfo_t;
+ typedef iteminfo_t::object iteminfo_object_t;
+ tut::iteminfo_t tut_iteminfo("iteminfo");
+
+ typedef test_group<siminfo_test> siminfo_t;
+ typedef siminfo_t::object siminfo_object_t;
+ tut::siminfo_t tut_siminfo("siminfo");
+
+ typedef test_group<worldmap_test> worldmap_t;
+ typedef worldmap_t::object worldmap_object_t;
+ tut::worldmap_t tut_worldmap("worldmap");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLItemInfo interface
+ // ---------------------------------------------------------------------------------------
+ template<> template<>
+ void iteminfo_object_t::test<1>()
+ {
+ // Test 1 : setCount() / getCount()
+ mItem->setCount(10);
+ ensure("LLItemInfo::setCount() test failed", mItem->getCount() == 10);
+ // Test 2 : setTooltip() / getToolTip()
+ std::string tooltip = TOOLTIP_TEST;
+ mItem->setTooltip(tooltip);
+ ensure("LLItemInfo::setTooltip() test failed", mItem->getToolTip() == TOOLTIP_TEST);
+ // Test 3 : setElevation() / getGlobalPosition()
+ mItem->setElevation(Z_WORLD_TEST);
+ LLVector3d pos = mItem->getGlobalPosition();
+ LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, Z_WORLD_TEST);
+ ensure("LLItemInfo::getGlobalPosition() test failed", pos == ref);
+ // Test 4 : getName()
+ std::string name = mItem->getName();
+ ensure("LLItemInfo::getName() test failed", name == ITEM_NAME_TEST);
+ // Test 5 : isName()
+ ensure("LLItemInfo::isName() test failed", mItem->isName(name));
+ // Test 6 : getUUID()
+ LLUUID id;
+ ensure("LLItemInfo::getUUID() test failed", mItem->getUUID() == id);
+ // Test 7 : getRegionHandle()
+ U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+ ensure("LLItemInfo::getRegionHandle() test failed", mItem->getRegionHandle() == handle);
+ }
+ // ---------------------------------------------------------------------------------------
+ // Test the LLSimInfo interface
+ // ---------------------------------------------------------------------------------------
+ // Test Setters and Accessors methods
+ template<> template<>
+ void siminfo_object_t::test<1>()
+ {
+ // Test 1 : setName() / getName()
+ std::string name = SIM_NAME_TEST;
+ mSim->setName(name);
+ ensure("LLSimInfo::setName() test failed", mSim->getName() == SIM_NAME_TEST);
+ // Test 2 : isName()
+ ensure("LLSimInfo::isName() test failed", mSim->isName(name));
+ // Test 3 : getGlobalPos()
+ LLVector3 local;
+ LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, 0.0f);
+ LLVector3d pos = mSim->getGlobalPos(local);
+ ensure("LLSimInfo::getGlobalPos() test failed", pos == ref);
+ // Test 4 : getGlobalOrigin()
+ pos = mSim->getGlobalOrigin();
+ ensure("LLSimInfo::getGlobalOrigin() test failed", pos == ref);
+ // Test 5 : clearImage()
+ try {
+ mSim->clearImage();
+ } catch (...) {
+ fail("LLSimInfo::clearImage() test failed");
+ }
+ // Test 6 : dropImagePriority()
+ try {
+ mSim->dropImagePriority();
+ } catch (...) {
+ fail("LLSimInfo::dropImagePriority() test failed");
+ }
+ // Test 7 : updateAgentCount()
+ try {
+ mSim->updateAgentCount(0.0f);
+ } catch (...) {
+ fail("LLSimInfo::updateAgentCount() test failed");
+ }
+ // Test 8 : getAgentCount()
+ S32 agents = mSim->getAgentCount();
+ ensure("LLSimInfo::getAgentCount() test failed", agents == 0);
+ // Test 9 : setLandForSaleImage() / getLandForSaleImage()
+ LLUUID id;
+ mSim->setLandForSaleImage(id);
+ LLPointer<LLViewerImage> image = mSim->getLandForSaleImage();
+ ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull());
+ // Test 10 : isPG()
+ mSim->setAccess(SIM_ACCESS_PG);
+ ensure("LLSimInfo::isPG() test failed", mSim->isPG());
+ // Test 11 : isDown()
+ mSim->setAccess(SIM_ACCESS_DOWN);
+ ensure("LLSimInfo::isDown() test failed", mSim->isDown());
+ // Test 12 : Access strings can't be accessed from unit test...
+ //ensure("LLSimInfo::getAccessString() test failed", mSim->getAccessString() == "Offline");
+ // Test 13 : Region strings can't be accessed from unit test...
+ //mSim->setRegionFlags(REGION_FLAGS_SANDBOX);
+ //ensure("LLSimInfo::setRegionFlags() test failed", mSim->getFlagsString() == "Sandbox");
+ }
+ // Test management of LLInfoItem lists
+ template<> template<>
+ void siminfo_object_t::test<2>()
+ {
+ // Test 14 : clearItems()
+ try {
+ mSim->clearItems();
+ } catch (...) {
+ fail("LLSimInfo::clearItems() at init test failed");
+ }
+
+ // Test 15 : Verify that all the lists are empty
+ LLSimInfo::item_info_list_t list;
+ list = mSim->getTeleHub();
+ ensure("LLSimInfo::getTeleHub() empty at init test failed", list.empty());
+ list = mSim->getInfoHub();
+ ensure("LLSimInfo::getInfoHub() empty at init test failed", list.empty());
+ list = mSim->getPGEvent();
+ ensure("LLSimInfo::getPGEvent() empty at init test failed", list.empty());
+ list = mSim->getMatureEvent();
+ ensure("LLSimInfo::getMatureEvent() empty at init test failed", list.empty());
+ list = mSim->getLandForSale();
+ ensure("LLSimInfo::getLandForSale() empty at init test failed", list.empty());
+ list = mSim->getAgentLocation();
+ ensure("LLSimInfo::getAgentLocation() empty at init test failed", list.empty());
+
+ // Create an item to be inserted
+ LLUUID id;
+ LLItemInfo item(X_WORLD_TEST, Y_WORLD_TEST, ITEM_NAME_TEST, id);
+
+ // Insert the item in each list
+ mSim->insertTeleHub(item);
+ mSim->insertInfoHub(item);
+ mSim->insertPGEvent(item);
+ mSim->insertMatureEvent(item);
+ mSim->insertLandForSale(item);
+ mSim->insertAgentLocation(item);
+
+ // Test 16 : Verify that the lists contain 1 item each
+ list = mSim->getTeleHub();
+ ensure("LLSimInfo::insertTeleHub() test failed", list.size() == 1);
+ list = mSim->getInfoHub();
+ ensure("LLSimInfo::insertInfoHub() test failed", list.size() == 1);
+ list = mSim->getPGEvent();
+ ensure("LLSimInfo::insertPGEvent() test failed", list.size() == 1);
+ list = mSim->getMatureEvent();
+ ensure("LLSimInfo::insertMatureEvent() test failed", list.size() == 1);
+ list = mSim->getLandForSale();
+ ensure("LLSimInfo::insertLandForSale() test failed", list.size() == 1);
+ list = mSim->getAgentLocation();
+ ensure("LLSimInfo::insertAgentLocation() test failed", list.size() == 1);
+
+ // Test 17 : clearItems()
+ try {
+ mSim->clearItems();
+ } catch (...) {
+ fail("LLSimInfo::clearItems() at end test failed");
+ }
+
+ // Test 18 : Verify that all the lists are empty again... *except* agent which is persisted!! (on purpose)
+ list = mSim->getTeleHub();
+ ensure("LLSimInfo::getTeleHub() empty after clear test failed", list.empty());
+ list = mSim->getInfoHub();
+ ensure("LLSimInfo::getInfoHub() empty after clear test failed", list.empty());
+ list = mSim->getPGEvent();
+ ensure("LLSimInfo::getPGEvent() empty after clear test failed", list.empty());
+ list = mSim->getMatureEvent();
+ ensure("LLSimInfo::getMatureEvent() empty after clear test failed", list.empty());
+ list = mSim->getLandForSale();
+ ensure("LLSimInfo::getLandForSale() empty after clear test failed", list.empty());
+ list = mSim->getAgentLocation();
+ ensure("LLSimInfo::getAgentLocation() empty after clear test failed", list.size() == 1);
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLWorldMap interface
+ // ---------------------------------------------------------------------------------------
+ // Test Setters and Accessors methods
+ template<> template<>
+ void worldmap_object_t::test<1>()
+ {
+ // Test 1 : reset()
+ try {
+ mWorld->reset();
+ } catch (...) {
+ fail("LLWorldMap::reset() at init test failed");
+ }
+ // Test 2 : clearImageRefs()
+ try {
+ mWorld->clearImageRefs();
+ } catch (...) {
+ fail("LLWorldMap::clearImageRefs() test failed");
+ }
+ // Test 3 : dropImagePriorities()
+ try {
+ mWorld->dropImagePriorities();
+ } catch (...) {
+ fail("LLWorldMap::dropImagePriorities() test failed");
+ }
+ // Test 4 : reloadItems()
+ try {
+ mWorld->reloadItems(true);
+ } catch (...) {
+ fail("LLWorldMap::reloadItems() test failed");
+ }
+ // Test 5 : updateRegions()
+ try {
+ mWorld->updateRegions(1000, 1000, 1004, 1004);
+ } catch (...) {
+ fail("LLWorldMap::updateRegions() test failed");
+ }
+ // Test 6 : equalizeBoostLevels()
+ try {
+ mWorld->equalizeBoostLevels();
+ } catch (...) {
+ fail("LLWorldMap::equalizeBoostLevels() test failed");
+ }
+ // Test 7 : getObjectsTile()
+ try {
+ LLPointer<LLViewerImage> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
+ ensure("LLWorldMap::getObjectsTile() failed", image.isNull());
+ } catch (...) {
+ fail("LLWorldMap::getObjectsTile() test failed with exception");
+ }
+ }
+ // Test management of LLSimInfo lists
+ template<> template<>
+ void worldmap_object_t::test<2>()
+ {
+ // Test 8 : reset()
+ try {
+ mWorld->reset();
+ } catch (...) {
+ fail("LLWorldMap::reset() at init test failed");
+ }
+
+ // Test 9 : Verify that all the region list is empty
+ LLWorldMap::sim_info_map_t list;
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::getRegionMap() empty at init test failed", list.empty());
+
+ // Test 10 : Insert a region
+ bool success;
+ LLUUID id;
+ std::string name_sim = SIM_NAME_TEST;
+ success = mWorld->insertRegion( U32(X_WORLD_TEST),
+ U32(Y_WORLD_TEST),
+ name_sim,
+ id,
+ SIM_ACCESS_PG,
+ REGION_FLAGS_SANDBOX);
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::insertRegion() failed", success && (list.size() == 1));
+
+ // Test 11 : Insert an item in the same region -> number of regions doesn't increase
+ std::string name_item = ITEM_NAME_TEST;
+ success = mWorld->insertItem( U32(X_WORLD_TEST + REGION_WIDTH_METERS/2),
+ U32(Y_WORLD_TEST + REGION_WIDTH_METERS/2),
+ name_item,
+ id,
+ MAP_ITEM_LAND_FOR_SALE,
+ 0, 0);
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::insertItem() in existing region failed", success && (list.size() == 1));
+
+ // Test 12 : Insert an item in another region -> number of regions increases
+ success = mWorld->insertItem( U32(X_WORLD_TEST + REGION_WIDTH_METERS*2),
+ U32(Y_WORLD_TEST + REGION_WIDTH_METERS*2),
+ name_item,
+ id,
+ MAP_ITEM_LAND_FOR_SALE,
+ 0, 0);
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::insertItem() in unexisting region failed", success && (list.size() == 2));
+
+ // Test 13 : simInfoFromPosGlobal() in region
+ LLVector3d pos1( X_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2,
+ Y_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2,
+ 0.0f);
+ LLSimInfo* sim;
+ sim = mWorld->simInfoFromPosGlobal(pos1);
+ ensure("LLWorldMap::simInfoFromPosGlobal() test on existing region failed", sim != NULL);
+
+ // Test 14 : simInfoFromPosGlobal() outside region
+ LLVector3d pos2( X_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2,
+ Y_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2,
+ 0.0f);
+ sim = mWorld->simInfoFromPosGlobal(pos2);
+ ensure("LLWorldMap::simInfoFromPosGlobal() test outside region failed", sim == NULL);
+
+ // Test 15 : simInfoFromName()
+ sim = mWorld->simInfoFromName(name_sim);
+ ensure("LLWorldMap::simInfoFromName() test on existing region failed", sim != NULL);
+
+ // Test 16 : simInfoFromHandle()
+ U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+ sim = mWorld->simInfoFromHandle(handle);
+ ensure("LLWorldMap::simInfoFromHandle() test on existing region failed", sim != NULL);
+
+ // Test 17 : simNameFromPosGlobal()
+ LLVector3d pos3( X_WORLD_TEST + REGION_WIDTH_METERS/2,
+ Y_WORLD_TEST + REGION_WIDTH_METERS/2,
+ 0.0f);
+ success = mWorld->simNameFromPosGlobal(pos3, name_sim);
+ ensure("LLWorldMap::simNameFromPosGlobal() test on existing region failed", success && (name_sim == SIM_NAME_TEST));
+
+ // Test 18 : reset()
+ try {
+ mWorld->reset();
+ } catch (...) {
+ fail("LLWorldMap::reset() at end test failed");
+ }
+
+ // Test 19 : Verify that all the region list is empty
+ list = mWorld->getRegionMap();
+ ensure("LLWorldMap::getRegionMap() empty at end test failed", list.empty());
+ }
+ // Test tracking
+ template<> template<>
+ void worldmap_object_t::test<3>()
+ {
+ // Point to track
+ LLVector3d pos( X_WORLD_TEST + REGION_WIDTH_METERS/2, Y_WORLD_TEST + REGION_WIDTH_METERS/2, Z_WORLD_TEST);
+
+ // Test 20 : no tracking
+ mWorld->cancelTracking();
+ ensure("LLWorldMap::cancelTracking() at begin test failed", mWorld->isTracking() == false);
+
+ // Test 21 : set tracking
+ mWorld->setTracking(pos);
+ ensure("LLWorldMap::setTracking() failed", mWorld->isTracking() && !mWorld->isTrackingValidLocation());
+
+ // Test 22 : set click and commit flags
+ mWorld->setTrackingDoubleClick();
+ ensure("LLWorldMap::setTrackingDoubleClick() failed", mWorld->isTrackingDoubleClick());
+ mWorld->setTrackingCommit();
+ ensure("LLWorldMap::setTrackingCommit() failed", mWorld->isTrackingCommit());
+
+ // Test 23 : in rectangle test
+ bool inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST, Y_WORLD_TEST,
+ X_WORLD_TEST + REGION_WIDTH_METERS,
+ Y_WORLD_TEST + REGION_WIDTH_METERS);
+ ensure("LLWorldMap::isTrackingInRectangle() in rectangle failed", inRect);
+ inRect = mWorld->isTrackingInRectangle( X_WORLD_TEST + REGION_WIDTH_METERS,
+ Y_WORLD_TEST + REGION_WIDTH_METERS,
+ X_WORLD_TEST + 2 * REGION_WIDTH_METERS,
+ Y_WORLD_TEST + 2 * REGION_WIDTH_METERS);
+ ensure("LLWorldMap::isTrackingInRectangle() outside rectangle failed", !inRect);
+
+ // Test 24 : set tracking to valid and invalid
+ mWorld->setTrackingValid();
+ ensure("LLWorldMap::setTrackingValid() failed", mWorld->isTrackingValidLocation() && !mWorld->isTrackingInvalidLocation());
+ mWorld->setTrackingInvalid();
+ ensure("LLWorldMap::setTrackingInvalid() failed", !mWorld->isTrackingValidLocation() && mWorld->isTrackingInvalidLocation());
+
+ // Test 25 : getTrackedPositionGlobal()
+ LLVector3d res = mWorld->getTrackedPositionGlobal();
+ ensure("LLWorldMap::getTrackedPositionGlobal() failed", res == pos);
+
+ // Test 26 : reset tracking
+ mWorld->cancelTracking();
+ ensure("LLWorldMap::cancelTracking() at end test failed", mWorld->isTracking() == false);
+ }
+}
diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp
new file mode 100644
index 0000000000..9938175c55
--- /dev/null
+++ b/indra/newview/tests/llworldmipmap_test.cpp
@@ -0,0 +1,176 @@
+/**
+ * @file llworldmipmap_test.cpp
+ * @author Merov Linden
+ * @date 2009-02-03
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../llworldmipmap.h"
+// Dependencies
+#include "../llviewerimagelist.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+LLViewerImageList::LLViewerImageList() { }
+LLViewerImageList::~LLViewerImageList() { }
+
+LLViewerImageList gImageList;
+
+LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url,
+ BOOL usemipmaps,
+ BOOL level_immediate,
+ LLGLint internal_format,
+ LLGLenum primary_format,
+ const LLUUID& force_id)
+{ return NULL; }
+void LLViewerImage::setBoostLevel(S32 level) { }
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+ // Test wrapper declaration
+ struct worldmipmap_test
+ {
+ // Derived test class
+ class LLTestWorldMipmap : public LLWorldMipmap
+ {
+ // Put here stubbs of virtual methods we shouldn't call all the way down
+ };
+ // Instance to be tested
+ LLTestWorldMipmap* mMap;
+
+ // Constructor and destructor of the test wrapper
+ worldmipmap_test()
+ {
+ mMap = new LLTestWorldMipmap;
+ }
+ ~worldmipmap_test()
+ {
+ delete mMap;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<worldmipmap_test> worldmipmap_t;
+ typedef worldmipmap_t::object worldmipmap_object_t;
+ tut::worldmipmap_t tut_worldmipmap("worldmipmap");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+ // Test static methods
+ // Test 1 : scaleToLevel()
+ template<> template<>
+ void worldmipmap_object_t::test<1>()
+ {
+ S32 level = mMap->scaleToLevel(0.0);
+ ensure("scaleToLevel() test 1 failed", level == LLWorldMipmap::MAP_LEVELS);
+ level = mMap->scaleToLevel(LLWorldMipmap::MAP_TILE_SIZE);
+ ensure("scaleToLevel() test 2 failed", level == 1);
+ level = mMap->scaleToLevel(10 * LLWorldMipmap::MAP_TILE_SIZE);
+ ensure("scaleToLevel() test 3 failed", level == 1);
+ }
+ // Test 2 : globalToMipmap()
+ template<> template<>
+ void worldmipmap_object_t::test<2>()
+ {
+ U32 grid_x, grid_y;
+ mMap->globalToMipmap(1000.f*REGION_WIDTH_METERS, 1000.f*REGION_WIDTH_METERS, 1, &grid_x, &grid_y);
+ ensure("globalToMipmap() test 1 failed", (grid_x == 1000) && (grid_y == 1000));
+ mMap->globalToMipmap(0.0, 0.0, LLWorldMipmap::MAP_LEVELS, &grid_x, &grid_y);
+ ensure("globalToMipmap() test 2 failed", (grid_x == 0) && (grid_y == 0));
+ }
+ // Test 3 : getObjectsTile()
+ template<> template<>
+ void worldmipmap_object_t::test<3>()
+ {
+ // Depends on some inline methods in LLViewerImage... Thinking about how to make this work
+ // LLPointer<LLViewerImage> img = mMap->getObjectsTile(0, 0, 1);
+ // ensure("getObjectsTile() test failed", img.isNull());
+ }
+ // Test 4 : equalizeBoostLevels()
+ template<> template<>
+ void worldmipmap_object_t::test<4>()
+ {
+ try
+ {
+ mMap->equalizeBoostLevels();
+ }
+ catch (...)
+ {
+ fail("equalizeBoostLevels() test failed");
+ }
+ }
+ // Test 5 : dropBoostLevels()
+ template<> template<>
+ void worldmipmap_object_t::test<5>()
+ {
+ try
+ {
+ mMap->dropBoostLevels();
+ }
+ catch (...)
+ {
+ fail("dropBoostLevels() test failed");
+ }
+ }
+ // Test 6 : reset()
+ template<> template<>
+ void worldmipmap_object_t::test<6>()
+ {
+ try
+ {
+ mMap->reset();
+ }
+ catch (...)
+ {
+ fail("reset() test failed");
+ }
+ }
+}