From 6b9a2d24cce8efaa72c2fd60655998844394312d Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Wed, 30 Mar 2011 18:38:22 -0500
Subject: SH-477 Better mesh streaming cost estimation.

---
 indra/newview/app_settings/settings.xml |   2 +-
 indra/newview/llfloatermodelpreview.cpp |  34 ++++++----
 indra/newview/llmeshrepository.cpp      | 109 +++++++++++++++++++-------------
 indra/newview/llmeshrepository.h        |   7 +-
 indra/newview/llselectmgr.cpp           |  18 +++++-
 indra/newview/llselectmgr.h             |   4 +-
 indra/newview/llviewerobject.cpp        |   2 +-
 indra/newview/llviewerobject.h          |   2 +-
 indra/newview/llviewerwindow.cpp        |  21 ++++--
 indra/newview/llvovolume.cpp            |   6 +-
 indra/newview/llvovolume.h              |   2 +-
 11 files changed, 132 insertions(+), 75 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c11de57c42..4c042435f2 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8974,7 +8974,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>2.0</real>
+    <real>3.0</real>
   </map>
   <key>MeshThreadCount</key>
   <map>
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 541511e448..243f301e9d 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -1093,7 +1093,7 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev
 	{
 		//only try to load from slm if viewer is configured to do so and this is the 
 		//initial model load (not an LoD or physics shape)
-		mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mBaseModel.empty();
+		mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
 		mPreview->setLoadState(STARTING);
 	}
 	else
@@ -1889,6 +1889,14 @@ void LLModelLoader::loadModelCallback()
 	{ //wait until this thread is stopped before deleting self
 		apr_sleep(100);
 	}
+
+	//cleanup model loader
+	if (mPreview)
+	{
+		mPreview->mModelLoader = NULL;
+	}
+
+	delete this;
 }
 
 void LLModelLoader::handlePivotPoint( daeElement* pRoot )
@@ -2518,13 +2526,13 @@ U32 LLModelPreview::calcResourceCost()
 		{
 			accounted.insert(instance.mModel);
 
-			LLModel::convex_hull_decomposition& decomp =
+			LLModel::Decomposition& decomp =
 			instance.mLOD[LLModel::LOD_PHYSICS] ?
-			instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull :
-			instance.mModel->mPhysics.mHull;
+			instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
+			instance.mModel->mPhysics;
 
-			LLSD ret = LLModel::writeModel(
-										   "",
+			std::stringstream ostr;
+			LLSD ret = LLModel::writeModel(ostr,
 										   instance.mLOD[4],
 										   instance.mLOD[3],
 										   instance.mLOD[2],
@@ -2536,10 +2544,10 @@ U32 LLModelPreview::calcResourceCost()
 										   TRUE);
 			cost += gMeshRepo.calcResourceCost(ret);
 
-			num_hulls += decomp.size();
-			for (U32 i = 0; i < decomp.size(); ++i)
+			num_hulls += decomp.mHull.size();
+			for (U32 i = 0; i < decomp.mHull.size(); ++i)
 			{
-				num_points += decomp[i].size();
+				num_points += decomp.mHull[i].size();
 			}
 
 			//calculate streaming cost
@@ -2737,10 +2745,10 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
 
 			std::stringstream str;
 
-			LLModel::convex_hull_decomposition& decomp =
+			LLModel::Decomposition& decomp =
 				instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? 
-				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
-				instance.mModel->mPhysics.mHull;
+				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : 
+				instance.mModel->mPhysics;
 
 			LLModel::writeModel(str, 
 				instance.mLOD[LLModel::LOD_PHYSICS], 
@@ -2749,7 +2757,7 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
 				instance.mLOD[LLModel::LOD_LOW], 
 				instance.mLOD[LLModel::LOD_IMPOSTOR], 
 				decomp, 
-				empty_hull, save_skinweights, save_joint_positions);
+				save_skinweights, save_joint_positions);
 
 			
 			data["mesh"][instance.mModel->mLocalID] = str.str();
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 752e4c8744..78943ef1b6 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1535,8 +1535,6 @@ void LLMeshRepoThread::notifyLoadedMeshes()
 
 S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod) 
 { //only ever called from main thread
-	lod = llclamp(lod, 0, 3);
-
 	LLMutexLock lock(mHeaderMutex);
 	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
 
@@ -1544,40 +1542,48 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo
 	{
 		LLSD& header = iter->second;
 
-		if (header.has("404"))
-		{
-			return -1;
-		}
+		return LLMeshRepository::getActualMeshLOD(header, lod);
+	}
 
-		if (header[header_lod[lod]]["size"].asInteger() > 0)
-		{
-			return lod;
-		}
+	return lod;
+}
+
+//static
+S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
+{
+	lod = llclamp(lod, 0, 3);
+
+	if (header.has("404"))
+	{
+		return -1;
+	}
 
-		//search down to find the next available lower lod
-		for (S32 i = lod-1; i >= 0; --i)
+	if (header[header_lod[lod]]["size"].asInteger() > 0)
+	{
+		return lod;
+	}
+
+	//search down to find the next available lower lod
+	for (S32 i = lod-1; i >= 0; --i)
+	{
+		if (header[header_lod[i]]["size"].asInteger() > 0)
 		{
-			if (header[header_lod[i]]["size"].asInteger() > 0)
-			{
-				return i;
-			}
+			return i;
 		}
+	}
 
-		//search up to find then ext available higher lod
-		for (S32 i = lod+1; i < 4; ++i)
+	//search up to find then ext available higher lod
+	for (S32 i = lod+1; i < 4; ++i)
+	{
+		if (header[header_lod[i]]["size"].asInteger() > 0)
 		{
-			if (header[header_lod[i]]["size"].asInteger() > 0)
-			{
-				return i;
-			}
+			return i;
 		}
-
-		//header exists and no good lod found, treat as 404
-		header["404"] = 1;
-		return -1;
 	}
 
-	return lod;
+	//header exists and no good lod found, treat as 404
+	header["404"] = 1;
+	return -1;
 }
 
 U32 LLMeshRepoThread::getResourceCost(const LLUUID& mesh_id)
@@ -2514,12 +2520,12 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
 	return mesh.has("physics_shape") && mesh["physics_shape"].has("size") && (mesh["physics_shape"]["size"].asInteger() > 0);
 }
 
-const LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id)
+LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id)
 {
 	return mThread->getMeshHeader(mesh_id);
 }
 
-const LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
+LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
 {
 	static LLSD dummy_ret;
 	if (mesh_id.notNull())
@@ -2577,12 +2583,10 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
 	//write model file to memory buffer
 	std::stringstream ostr;
 
-	LLModel::convex_hull_decomposition& decomp =
+	LLModel::Decomposition& decomp =
 		data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-		data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
-		data.mBaseModel->mPhysics.mHull;
-
-	LLModel::hull dummy_hull;
+		data.mModel[LLModel::LOD_PHYSICS]->mPhysics : 
+		data.mBaseModel->mPhysics;
 
 	LLSD header = LLModel::writeModel(
 		ostr,
@@ -2592,7 +2596,6 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
 		data.mModel[LLModel::LOD_LOW],
 		data.mModel[LLModel::LOD_IMPOSTOR], 
 		decomp,
-		dummy_hull,
 		mUploadSkin,
 		mUploadJoints,
 		true);
@@ -2678,10 +2681,12 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
 	{
 		std::stringstream ostr;
 
-		LLModel::convex_hull_decomposition& decomp =
+		LLModel::Decomposition& decomp =
 			data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-			data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
-			data.mBaseModel->mPhysics.mHull;
+			data.mModel[LLModel::LOD_PHYSICS]->mPhysics : 
+			data.mBaseModel->mPhysics;
+
+		decomp.mBaseHull = mHullMap[data.mBaseModel];
 
 		LLModel::writeModel(
 			ostr,  
@@ -2691,7 +2696,6 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
 			data.mModel[LLModel::LOD_LOW],
 			data.mModel[LLModel::LOD_IMPOSTOR], 
 			decomp,
-			mHullMap[data.mBaseModel],
 			mUploadSkin,
 			mUploadJoints);
 
@@ -2939,17 +2943,36 @@ void LLMeshRepository::uploadError(LLSD& args)
 }
 
 //static
-F32 LLMeshRepository::getStreamingCost(const LLSD& header, F32 radius)
+F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod)
 {
-	F32 dlowest = llmin(radius/0.06f, 256.f);
-	F32 dlow = llmin(radius/0.24f, 256.f);
-	F32 dmid = llmin(radius/1.0f, 256.f);
+	F32 dlowest = llmin(radius/0.03f, 256.f);
+	F32 dlow = llmin(radius/0.06f, 256.f);
+	F32 dmid = llmin(radius/0.24f, 256.f);
 	
 	F32 bytes_lowest = header["lowest_lod"]["size"].asReal()/1024.f;
 	F32 bytes_low = header["low_lod"]["size"].asReal()/1024.f;
 	F32 bytes_mid = header["medium_lod"]["size"].asReal()/1024.f;
 	F32 bytes_high = header["high_lod"]["size"].asReal()/1024.f;
 
+	if (bytes)
+	{
+		*bytes = 0;
+		*bytes += header["lowest_lod"]["size"].asInteger();
+		*bytes += header["low_lod"]["size"].asInteger();
+		*bytes += header["medium_lod"]["size"].asInteger();
+		*bytes += header["high_lod"]["size"].asInteger();
+	}
+
+
+	if (bytes_visible)
+	{
+		lod = LLMeshRepository::getActualMeshLOD(header, lod);
+		if (lod >= 0 && lod <= 3)
+		{
+			*bytes_visible = header[header_lod[lod]]["size"].asInteger();
+		}
+	}
+
 	if (bytes_high == 0.f)
 	{
 		return 0.f;
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 31c2049c32..5983a282a2 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -318,7 +318,7 @@ public:
 	bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
 	bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
 	bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
-	const LLSD& getMeshHeader(const LLUUID& mesh_id);
+	LLSD& getMeshHeader(const LLUUID& mesh_id);
 
 	void notifyLoadedMeshes();
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
@@ -434,7 +434,7 @@ public:
 	static U32 sCacheBytesWritten;
 	static U32 sPeakKbps;
 	
-	static F32 getStreamingCost(const LLSD& header, F32 radius);
+	static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1);
 
 	LLMeshRepository();
 
@@ -452,6 +452,7 @@ public:
 	void notifyDecompositionReceived(LLModel::Decomposition* info);
 
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
+	static S32 getActualMeshLOD(LLSD& header, S32 lod);
 	U32 calcResourceCost(LLSD& header);
 	U32 getResourceCost(const LLUUID& mesh_params);
 	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id);
@@ -462,7 +463,7 @@ public:
 	void buildHull(const LLVolumeParams& params, S32 detail);
 	void buildPhysicsMesh(LLModel::Decomposition& decomp);
 
-	const LLSD& getMeshHeader(const LLUUID& mesh_id);
+	LLSD& getMeshHeader(const LLUUID& mesh_id);
 
 	void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
 			bool upload_skin, bool upload_joints);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index b139ba361e..78ffc7908d 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -6374,7 +6374,7 @@ BOOL LLObjectSelection::isEmpty() const
 //-----------------------------------------------------------------------------
 // getObjectCount() - returns number of non null objects
 //-----------------------------------------------------------------------------
-S32 LLObjectSelection::getObjectCount(BOOL mesh_adjust)
+S32 LLObjectSelection::getObjectCount()
 {
 	cleanupNodes();
 	S32 count = mList.size();
@@ -6478,7 +6478,7 @@ F32 LLObjectSelection::getSelectedLinksetPhysicsCost()
 	return cost;
 }
 
-F32 LLObjectSelection::getSelectedObjectStreamingCost()
+F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* visible_bytes)
 {
 	F32 cost = 0.f;
 	for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
@@ -6488,7 +6488,19 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost()
 		
 		if (object)
 		{
-			cost += object->getStreamingCost();
+			S32 bytes = 0;
+			S32 visible = 0;
+			cost += object->getStreamingCost(&bytes, &visible);
+
+			if (total_bytes)
+			{
+				*total_bytes += bytes;
+			}
+
+			if (visible_bytes)
+			{
+				*visible_bytes += visible;
+			}
 		}
 	}
 
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 031898d7c5..166616e13e 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -278,14 +278,14 @@ public:
 	LLSelectNode* findNode(LLViewerObject* objectp);
 
 	// count members
-	S32 getObjectCount(BOOL mesh_adjust = FALSE);
+	S32 getObjectCount();
 	F32 getSelectedObjectCost();
 	F32 getSelectedLinksetCost();
 	F32 getSelectedPhysicsCost();
 	F32 getSelectedLinksetPhysicsCost();
 	S32 getSelectedObjectRenderCost();
 	
-	F32 getSelectedObjectStreamingCost();
+	F32 getSelectedObjectStreamingCost(S32* total_bytes = NULL, S32* visible_bytes = NULL);
 	U32 getSelectedObjectTriangleCount();
 
 	S32 getTECount();
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index bcdc774c5e..70b1809033 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3134,7 +3134,7 @@ F32 LLViewerObject::getLinksetPhysicsCost()
 	return mLinksetPhysicsCost;
 }
 
-F32 LLViewerObject::getStreamingCost()
+F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes)
 {
 	return 0.f;
 }
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 2b2b7bd59d..44f46b8c0f 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -326,7 +326,7 @@ public:
 	
 	virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE);
 
-	virtual F32 getStreamingCost();
+	virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
 	virtual U32 getTriangleCount();
 
 	void setObjectCost(F32 cost);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 39ef56d156..141ade8079 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -493,6 +493,10 @@ public:
 			{
 				F32 cost = 0.f;
 				S32 count = 0;
+				S32 object_count = 0;
+				S32 total_bytes = 0;
+				S32 visible_bytes = 0;
+
 				const char* label = "Region";
 				if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 0)
 				{ //region
@@ -506,8 +510,13 @@ public:
 								object->getRegion() == region &&
 								object->getVolume())
 							{
-								cost += object->getStreamingCost();
+								object_count++;
+								S32 bytes = 0;	
+								S32 visible = 0;
+								cost += object->getStreamingCost(&bytes, &visible);
 								count += object->getTriangleCount();
+								total_bytes += bytes;
+								visible_bytes += visible;
 							}
 						}
 					}
@@ -515,12 +524,16 @@ public:
 				else
 				{
 					label = "Selection";
-					cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost();
+					cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectStreamingCost(&total_bytes, &visible_bytes);
 					count = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectTriangleCount();
+					object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
 				}
 					
-				addText(xpos,ypos, llformat("%s streaming cost: %.1f (%.1f KTris)",
-							label, cost, count/1000.f));
+				addText(xpos,ypos, llformat("%s streaming cost: %.1f", label, cost));
+				ypos += y_inc;
+
+				addText(xpos, ypos, llformat("    %.1f KTris, %.1f/%.1f KB, %d objects",
+										count/1024.f, visible_bytes/1024.f, total_bytes/1024.f, object_count));
 				ypos += y_inc;
 			
 			}
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 98e5e4c6de..7c4a4c13ba 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3082,15 +3082,15 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
 
 }
 
-F32 LLVOVolume::getStreamingCost()
+F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
 {
 	if (isMesh())
 	{	
-		const LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
+		LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
 
 		F32 radius = getScale().length();
 		
-		return LLMeshRepository::getStreamingCost(header, radius);
+		return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD);
 	}
 		
 	return 0.f;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index b09243055c..029811886d 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -130,7 +130,7 @@ public:
 	const LLMatrix3&	getRelativeXformInvTrans() const		{ return mRelativeXformInvTrans; }
 	/*virtual*/	const LLMatrix4	getRenderMatrix() const;
 				U32 	getRenderCost(std::set<LLUUID> &textures) const;
-	/*virtual*/	F32		getStreamingCost();
+	/*virtual*/	F32		getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
 	/*virtual*/ U32		getTriangleCount();
 	/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
 										  S32 face = -1,                        // which face to check, -1 = ALL_SIDES
-- 
cgit v1.2.3