davep avatar davep committed 6ee6af9

SH-2889 Add visual auto-muting controls

Comments (0)

Files changed (13)

indra/llmath/llvolume.cpp

 	mFaceMask = 0x0;
 	mDetail = detail;
 	mSculptLevel = -2;
+	mSurfaceArea = 1.f; //only calculated for sculpts, defaults to 1 for all other prims
 	mIsMeshAssetLoaded = FALSE;
 	mLODScaleBias.setVec(1,1,1);
 	mHullPoints = NULL;
 		{
 			F32 area = sculptGetSurfaceArea();
 
+			mSurfaceArea = area;
+
 			const F32 SCULPT_MAX_AREA = 384.f;
 
 			if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA)

indra/llmath/llvolume.h

 	S32	getNumFaces() const;
 	S32 getNumVolumeFaces() const							{ return mVolumeFaces.size(); }
 	F32 getDetail() const									{ return mDetail; }
+	F32 getSurfaceArea() const								{ return mSurfaceArea; }
 	const LLVolumeParams& getParams() const					{ return mParams; }
 	LLVolumeParams getCopyOfParams() const					{ return mParams; }
 	const LLProfile& getProfile() const						{ return *mProfilep; }
 	BOOL mUnique;
 	F32 mDetail;
 	S32 mSculptLevel;
+	F32 mSurfaceArea; //unscaled surface area
 	BOOL mIsMeshAssetLoaded;
 	
 	LLVolumeParams mParams;

indra/newview/app_settings/settings.xml

       <key>Value</key>
       <integer>1</integer>
     </map>
+  <key>RenderAutoMuteByteLimit</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum bytes of attachments before an avatar is automatically visually muted (0 for no limit).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>RenderAutoMuteSurfaceAreaLimit</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum surface area of attachments before an avatar is automatically visually muted (0 for no limit).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
     <key>RenderUseShaderLOD</key>
     <map>
       <key>Comment</key>

indra/newview/lldrawable.cpp

 LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
 : LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB)
 {
+	mBridge = this;
 	mDrawable = root;
 	root->setSpatialBridge(this);
 	
 	{
 		group->mSpatialPartition->remove(this, group);
 	}
+
+	//delete octree here so listeners will still be able to access bridge specific state
+	destroyTree();
+}
+
+void LLSpatialBridge::destroyTree()
+{
+	delete mOctree;
+	mOctree = NULL;
 }
 
 void LLSpatialBridge::updateSpatialExtents()

indra/newview/llspatialpartition.cpp

 
 LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	mState(0),
+	mGeometryBytes(0),
+	mSurfaceArea(0.f),
 	mBuilt(0.f),
 	mOctreeNode(node),
 	mSpatialPartition(part),
 		}
 	}
 	
+	//clean up avatar attachment stats
+	LLSpatialBridge* bridge = mSpatialPartition->asBridge();
+	if (bridge)
+	{
+		if (bridge->mAvatar.notNull())
+		{
+			bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes;
+			bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea;
+		}
+	}
+
 	clearDrawMap();
 	mVertexBuffer = NULL;
 	mBufferMap.clear();
 //==============================================
 
 LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
-: mRenderByGroup(render_by_group)
+: mRenderByGroup(render_by_group), mBridge(NULL)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	mOcclusionEnabled = TRUE;

indra/newview/llspatialpartition.h

 	bridge_list_t mBridgeList;
 	buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers
 
+	U32 mGeometryBytes; //used by volumes to track how many bytes of geometry data are in this node
+	F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node
+
 	F32 mBuilt;
 	OctreeNode* mOctreeNode;
 	LLSpatialPartition* mSpatialPartition;
 	BOOL isVisible(const LLVector3& v);
 	bool isHUDPartition() ;
 	
-	virtual LLSpatialBridge* asBridge() { return NULL; }
-	virtual BOOL isBridge() { return asBridge() != NULL; }
+	LLSpatialBridge* asBridge() { return mBridge; }
+	BOOL isBridge() { return asBridge() != NULL; }
 
 	void renderPhysicsShapes();
 	void renderDebug();
 
 public:
 	LLSpatialGroup::OctreeNode* mOctree;
+	LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this
+							// use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe
+							// to call asBridge() from the destructor
 	BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
 	BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
 	U32 mBufferUsage;
 	
 	LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask);
 	
+	void destroyTree();
+
 	virtual BOOL isSpatialBridge() const		{ return TRUE; }
-
 	virtual void updateSpatialExtents();
 	virtual void updateBinRadius();
 	virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE);
 	virtual void shiftPos(const LLVector4a& vec);
 	virtual void cleanupReferences();
 	virtual LLSpatialPartition* asPartition()		{ return this; }
-	virtual LLSpatialBridge* asBridge()				{ return this; }
-	
+		
 	virtual LLCamera transformCamera(LLCamera& camera);
 	
 	LLDrawable* mDrawable;
+	LLPointer<LLVOAvatar> mAvatar;
+
 };
 
 class LLCullResult 

indra/newview/llviewermenu.cpp

 	{
 		return LLPipeline::RENDER_DEBUG_COMPOSITION;
 	}
+	else if ("attachment bytes" == info_display)
+	{
+		return LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES;
+	}
 	else if ("glow" == info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_GLOW;

indra/newview/llvoavatar.cpp

 	LLViewerObject(id, pcode, regionp),
 	mIsDummy(FALSE),
 	mSpecialRenderMode(0),
+	mAttachmentGeometryBytes(0),
+	mAttachmentSurfaceArea(0.f),
 	mTurning(FALSE),
 	mPelvisToFoot(0.f),
 	mLastSkeletonSerialNum( 0 ),
 	mRoot.updateWorldMatrixChildren();
 }
 
+bool LLVOAvatar::isVisuallyMuted()
+{
+	static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit");
+	static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit");
+	
+	return LLMuteList::getInstance()->isMuted(getID()) ||
+			(mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) ||
+			(mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f);
+}
+
 //------------------------------------------------------------------------
 // updateCharacter()
 // called on both your avatar and other avatars
 		size.setSub(ext[1],ext[0]);
 		F32 mag = size.getLength3().getF32()*0.5f;
 
+		
 		F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
-		if (LLMuteList::getInstance()->isMuted(getID()))
+		if (isVisuallyMuted())
 		{ // muted avatars update at 16 hz
 			mUpdatePeriod = 16;
 		}
 
 	static std::set<LLUUID> all_textures;
 
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES))
+	{ //set debug text to attachment geometry bytes here so render cost will override
+		setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea));
+	}
+
 	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
 	{
 		return;

indra/newview/llvoavatar.h

 
 public:
 	U32 		renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
+	bool		isVisuallyMuted();
+
 	U32 		renderRigid();
 	U32 		renderSkinned(EAvatarRenderPass pass);
 	F32			getLastSkinTime() { return mLastSkinTime; }
 	static void	restoreGL();
 	BOOL 		mIsDummy; // for special views
 	S32			mSpecialRenderMode; // special lighting
+	U32			mAttachmentGeometryBytes; //number of bytes in attached geometry
+	F32			mAttachmentSurfaceArea; //estimated surface area of attachments
+
 private:
 	bool		shouldAlphaMask();
 

indra/newview/llvovolume.cpp

 
 	LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
 
+	LLVOAvatar* pAvatarVO = NULL;
+
+	LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+	if (bridge)
+	{
+		if (bridge->mAvatar.isNull())
+		{
+			LLViewerObject* vobj = bridge->mDrawable->getVObj();
+			if (vobj)
+			{
+				bridge->mAvatar = vobj->getAvatar();
+			}
+		}
+
+		pAvatarVO = bridge->mAvatar;
+	}
+
+	if (pAvatarVO)
+	{
+		pAvatarVO->mAttachmentGeometryBytes -= group->mGeometryBytes;
+		pAvatarVO->mAttachmentSurfaceArea -= group->mSurfaceArea;
+	}
+
+	group->mGeometryBytes = 0;
+	group->mSurfaceArea = 0;
+	
 	group->clearDrawMap();
 
 	mFaceList.clear();
 
 		LLVOVolume* vobj = drawablep->getVOVolume();
 
+		if (!vobj)
+		{
+			continue;
+		}
+
 		if (vobj->isMesh() &&
 			(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
 		{
 			continue;
 		}
 
+		LLVolume* volume = vobj->getVolume();
+		if (volume)
+		{
+			const LLVector3& scale = vobj->getScale();
+			group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
+		}
+
 		llassert_always(vobj);
 		vobj->updateTextureVirtualSize(true);
 		vobj->preRebuild();
 				//Determine if we've received skininfo that contains an
 				//alternate bind matrix - if it does then apply the translational component
 				//to the joints of the avatar.
-				LLVOAvatar* pAvatarVO = vobj->getAvatar();
 				bool pelvisGotSet = false;
 
 				if ( pAvatarVO )
 
 					if (type == LLDrawPool::POOL_ALPHA)
 					{
-						if (te->getFullbright())
+						if (te->getColor().mV[3] > 0.f)
 						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
-						}
-						else
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+							if (te->getFullbright())
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+							}
+							else
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+							}
 						}
 					}
 					else if (te->getShiny())
 					}
 					else
 					{
-						drawablep->setState(LLDrawable::HAS_ALPHA);
-						alpha_faces.push_back(facep);
+						if (te->getColor().mV[3] > 0.f)
+						{
+							drawablep->setState(LLDrawable::HAS_ALPHA);
+							alpha_faces.push_back(facep);
+						}
 					}
 				}
 				else
 	}
 
 	mFaceList.clear();
+
+	if (pAvatarVO)
+	{
+		pAvatarVO->mAttachmentGeometryBytes += group->mGeometryBytes;
+		pAvatarVO->mAttachmentSurfaceArea += group->mSurfaceArea;
+	}
 }
 
 static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
 			}
 		}
 
+		group->mGeometryBytes += buffer->getSize() + buffer->getIndicesSize();
+
+
 		buffer_map[mask][*face_iter].push_back(buffer);
 
 		//add face geometry

indra/newview/pipeline.cpp

 
 	assertInitialized();
 
-	BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
+	bool muted = avatar->isVisuallyMuted();		
 
 	pushRenderTypeMask();
 	

indra/newview/pipeline.h

 
 	enum LLRenderDebugMask
 	{
-		RENDER_DEBUG_COMPOSITION		= 0x0000001,
-		RENDER_DEBUG_VERIFY				= 0x0000002,
-		RENDER_DEBUG_BBOXES				= 0x0000004,
-		RENDER_DEBUG_OCTREE				= 0x0000008,
-		RENDER_DEBUG_WIND_VECTORS		= 0x0000010,
-		RENDER_DEBUG_OCCLUSION			= 0x0000020,
-		RENDER_DEBUG_POINTS				= 0x0000040,
-		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x0000080,
-		RENDER_DEBUG_TEXTURE_AREA		= 0x0000100,
-		RENDER_DEBUG_FACE_AREA			= 0x0000200,
-		RENDER_DEBUG_PARTICLES			= 0x0000400,
-		RENDER_DEBUG_GLOW				= 0x0000800,
-		RENDER_DEBUG_TEXTURE_ANIM		= 0x0001000,
-		RENDER_DEBUG_LIGHTS				= 0x0002000,
-		RENDER_DEBUG_BATCH_SIZE			= 0x0004000,
-		RENDER_DEBUG_ALPHA_BINS			= 0x0008000,
-		RENDER_DEBUG_RAYCAST            = 0x0010000,
-		RENDER_DEBUG_SHAME				= 0x0020000,
-		RENDER_DEBUG_SHADOW_FRUSTA		= 0x0040000,
-		RENDER_DEBUG_SCULPTED           = 0x0080000,
-		RENDER_DEBUG_AVATAR_VOLUME      = 0x0100000,
-		RENDER_DEBUG_BUILD_QUEUE		= 0x0200000,
-		RENDER_DEBUG_AGENT_TARGET       = 0x0400000,
-		RENDER_DEBUG_UPDATE_TYPE		= 0x0800000,
-		RENDER_DEBUG_PHYSICS_SHAPES     = 0x1000000,
-		RENDER_DEBUG_NORMALS	        = 0x2000000,
-		RENDER_DEBUG_LOD_INFO	        = 0x4000000,
-		RENDER_DEBUG_RENDER_COMPLEXITY  = 0x8000000
+		RENDER_DEBUG_COMPOSITION		= 0x00000001,
+		RENDER_DEBUG_VERIFY				= 0x00000002,
+		RENDER_DEBUG_BBOXES				= 0x00000004,
+		RENDER_DEBUG_OCTREE				= 0x00000008,
+		RENDER_DEBUG_WIND_VECTORS		= 0x00000010,
+		RENDER_DEBUG_OCCLUSION			= 0x00000020,
+		RENDER_DEBUG_POINTS				= 0x00000040,
+		RENDER_DEBUG_TEXTURE_PRIORITY	= 0x00000080,
+		RENDER_DEBUG_TEXTURE_AREA		= 0x00000100,
+		RENDER_DEBUG_FACE_AREA			= 0x00000200,
+		RENDER_DEBUG_PARTICLES			= 0x00000400,
+		RENDER_DEBUG_GLOW				= 0x00000800,
+		RENDER_DEBUG_TEXTURE_ANIM		= 0x00001000,
+		RENDER_DEBUG_LIGHTS				= 0x00002000,
+		RENDER_DEBUG_BATCH_SIZE			= 0x00004000,
+		RENDER_DEBUG_ALPHA_BINS			= 0x00008000,
+		RENDER_DEBUG_RAYCAST            = 0x00010000,
+		RENDER_DEBUG_SHAME				= 0x00020000,
+		RENDER_DEBUG_SHADOW_FRUSTA		= 0x00040000,
+		RENDER_DEBUG_SCULPTED           = 0x00080000,
+		RENDER_DEBUG_AVATAR_VOLUME      = 0x00100000,
+		RENDER_DEBUG_BUILD_QUEUE		= 0x00200000,
+		RENDER_DEBUG_AGENT_TARGET       = 0x00400000,
+		RENDER_DEBUG_UPDATE_TYPE		= 0x00800000,
+		RENDER_DEBUG_PHYSICS_SHAPES     = 0x01000000,
+		RENDER_DEBUG_NORMALS	        = 0x02000000,
+		RENDER_DEBUG_LOD_INFO	        = 0x04000000,
+		RENDER_DEBUG_RENDER_COMPLEXITY  = 0x08000000,
+		RENDER_DEBUG_ATTACHMENT_BYTES	= 0x10000000,
 	};
 
 public:

indra/newview/skins/default/xui/en/menu_viewer.xml

            function="Advanced.ToggleInfoDisplay"
            parameter="rendercomplexity" />
         </menu_item_check>
+        <menu_item_check
+         label="Attachment Bytes"
+         name="attachment bytes">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="attachment bytes" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="attachment bytes" />
+        </menu_item_check>
 		<menu_item_check
          label="Sculpt"
          name="Sculpt">
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.