diff options
151 files changed, 8429 insertions, 4076 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 a1fcd2cf8d..b08bb617c5 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -70,9 +70,9 @@ class LL_COMMON_API 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 LL_COMMON_API 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 LL_COMMON_API LLAPRFile + +class LL_COMMON_API 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 8bfa5632a1..9a9dbb18cc 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -166,6 +166,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(); @@ -200,6 +203,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 c3d7650bd9..932d96d940 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 a12bd52a64..a1e85d2ecc 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -52,6 +52,7 @@ class LLWorkerClass;  class LL_COMMON_API 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 73c23fa8d8..575ad5363d 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 2352c8edd7..74f08b2d0b 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -283,6 +283,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); @@ -295,7 +296,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  	{ @@ -348,7 +349,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 5ff41322b7..dc02367a62 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -229,7 +229,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(); @@ -441,7 +441,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(); @@ -474,8 +476,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  }  //////////////////////////////////////////////////////////////////////////// @@ -685,15 +692,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; @@ -723,17 +733,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)  	{ @@ -745,14 +758,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(); @@ -772,6 +788,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(); ) @@ -791,6 +808,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(); ) @@ -1011,7 +1029,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 0b58e7c4a5..1bc1767966 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -194,12 +194,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(); @@ -213,6 +215,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 e6a5ad9946..ffbe7bd202 100644 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -20,6 +20,7 @@   */  #include "linden_common.h" +#include "llcurl.h"  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 0cd9667644..7034e9199d 100644 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -63,7 +63,7 @@ public:  	//  	virtual S8         getType() const = 0 ;  	virtual void       setKnownDrawSize(S32 width, S32 height) = 0 ; -	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 af22e3eaf9..b63183026a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -268,7 +268,6 @@ set(viewer_SOURCE_FILES      llmaniprotate.cpp      llmanipscale.cpp      llmaniptranslate.cpp -    llmapresponders.cpp      llmediactrl.cpp      llmediadataclient.cpp      llmediaremotectrl.cpp @@ -397,6 +396,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 @@ -522,6 +525,8 @@ set(viewer_SOURCE_FILES      llwlparamset.cpp      llworld.cpp      llworldmap.cpp +    llworldmapmessage.cpp +    llworldmipmap.cpp      llworldmapview.cpp      llxmlrpclistener.cpp      llxmlrpctransaction.cpp @@ -757,7 +762,6 @@ set(viewer_HEADER_FILES      llmaniprotate.h      llmanipscale.h      llmaniptranslate.h -    llmapresponders.h      llmediactrl.h      llmediadataclient.h      llmediaremotectrl.h @@ -885,6 +889,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 @@ -1011,6 +1019,8 @@ set(viewer_HEADER_FILES      llwlparamset.h      llworld.h      llworldmap.h +    llworldmapmessage.h +    llworldmipmap.h      llworldmapview.h      llxmlrpclistener.h      llxmlrpctransaction.h @@ -1666,6 +1676,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 e8af26c743..6f6d5fb979 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> @@ -3574,7 +3585,7 @@        <key>Type</key>        <string>String</string>        <key>Value</key> -      <string>http://www.google.com/search?q=site%3Awiki.secondlife.com+[TOPIC]&ignore_channel=[CHANNEL]&ignore_version=[VERSION]&ignore_os=[OS]&ignore_language=[LANGUAGE]&ignore_version_major=[VERSION_MAJOR]&ignore_version_minor=[VERSION_MINOR]&ignore_version_patch=[VERSION_PATCH]&ignore_version_build=[VERSION_BUILD]</string> +      <string>http://docs.lindenlab.com/help/helpfloater.php?topic=[TOPIC]&channel=[CHANNEL]&version=[VERSION]&os=[OS]&language=[LANGUAGE]&version_major=[VERSION_MAJOR]&version_minor=[VERSION_MINOR]&version_patch=[VERSION_PATCH]&version_build=[VERSION_BUILD]</string>      </map>      <key>HighResSnapshot</key>      <map> @@ -4567,6 +4578,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> @@ -4581,7 +4603,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> @@ -6247,7 +6269,7 @@      <key>Type</key>      <string>Boolean</string>      <key>Value</key> -    <integer>0</integer> +    <integer>1</integer>    </map>    <key>RenderHighlightFadeTime</key> @@ -8611,6 +8633,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> @@ -10669,5 +10713,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 75a72e5b17..24bdf66c2a 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -75,6 +75,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" @@ -6085,17 +6087,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]))) @@ -6512,3 +6513,4 @@ LLAgentQueryManager::~LLAgentQueryManager()  }  // EOF + diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e95eec4741..8e6d6b885d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -57,6 +57,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" @@ -255,9 +257,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; @@ -419,7 +418,7 @@ static void settings_to_globals()  	gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");  	gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates"); -	gMapScale = gSavedSettings.getF32("MapScale"); +	LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");  	LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");  } @@ -432,7 +431,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())  	{ @@ -553,7 +552,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() :  @@ -657,6 +656,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. @@ -1637,14 +1639,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)  	{ @@ -2437,7 +2439,7 @@ void LLAppViewer::cleanupSavedSettings()  		}  	} -	gSavedSettings.setF32("MapScale", gMapScale ); +	gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );  	// Some things are cached in LLAgent.  	if (gAgent.mInitialized) @@ -2763,7 +2765,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())  	{ diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 73256a8fe6..c1bfbca868 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -41,15 +41,13 @@ class LLCommandLineParser;  class LLFrameTimer;  class LLPumpIO;  class LLTextureCache; +class LLImageDecodeThread;  class LLTextureFetch; -class LLTimer; -class LLVFS;  class LLWatchdogTimeout; -class LLWorkerThread; +class LLCommandLineParser;  struct apr_dso_handle_t; -  class LLAppViewer : public LLApp  {  public: @@ -100,7 +98,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; } @@ -232,7 +230,7 @@ private:  	// Thread objects.  	static LLTextureCache* sTextureCache;  -	static LLWorkerThread* sImageDecodeThread;  +	static LLImageDecodeThread* sImageDecodeThread;   	static LLTextureFetch* sTextureFetch;  	S32 mNumSessions; @@ -320,9 +318,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 d4df6dfbe7..4d85ecb97c 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -369,7 +369,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  @@ -383,6 +383,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 ed304bdd34..442e9ab27b 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,  +			LLPointer<LLViewerFetchedTexture> fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE,   				LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);  			if( fallback_image->getComponents() == 4 )  			{	 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 d8c34581d5..95ddacb722 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();  		} @@ -475,17 +475,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 8ec448e281..c54b83d865 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();  	} @@ -1314,6 +1322,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 2b134c8c31..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,6 +253,13 @@ 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 ; 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 0f4d6e33a3..1002697fe5 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, LLViewerTexture::BOOST_NONE, 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 412011e76a..7d2eb98111 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -56,7 +56,6 @@  #include "llregionhandle.h"  #include "llscrolllistctrl.h"  #include "llslurl.h" -#include "lltabcontainer.h"  #include "lltextbox.h"  #include "lltracker.h"  #include "lltrans.h" @@ -64,7 +63,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" @@ -80,6 +81,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, @@ -190,11 +197,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));	 @@ -213,17 +220,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) @@ -251,8 +248,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); @@ -265,7 +262,7 @@ BOOL LLFloaterWorldMap::postBuild()  LLFloaterWorldMap::~LLFloaterWorldMap()  {  	// All cleaned up by LLView destructor -	mTabs = NULL; +	mPanel = NULL;  	// Inventory deletes all observers on shutdown  	mInventory = NULL; @@ -298,7 +295,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();  	{ @@ -309,15 +306,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. @@ -351,12 +341,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)  { @@ -388,12 +375,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();  } @@ -475,7 +456,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); @@ -495,6 +476,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();  } @@ -583,14 +576,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");  } @@ -599,29 +592,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)",  @@ -633,9 +624,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");  } @@ -748,9 +737,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();  	}  } @@ -817,19 +806,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); @@ -850,10 +832,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(); @@ -894,7 +873,6 @@ void LLFloaterWorldMap::buildLandmarkIDLists()  		mLandmarkAssetIDList.put( item->getAssetUUID() );  		mLandmarkItemIDList.put( item->getUUID() );  	} -	list->sortByColumn(std::string("landmark name"), TRUE);  	list->selectFirstItem();  } @@ -931,7 +909,7 @@ void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)  	{  		childSetValue("spin z", 0);  	} -	LLWorldMap::getInstance()->mIsTrackingCommit = FALSE; +	LLWorldMap::getInstance()->cancelTracking();  	mCompletingRegionName = "";  } @@ -967,18 +945,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 @@ -1191,15 +1167,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);  	}  } @@ -1207,8 +1183,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  } @@ -1260,9 +1236,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  	{ @@ -1270,8 +1246,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;  } @@ -1429,13 +1405,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 == "") @@ -1452,24 +1421,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++;  		} @@ -1526,15 +1494,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 b1829b3945..e0dc1b6f0f 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" @@ -305,13 +306,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);  	}  } @@ -322,18 +323,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);  	}  } @@ -365,7 +367,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 4f145891ea..63794be085 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -52,7 +52,7 @@  #include "llviewerinventory.h"  #include "llviewermenu.h"  #include "llviewerparcelmgr.h" -#include "llworldmap.h" +#include "llworldmapmessage.h"  #include "llappviewer.h"  #include "llviewercontrol.h"  #include "llfloatermediabrowser.h" @@ -393,14 +393,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 a34f029095..28e89fd619 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -359,7 +359,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 86fa2c4695..62847d15e2 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, LLViewerTexture::BOOST_NONE, 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 279e143851..8c5439d47e 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 b23e7feda2..4c322810d5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -60,6 +60,7 @@  #include "llfocusmgr.h"  #include "llhttpsender.h"  #include "lllocationhistory.h" +#include "llimageworker.h"  #include "llloginflags.h"  #include "llmd5.h"  #include "llmemorystream.h" @@ -168,7 +169,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" @@ -1310,6 +1311,7 @@ bool idle_startup()  			gViewerWindow->moveProgressViewToFront();  			LLError::logToFixedBuffer(gDebugView->mDebugConsolep); +			  			// set initial visibility of debug console  			gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));  		} @@ -2525,9 +2527,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 73340cbc03..5d682cad3c 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -1388,7 +1388,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)  					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 ); @@ -1410,7 +1410,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)  			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);  			} @@ -1523,7 +1523,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);  		} @@ -1602,7 +1602,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 ); @@ -1621,7 +1621,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);  			} @@ -2043,7 +2043,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 dafa4f25ca..b6e20608eb 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/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 24017202cc..93da32b115 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -494,6 +494,8 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)  	}  	else if (handleMediaHover(mHoverPick))  	{ +		// *NOTE: If you think the hover glow conflicts with the media outline, you +		// could disable it here.  		show_highlight = true;  		// cursor set by media object  		lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; 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 ¢er,  	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 35226a1632..5e23a7e114 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; @@ -587,6 +593,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 b30acd47f1..d158fc29a6 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -609,6 +609,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 ); @@ -636,6 +644,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 ); @@ -1160,28 +1176,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 //  ////////////////////// @@ -1884,7 +1878,7 @@ class LLAdvancedRebakeTextures : public view_listener_t  }; -#ifndef LL_RELEASE_FOR_DOWNLOAD +#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD  ///////////////////////////  // DEBUG AVATAR TEXTURES //  /////////////////////////// @@ -3483,9 +3477,8 @@ void set_god_level(U8 god_level)  	gAgent.setGodLevel( god_level );  	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(); @@ -7777,8 +7770,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 26411ce152..e491e11960 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 6b8c8c01d4..b2d7d71b53 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 @@ -162,6 +172,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(BOOL usemipma  	if(generate_gl_tex)  	{  		tex->generateGLTexture() ; +		tex->setCategory(LLViewerTexture::LOCAL) ;  	}  	return tex ;  } @@ -171,12 +182,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)  @@ -185,6 +198,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 wid  	if(generate_gl_tex)  	{  		tex->generateGLTexture() ; +		tex->setCategory(LLViewerTexture::LOCAL) ;  	}  	return tex ;  } @@ -215,6 +229,19 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile(  	return gTextureList.getImageFromFile(filename, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ;  } +//static  +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url,									  +									 BOOL usemipmaps, +									 S32 boost_priority, +									 S8 texture_type, +									 LLGLint internal_format, +									 LLGLenum primary_format, +									 const LLUUID& force_id +									 ) +{ +	return gTextureList.getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ; +} +  LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host)   {  	return gTextureList.getImageFromHost(image_id, host) ; @@ -256,11 +283,12 @@ void LLViewerTextureManager::init()  	}  	imagep->createGLTexture(0, image_raw);  	image_raw = NULL; -	LLViewerFetchedTexture::sDefaultImagep->dontDiscard();  #else   	LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLViewerTexture::BOOST_UI);  #endif -	 +	LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); +	LLViewerFetchedTexture::sDefaultImagep->setCategory(LLViewerTexture::OTHER) ; +   	LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, TRUE, LLViewerTexture::BOOST_UI);  	LLViewerFetchedTexture::sSmokeImagep->setNoDelete() ; @@ -284,6 +312,8 @@ void LLViewerTextureManager::cleanup()  	LLViewerFetchedTexture::sWhiteImagep = NULL;  	LLViewerMediaTexture::cleanup() ;	 + +	LLViewerTexture::cleanupClass() ;  }  //---------------------------------------------------------------------------------------------- @@ -294,6 +324,11 @@ void LLViewerTextureManager::cleanup()  void LLViewerTexture::initClass()  {  	LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ; + +	if(gAuditTexture) +	{ +		LLImageGL::setHighlightTexture(LLViewerTexture::OTHER) ;	 +	}  }  // static @@ -301,6 +336,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; @@ -312,6 +366,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() ; @@ -352,6 +408,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 @@ -417,7 +480,9 @@ void LLViewerTexture::init(bool firstinit)  	mTextureState = NO_DELETE ;  	mDontDiscard = FALSE;  	mMaxVirtualSize = 0.f; +	mNeedsGLTexture = FALSE ;  	mNeedsResetMaxVirtualSize = FALSE ; +	mAdditionalDecodePriority = 0.f ;	  	mParcelMedia = NULL ;  } @@ -459,11 +524,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; @@ -482,6 +551,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() ; @@ -500,24 +573,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  @@ -544,6 +625,12 @@ void LLViewerTexture::removeFace(LLFace* facep)  	mFaceList.remove(facep) ;  } +//virtual +void LLViewerTexture::switchToCachedImage() +{ +	//nothing here. +} +  void LLViewerTexture::forceActive()  {  	mTextureState = ACTIVE ;  @@ -588,11 +675,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)  	{ @@ -704,6 +791,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()) ; @@ -752,18 +846,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 @@ -803,6 +897,11 @@ void LLViewerTexture::destroyGLTexture()  	}	  } +BOOL LLViewerTexture::isLargeImage() +{ +	return mFullWidth * mFullHeight > LLViewerTexture::sMinLargeImageSize ; +} +  //virtual   void LLViewerTexture::updateBindStatsForTester()  { @@ -823,11 +922,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() ; @@ -839,9 +939,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() ; @@ -890,6 +990,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() @@ -926,11 +1036,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()   @@ -965,17 +1089,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;  } @@ -996,6 +1140,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*/)  { @@ -1017,7 +1230,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(); @@ -1063,7 +1276,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() ; @@ -1117,7 +1330,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() ;  	} @@ -1177,8 +1398,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); @@ -1188,11 +1412,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 @@ -1242,7 +1479,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()  		{  			ddiscard+=2;  		} -		else if (mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == LLViewerTexture::BOOST_NONE) +		else if (ddiscard > 2 && mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == LLViewerTexture::BOOST_NONE)  		{  			ddiscard-=2;  		} @@ -1251,7 +1488,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 - LLViewerTexture::BOOST_NONE); @@ -1260,6 +1500,12 @@ F32 LLViewerFetchedTexture::calcDecodePriority()  		{  			priority +=      0.f + pixel_priority + 1000.f * (mBoostLevel - LLViewerTexture::BOOST_NONE);  		} + +		// priority range = [2100000.f, 5000000.f] if mAdditionalDecodePriority > 1.0 +		if(mAdditionalDecodePriority > 1.0f) +		{ +			priority += 2000000.f + mAdditionalDecodePriority ; +		}  	}  	return priority;  } @@ -1271,6 +1517,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; @@ -1310,6 +1590,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); @@ -1349,11 +1638,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  			{ @@ -1376,13 +1678,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 @@ -1391,12 +1693,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; @@ -1409,6 +1728,10 @@ bool LLViewerFetchedTexture::updateFetch()  	{  		make_request = false;  	} +	else if (!isJustBound() && mCachedRawImageReady) +	{ +		make_request = false; +	}  	else  	{  		if (mIsFetching) @@ -1436,33 +1759,12 @@ bool LLViewerFetchedTexture::updateFetch()  			h = mGLTexturep->getHeight(0);  			c = mComponents;  		} -		if (!mDontDiscard) -		{ -			if (mBoostLevel == LLViewerTexture::BOOST_NONE) -			{ -				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; @@ -1492,9 +1794,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); @@ -1516,7 +1891,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; @@ -1645,7 +2026,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  		// We have GL data.  		destroyRawImage(); -		readBackRawImage(gl_discard); +		reloadRawImage(mLoadedCallbackDesiredDiscardLevel);  		llassert_always(mRawImage.notNull());  		llassert_always(!mNeedsAux || mAuxRawImage.notNull());  	} @@ -1754,8 +2135,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); @@ -1765,25 +2145,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  //---------------------------------------------------------------------------------------------- @@ -1981,14 +2552,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) ;  } @@ -2006,12 +2577,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) @@ -2040,13 +2624,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; @@ -2057,6 +2635,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))  			{ @@ -2073,13 +2657,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) @@ -2098,46 +2680,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  //---------------------------------------------------------------------------------------------- @@ -2226,6 +2801,8 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL  	setMediaImpl() ; +	setCategory(LLViewerTexture::MEDIA) ; +	  	LLViewerTexture* tex = gTextureList.findImage(mID) ;  	if(tex) //this media is a parcel media for tex.  	{ @@ -2770,7 +3347,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 ff8f14e879..4da6620658 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -123,10 +123,23 @@ public:  		BOOST_UI			= 16,  		BOOST_PREVIEW		= 17,  		BOOST_MAP			= 18, -		BOOST_AVATAR_SELF	= 19, // needed for baking avatar -		BOOST_MAX_LEVEL +		BOOST_MAP_VISIBLE	= 19, +		BOOST_AVATAR_SELF	= 20, // needed for baking avatar +		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: @@ -147,7 +160,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; } @@ -155,9 +168,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 ;} @@ -182,7 +195,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); @@ -190,7 +203,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; @@ -203,8 +217,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 ; @@ -222,6 +236,8 @@ public:  	BOOL getDontDiscard() const { return mDontDiscard; }  	//-----------------	 +	BOOL isLargeImage() ;	 +	  	void setParcelMedia(LLViewerMediaTexture* media) {mParcelMedia = media;}  	BOOL hasParcelMedia() const { return mParcelMedia != NULL;}  	LLViewerMediaTexture* getParcelMedia() const { return mParcelMedia;} @@ -234,6 +250,7 @@ protected:  private:  	//note: do not make this function public.  	/*virtual*/ LLImageGL* getGLTexture() const ; +	virtual void switchToCachedImage();  protected:  	LLUUID mID; @@ -243,7 +260,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 @@ -279,7 +298,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. @@ -299,9 +323,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(); @@ -337,6 +361,8 @@ public:  	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	  	bool doLoadedCallbacks(); +	void addToCreateTexture(); +  	 // ONLY call from LLViewerTextureList  	BOOL createTexture(S32 usename = 0);  	void destroyTexture() ;	 @@ -355,7 +381,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; } @@ -379,15 +410,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() ; @@ -398,13 +429,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() ; @@ -425,11 +479,8 @@ protected:  	S32 mKnownDrawWidth;  	S32	mKnownDrawHeight;  	BOOL mKnownDrawSizeChanged ; - -	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; @@ -439,6 +490,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 @@ -446,10 +501,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; @@ -459,6 +514,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 @@ -487,15 +555,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: @@ -611,7 +681,16 @@ public:  	static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename,									   									 BOOL usemipmap = TRUE, -									 S32 boost_priority = LLViewerTexture::BOOST_NONE,		// Get the requested level immediately upon creation. +									 S32 boost_priority = LLViewerTexture::BOOST_NONE, +									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, +									 LLGLint internal_format = 0, +									 LLGLenum primary_format = 0, +									 const LLUUID& force_id = LLUUID::null +									 ); + +	static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,									  +									 BOOL usemipmap = TRUE, +									 S32 boost_priority = LLViewerTexture::BOOST_NONE,  									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,  									 LLGLint internal_format = 0,  									 LLGLenum primary_format = 0, diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index d2be1ac9b5..081b7cc483 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, LLViewerTexture::BOOST_UI);  	} -	std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename); -	if (full_path.empty()) +	std::string url = "file://" + full_path; + +	return getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); +} + +LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url, +												   BOOL usemipmaps, +												   S32 boost_priority, +												   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, LLViewerTexture::BOOST_UI);  	} @@ -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 ; @@ -428,18 +451,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); @@ -517,7 +537,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; @@ -534,7 +554,7 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)  		}  		llverify(mUUIDMap.erase(image->getID()) == 1); -		mNumImages--; +		sNumImages--;  		removeImageFromList(image);  	}  } @@ -554,7 +574,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)); @@ -562,10 +584,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); @@ -578,7 +603,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(); @@ -636,6 +661,14 @@ void LLViewerTextureList::updateImagesDecodePriorities()  			}  			else  			{ +				if(imagep->hasSavedRawImage()) +				{ +					if(imagep->getElapsedLastReferencedSavedRawImageTime() > MAX_INACTIVE_TIME) +					{ +						imagep->destroySavedRawImage() ; +					} +				} +  				if(imagep->isDeleted())  				{  					continue ; @@ -766,74 +799,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; @@ -1019,6 +1054,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()  { @@ -1137,13 +1175,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; @@ -1202,13 +1240,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); @@ -1401,7 +1439,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(); @@ -1458,6 +1496,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 6948db70f8..3c9c81a689 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 9b3dbcd2f6..fc09c946af 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -121,6 +121,7 @@  #include "llhudview.h"  #include "llimagebmp.h"  #include "llimagej2c.h" +#include "llimageworker.h"  #include "llkeyboard.h"  #include "lllineeditor.h"  #include "llmenugl.h" @@ -160,7 +161,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" @@ -192,6 +192,7 @@  #include "llbottomtray.h"  #include "llnearbychatbar.h"  #include "llagentui.h" +#include "llwearablelist.h"  #include "llnotificationmanager.h" @@ -330,7 +331,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; @@ -1304,6 +1307,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(); @@ -1670,6 +1674,8 @@ void LLViewerWindow::shutdownGL()  	gSky.cleanup();  	stop_glerror(); +	LLWearableList::instance().cleanup() ; +  	gTextureList.shutdown();  	stop_glerror(); @@ -1683,7 +1689,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 d7c403739e..c2906b1718 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -324,7 +324,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 acf1222455..a6f20922d9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -998,7 +998,7 @@ void LLVOAvatar::resetImpostors()  // static  void LLVOAvatar::deleteCachedImages(bool clearAll) -{ +{	  	if (LLTexLayerSet::sHasCaches)  	{  		lldebugs << "Deleting layer set caches" << llendl; @@ -3918,7 +3918,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); @@ -3966,7 +3966,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 cf86612ce6..173ad02808 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 6c3348b247..7a83070770 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1171,26 +1171,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; @@ -1841,12 +1821,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 @@ -2144,6 +2125,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() ) @@ -2166,7 +2190,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); @@ -2178,12 +2203,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; @@ -2191,9 +2216,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 )  	{ @@ -2239,6 +2263,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 6e52b33634..8a66422c44 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -241,7 +241,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 110433a27d..f33a5cc818 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 143cd2d9c6..9dd0b598dc 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 d37deaf53d..5ff8f0d267 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 ec118d89bc..235e10f716 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 f6343b4134..78f534bacd 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; @@ -151,7 +148,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; @@ -564,28 +560,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;  	} @@ -602,14 +602,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(); @@ -619,12 +620,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)  		{ @@ -636,7 +635,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; @@ -668,32 +666,44 @@ void LLVOVolume::updateTextures()  		mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, 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()) @@ -714,10 +724,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))); @@ -729,36 +739,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.f) -	{ -		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()*F_PI; -	if (texel_area <= 0.f) -	{ -		// 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()); @@ -835,7 +815,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 @@ -890,7 +869,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail  				{  					sculpt();  				} -				mSculptLevel = getVolume()->getSculptLevel();  			}  		}  		else @@ -905,32 +883,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  @@ -951,18 +919,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; @@ -974,10 +931,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(); @@ -1013,12 +970,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(); @@ -2783,7 +2734,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  		{ @@ -2798,8 +2749,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; @@ -3046,7 +2997,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 00810b22c4..0574d3e385 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(); @@ -284,7 +284,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 355d4141c3..66cb02ce99 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -34,57 +34,81 @@  #include "llworldmap.h" -#include "llregionhandle.h" +#include "llworldmapmessage.h"  #include "message.h" - -#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, LLViewerTexture::BOOST_MAP, 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, LLViewerTexture::BOOST_MAP, 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]; @@ -93,128 +117,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();  		}  	}  } @@ -222,15 +302,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); @@ -242,11 +332,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;  } @@ -257,763 +343,273 @@ 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) -{ -	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() +// 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)  { -	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; -	} +	// Create an item record for the received object +	LLItemInfo new_item((F32)x_world, (F32)y_world, name, uuid); -	LLUUID image_id; -	//U32 left, right, top, bottom; +	// 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); -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_LayerData); - -	LLWorldMap::getInstance()->mMapLayers[agent_flags].clear(); - -	BOOL adjust = FALSE; -	for (S32 block=0; block<num_blocks; ++block) +	// 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)  	{ -		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, LLViewerTexture::BOOST_NONE, 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); +		siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);  	} -	LLWorldMap::getInstance()->mMapLoaded[agent_flags] = TRUE; -	if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); -} - -// public static -void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**) -{ -	U32 agent_flags; -	msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); - -	if ((S32)agent_flags < 0 || agent_flags >= MAP_SIM_IMAGE_TYPES) +	//LL_INFOS("World Map") << "Process item : type = " << type << LL_ENDL; +	switch (type)  	{ -		llwarns << "Invalid map image type returned! " << agent_flags << llendl; -		return; -	} - -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data); - -	bool found_null_sim = false; - -	BOOL adjust = 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_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, LLViewerTexture::BOOST_NONE, 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, LLViewerTexture::BOOST_NONE, 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 9a249d14f8..60b1e59645 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,308 +330,59 @@ 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); -		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, LLViewerTexture::BOOST_NONE, 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, LLViewerTexture::BOOST_NONE, 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) -		{ -			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) +		// Update the agent count for that region if we're not too zoomed out already +		if (level <= DRAW_SIMINFO_THRESHOLD)  		{ -			// 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); @@ -634,18 +396,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); @@ -656,68 +415,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;  	{ @@ -727,69 +485,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();  	} @@ -799,9 +537,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 @@ -811,31 +549,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 * F_PI);  			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() @@ -846,36 +586,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);  		} -		for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin(); -			 it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) +		// 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)  		{ -			LLSimInfo* info = (*it).second; -			if (info->mCurrentImage.notNull()) +			drawMipmapLevel(width, height, level - 1, false); +		} +	} +	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) +		{ +			// 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); @@ -884,7 +770,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);  } @@ -907,137 +793,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")) +		{ +			drawGenericItems(info->getTeleHub(), sTelehubImage); +		} +		// Land for sale +		if (gSavedSettings.getBOOL("MapShowLandForSale"))  		{ -			// Show agent 'stack' at center of sim -			S32 num_agents = LLWorldMap::getInstance()->mNumAgents[handle]; -			if (num_agents > 0) +			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(); @@ -1078,8 +918,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 @@ -1163,7 +1003,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 ); @@ -1184,23 +1024,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  			} @@ -1209,6 +1046,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) @@ -1224,7 +1063,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())  		{ @@ -1264,6 +1103,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; @@ -1272,13 +1114,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);  	} @@ -1293,7 +1136,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;  @@ -1302,10 +1145,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. @@ -1566,7 +1411,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]); @@ -1575,12 +1420,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());  		}  	} @@ -1589,8 +1434,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;  } @@ -1613,108 +1458,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::getInstance()->cancelTracking(); -	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) +	S32 level = LLWorldMipmap::scaleToLevel(sMapScale); +	// If the zoom level is not too far out already, test hits +	if (level <= DRAW_SIMINFO_THRESHOLD)  	{ -		(*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; -			} -		} -	} - -	if (gSavedSettings.getBOOL("MapShowLandForSale")) -	{ -		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;  } @@ -1775,59 +1628,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 )  { @@ -1916,16 +1746,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 3390463aa6..2daaf77772 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; @@ -3002,15 +3003,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/Blank.png b/indra/newview/skins/default/textures/Blank.png Binary files differnew file mode 100644 index 0000000000..f38e9f9100 --- /dev/null +++ b/indra/newview/skins/default/textures/Blank.png diff --git a/indra/newview/skins/default/textures/default_profile_picture.j2c b/indra/newview/skins/default/textures/default_profile_picture.j2c Binary files differindex c53a22e816..f21742cf09 100644 --- a/indra/newview/skins/default/textures/default_profile_picture.j2c +++ b/indra/newview/skins/default/textures/default_profile_picture.j2c diff --git a/indra/newview/skins/default/textures/map_avatar_32.tga b/indra/newview/skins/default/textures/map_avatar_32.tga Binary files differnew file mode 100644 index 0000000000..aebeab4093 --- /dev/null +++ b/indra/newview/skins/default/textures/map_avatar_32.tga diff --git a/indra/newview/skins/default/textures/map_avatar_above_32.tga b/indra/newview/skins/default/textures/map_avatar_above_32.tga Binary files differnew file mode 100644 index 0000000000..65bd0561a7 --- /dev/null +++ b/indra/newview/skins/default/textures/map_avatar_above_32.tga diff --git a/indra/newview/skins/default/textures/map_avatar_below_32.tga b/indra/newview/skins/default/textures/map_avatar_below_32.tga Binary files differnew file mode 100644 index 0000000000..496c44b369 --- /dev/null +++ b/indra/newview/skins/default/textures/map_avatar_below_32.tga diff --git a/indra/newview/skins/default/textures/map_avatar_you_32.tga b/indra/newview/skins/default/textures/map_avatar_you_32.tga Binary files differnew file mode 100644 index 0000000000..782207efd6 --- /dev/null +++ b/indra/newview/skins/default/textures/map_avatar_you_32.tga diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index cf7ab46dd5..7f33330123 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -27,6 +27,8 @@    <texture name="BackArrow_Off" file_name="icons/BackArrow_Off.png" preload="false" />    <texture name="BackArrow_Press" file_name="icons/BackArrow_Press.png" preload="false" /> +  <texture name="Blank" file_name="Blank.png" preload="false" /> +      <texture name="BottomTray_BG" file_name="bottomtray/BottomTray_BG.png" preload="false" />    <texture name="BuyArrow_Off" file_name="navbar/BuyArrow_Off.png" preload="true" scale.left="1" scale.top="1" scale.right="0" scale.bottom="0"  /> diff --git a/indra/newview/skins/default/xui/en/floater_test_textbox.xml b/indra/newview/skins/default/xui/en/floater_test_textbox.xml index 9e2e9e74e3..8dba05f1ee 100644 --- a/indra/newview/skins/default/xui/en/floater_test_textbox.xml +++ b/indra/newview/skins/default/xui/en/floater_test_textbox.xml @@ -2,11 +2,11 @@  <floater   legacy_header_height="18"   can_resize="true" - height="400" + height="450"   layout="topleft"   name="floater_test_textbox"   help_topic="floater_test_textbox" - width="400"> + width="600">      <text       type="string"       length="1" @@ -48,61 +48,80 @@          First line of multiple lines      Second line of multiple lines      </text> +      <text +       top_pad="10" +       left="10" +       right="-10"  +       follows="top|left" +       font.name="SansSerifSmall" +       name="test_text10" +       tool_tip="text"> +        SansSerifSmall. Русский 中文 (简体) The quick brown fox jumped over the lazy dog. +      </text> +      <text +       top_pad="10" +       left="10" +       right="-10"  +       follows="top|left" +       font.name="SansSerif" +       name="test_text11" +       tool_tip="text"> +        SansSerif.  Русский 中文 (简体) The quick brown fox jumped over the lazy dog. +      </text> +      <text +       top_pad="10" +       left="10" +       right="-10"  +       follows="top|left" +       font.name="SansSerifLarge" +       name="test_text12" +       tool_tip="text"> +        SansSerifLarge.  Русский 中文 (简体) The quick brown fox jumped over the lazy dog. +      </text> +      <text +       top_pad="10" +       left="10" +       right="-10"  +       follows="top|left" +       font.name="SansSerifHuge" +       name="test_text13" +       tool_tip="text"> +        SansSerifHuge.  Русский 中文 (简体) The quick brown fox jumped over the lazy dog. +      </text>      <text       type="string"       length="1"       font="SansSerif" -     height="10" -     layout="topleft" -     left_delta="0" -     top_pad="30" -     width="300"> -        font SansSerif -    </text> -    <text -     type="string" -     length="1" -     follows="bottom|right" -     height="10" -     layout="topleft" -     left_delta="0" -     top_pad="10" -     width="300"> -        follows bottom right -    </text> -    <text -     type="string" -     length="1" -     font="SansSerifSmall"       font.style="BOLD"       height="10"       layout="topleft"       left_delta="0" -     top_pad="10" +     top_pad="40"       width="300"> -        font style BOLD +      SansSerif BOLD      </text>      <text       type="string"       length="1" -     font="SansSerifSmall" +     font="SansSerif"       font.style="BOLD|UNDERLINE"       height="10"       layout="topleft"       left_delta="0"       top_pad="10"       width="300"> -        font style BOLD UNDERLINE +      SansSerif BOLD UNDERLINE      </text>      <text       type="string"       length="1" +     font="SansSerif"       height="10"       layout="topleft"       left_delta="0"       top_pad="10"       width="300"> -        font style UNDERLINE +      SansSerif UNDERLINE      </text>      <text       type="string" diff --git a/indra/newview/skins/default/xui/en/floater_test_widgets.xml b/indra/newview/skins/default/xui/en/floater_test_widgets.xml index 718d724aa6..44dcb07526 100644 --- a/indra/newview/skins/default/xui/en/floater_test_widgets.xml +++ b/indra/newview/skins/default/xui/en/floater_test_widgets.xml @@ -338,13 +338,13 @@ line to actually fit     height="400"     halign="center"     layout="topleft" -   left="575" +   left="525"     name="group_tab_container"     tab_position="top"     tab_height="20"     tool_tip="tab container"     top="80" -   width="250"> +   width="300">      <!-- "panel" is a container for widgets.  It is automatically resized to           fit the parent tab_container. -->      <panel @@ -380,6 +380,46 @@ line to actually fit         tool_tip="Color Swatch: Click to open Color Picker"         top_delta="0"         width="80" /> +      <text +       top_pad="10" +       left="10" +       width="250"  +       follows="top|left" +       font.name="SansSerifSmall" +       name="test_text10" +       tool_tip="text"> +        SansSerifSmall.  Русский 中文 (简体) +      </text> +      <text +       top_pad="10" +       left="10" +       width="250" +       follows="top|left" +       font.name="SansSerif" +       name="test_text11" +       tool_tip="text"> +        SansSerif.  Русский 中文 (简体) +      </text> +      <text +       top_pad="10" +       left="10" +       width="250"  +       follows="top|left" +       font.name="SansSerifLarge" +       name="test_text12" +       tool_tip="text"> +        SansSerifLarge.  Русский 中文 (简体) +      </text> +      <text +       top_pad="10" +       left="10" +       width="250" +       follows="top|left" +       font.name="SansSerifHuge" +       name="test_text13" +       tool_tip="text"> +        SansSerifHuge.  Русский 中文 (简体) +      </text>      </panel>      <!-- panels can also refer to other floaters or panels -->      <panel 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 f5ae611f93..387ffbd5b3 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -15,38 +15,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" @@ -210,7 +187,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/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index 65dfb13f4a..f3da62a896 100644 --- a/indra/newview/skins/default/xui/en/fonts.xml +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -150,11 +150,9 @@  	     comment="Size of large font (points, or 1/72 of an inch)"  	     size="10.0"  	     /> -	     <!-- Changed Medium size to address menu font size not matching spec. -	     May want to revert/update after menu font configuration has been enabled. -->    <font_size name="Medium"  	     comment="Size of medium font (points, or 1/72 of an inch)" -	     size="8.0" +	     size="9.0"  	     />    <font_size name="Small"  	     comment="Size of small font (points, or 1/72 of an inch)" diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index dfa5adb743..5eb0560962 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -180,23 +180,6 @@          </menu_item_call>        <menu_item_separator />        <menu_item_call -         label="Widget Test" -         name="Widget Test" -         shortcut="control|shift|T"> -        <menu_item_call.on_click -         function="ShowFloater" -         parameter="test_widgets" /> -      </menu_item_call> -      <menu_item_call -         label="Inspectors Test" -         name="inspectors_test" -         shortcut="control|shift|I" -         > -        <menu_item_call.on_click -         function="ShowFloater" -         parameter="test_inspectors" /> -      </menu_item_call> -      <menu_item_call           label="Show Side Tray"           name="Show Side Tray">          <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index ebdfb01787..633c258ecc 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1915,6 +1915,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" @@ -2471,19 +2507,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" @@ -2506,8 +2566,8 @@                   parameter="RenderAttachedParticles" />              </menu_item_check>              <menu_item_check -             label="Hover Highlight Objects" -             name="Hover Highlight Objects"> +             label="Hover Glow Objects" +             name="Hover Glow Objects">                  <menu_item_check.on_check                   function="CheckControl"                   parameter="RenderHighlightEnable" /> diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml index 23d55b33e2..a0055383b1 100644 --- a/indra/newview/skins/default/xui/en/panel_profile.xml +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -58,7 +58,7 @@               default_image_name="None"               enabled="false"               follows="top|left" -             height="117" +             height="102"               layout="topleft"               left="0"               name="2nd_life_pic" @@ -102,7 +102,7 @@               default_image_name="None"               enabled="false"               follows="top|left" -             height="117" +             height="102"               layout="topleft"               left="0"               name="real_world_pic" 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"); +		} +	} +} diff --git a/install.xml b/install.xml index 8e5c7e7ae4..a05122418d 100644 --- a/install.xml +++ b/install.xml @@ -132,9 +132,9 @@            <key>windows</key>            <map>              <key>md5sum</key> -            <string>4e2d4de03dce8a991a5727c15a284e8d</string> +            <string>70b51d0cc93c305026e4e2778cde6d19</string>              <key>url</key> -            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.3.0-windows-20090917.tar.bz2</uri> +            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.6.0-windows-20090722.tar.bz2</uri>            </map>          </map>        </map> @@ -326,9 +326,9 @@            <key>darwin</key>            <map>              <key>md5sum</key> -            <string>c457a0a041ac4946265889a503d26c3d</string> +            <string>9c5603e328e9f543e0a599d6b25be973</string>              <key>url</key> -            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20090805.tar.bz2</uri> +            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20080812.tar.bz2</uri>            </map>            <key>linux</key>            <map>  | 
