From 85c970e847c29641f95d3f3bc7e12f59e0dcade4 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 3 Aug 2010 18:26:47 -0600
Subject: [PATCH] fix for EXT-7399: 2.0.2 with http textures loads textures
 slower than 1.23.5 and     EXT-7397: decoding textures get stuck in REQ
 status

---
 indra/newview/lltexturefetch.cpp | 74 +++++++++++++++++++++++++++++---
 indra/newview/lltexturefetch.h   | 12 +++++-
 2 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index ceed90e210..48cb880bc9 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -844,15 +844,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	{
 		if(mCanUseHTTP)
 		{
-			const S32 HTTP_QUEUE_MAX_SIZE = 8;
 			// *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))
+			if (mFetcher->isHTTPThrottled(mDesiredSize) ||
+				mFetcher->getTextureBandwidth() > max_bandwidth)
 			{
 				// Make normal priority and return (i.e. wait until there is room in the queue)
 				setPriority(LLWorkerThread::PRIORITY_NORMAL | mWorkPriority);
@@ -1255,7 +1254,7 @@ bool LLTextureFetchWorker::deleteOK()
 
 	if ((haveWork() &&
 		 // not ok to delete from these states
-		 ((mState >= SEND_HTTP_REQ && mState <= WAIT_HTTP_REQ) ||
+		 ((mState == WAIT_HTTP_REQ) ||
 		  (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
 	{
 		delete_ok = false;
@@ -1516,6 +1515,11 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 {
 	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
 	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
+	
+	for(S32 i = 0 ; i < TOTAL_TEXTURE_TYPES; i++)
+	{
+		mHTTPThrottleFlag[i] = FALSE ;
+	}
 }
 
 LLTextureFetch::~LLTextureFetch()
@@ -1663,6 +1667,65 @@ void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id)
 	mHTTPTextureQueue.erase(id);
 }
 
+void LLTextureFetch::clearHTTPThrottleFlag()
+{
+	static const F32 WAIT_TIME = 0.3f ; //seconds.
+	static LLFrameTimer timer ;
+
+	if(timer.getElapsedTimeF32() < WAIT_TIME) //wait for WAIT_TIME
+	{
+		return ;
+	}
+	timer.reset() ;
+
+	LLMutexLock lock(&mNetworkQueueMutex);
+	for(S32 i = 0 ; i < TOTAL_TEXTURE_TYPES; i++)//reset the http throttle flags.
+	{
+		mHTTPThrottleFlag[i] = FALSE ;
+	}
+}
+
+//check if need to throttle this fetching request.
+//rule: if a request can not be inserted into the http queue due to a full queue,
+//      block all future insertions of requests with larger fetching size requirement.
+//because:
+//      later insertions are usually at lower priorities; and
+//      small textures need chance to be fetched.
+bool LLTextureFetch::isHTTPThrottled(S32 requested_size)
+{
+	static const S32 SMALL_TEXTURE_MAX_SIZE = 64 * 64 * 4 ;
+	static const S32 MEDIUM_TEXTURE_MAX_SIZE = 256 * 256 * 4 ;
+	static const U32 MAX_HTTP_QUEUE_SIZE = 8 ;
+
+	//determine the class of the texture: SMALL, MEDIUM, or LARGE.
+	S32 type = LARGE_TEXTURE ;
+	if(requested_size <= SMALL_TEXTURE_MAX_SIZE)
+	{
+		type = SMALL_TEXTURE ;
+	}
+	else if(requested_size <= MEDIUM_TEXTURE_MAX_SIZE)
+	{
+		type = MEDIUM_TEXTURE ;
+	}
+
+	LLMutexLock lock(&mNetworkQueueMutex);
+
+	if(mHTTPTextureQueue.size() >= MAX_HTTP_QUEUE_SIZE)//if the http queue is full.
+	{
+		if(!mHTTPThrottleFlag[TOTAL_TEXTURE_TYPES - 1])
+		{
+			for(S32 i = type + 1 ; i < TOTAL_TEXTURE_TYPES; i++) //block all requests with fetching size larger than this request.		
+			{
+				mHTTPThrottleFlag[i] = TRUE ;			
+			}
+		}
+		
+		return true ;
+	}
+
+	return mHTTPThrottleFlag[type] ; //true if this request can not be inserted to the http queue.
+}
+
 void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
 {
 	lockQueue() ;
@@ -1829,7 +1892,8 @@ S32 LLTextureFetch::update(U32 max_time_ms)
 			lldebugs << "processed: " << processed << " messages." << llendl;
 		}
 	}
-	
+	clearHTTPThrottleFlag();
+
 	return res;
 }
 
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 634e590fe0..bae2ceff72 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -95,7 +95,8 @@ protected:
 	void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
 	void addToHTTPQueue(const LLUUID& id);
 	void removeFromHTTPQueue(const LLUUID& id);
-	S32 getHTTPQueueSize() { return getNumHTTPRequests(); }
+	bool isHTTPThrottled(S32 requested_size);
+	void clearHTTPThrottleFlag();
 	void removeRequest(LLTextureFetchWorker* worker, bool cancel);
 	// Called from worker thread (during doWork)
 	void processCurlRequests();	
@@ -134,6 +135,15 @@ private:
 	F32 mTextureBandwidth;
 	F32 mMaxBandwidth;
 	LLTextureInfo mTextureInfo;
+
+	enum
+	{
+		SMALL_TEXTURE = 0 , //size <= 64 * 64
+		MEDIUM_TEXTURE,     //size <= 256 * 256
+		LARGE_TEXTURE,      //size > 256 * 256
+		TOTAL_TEXTURE_TYPES
+	};
+	BOOL mHTTPThrottleFlag[TOTAL_TEXTURE_TYPES];
 };
 
 #endif // LL_LLTEXTUREFETCH_H
-- 
GitLab