diff options
Diffstat (limited to 'indra/newview')
47 files changed, 3897 insertions, 1152 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ebc8e4572a..16d82d5a0a 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -462,6 +462,7 @@ set(viewer_SOURCE_FILES      llremoteparcelrequest.cpp      llsavedsettingsglue.cpp      llsaveoutfitcombobtn.cpp +	llscenemonitor.cpp      llsceneview.cpp      llscreenchannel.cpp      llscriptfloater.cpp @@ -586,6 +587,7 @@ set(viewer_SOURCE_FILES      llviewernetwork.cpp      llviewerobject.cpp      llviewerobjectlist.cpp +	llvieweroctree.cpp      llviewerparcelmedia.cpp      llviewerparcelmediaautoplay.cpp      llviewerparcelmgr.cpp @@ -1028,6 +1030,7 @@ set(viewer_HEADER_FILES      llrootview.h      llsavedsettingsglue.h      llsaveoutfitcombobtn.h +	llscenemonitor.h      llsceneview.h      llscreenchannel.h      llscriptfloater.h @@ -1152,6 +1155,7 @@ set(viewer_HEADER_FILES      llviewernetwork.h      llviewerobject.h      llviewerobjectlist.h +	llvieweroctree.h      llviewerparcelmedia.h      llviewerparcelmediaautoplay.h      llviewerparcelmgr.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 557a698d6d..5c0e8d858e 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6389,6 +6389,17 @@        <key>Value</key>        <integer>1</integer>      </map> +    <key>ObjectCacheViewCullingEnabled</key> +    <map> +      <key>Comment</key> +      <string>Enable the object cache view culling. Needs to restart viewer.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map>      <key>OpenDebugStatAdvanced</key>      <map>        <key>Comment</key> @@ -9447,6 +9458,17 @@        <key>Value</key>        <integer>0</integer>      </map> +    <key>SceneLoadingMonitorEnabled</key> +    <map> +      <key>Comment</key> +      <string>Enabled scene loading monitor if set</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map>      <key>ScriptHelpFollowsCursor</key>      <map>        <key>Comment</key> @@ -10853,7 +10875,7 @@        <key>Type</key>        <string>F32</string>        <key>Value</key> -      <integer>0.0</integer> +      <real>0.0</real>      </map>      <key>TextureFetchUpdateSkipLowPriority</key>      <map> @@ -12492,6 +12514,7 @@        <key>Type</key>        <string>LLSD</string>        <key>Value</key> +      <array />      </map>      <key>VFSOldSize</key>      <map> diff --git a/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl new file mode 100644 index 0000000000..f1400c9b44 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl @@ -0,0 +1,49 @@ +/**  + * @file onetexturefilterF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D tex0; +uniform float tolerance; + +VARYING vec2 vary_texcoord0; + +void main()  +{ +	frag_color = texture2D(tex0, vary_texcoord0.xy); +	 +	if(frag_color[0] + frag_color[1] + frag_color[2] < tolerance) +	{ +		discard; +	} +	else +	{		 +		frag_color[3] = 0.95f;	 +	}	 +} diff --git a/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl new file mode 100644 index 0000000000..a33ef7e92c --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl @@ -0,0 +1,38 @@ +/**  + * @file onetexturefilterV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +  +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_texcoord0; + +void main() +{ +	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +	vary_texcoord0 = texcoord0; +} + diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl new file mode 100644 index 0000000000..050114b37e --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl @@ -0,0 +1,41 @@ +/**  + * @file twotexturecompareF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D tex0; +uniform sampler2D tex1; + +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; + +void main()  +{ +	frag_color = abs(texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy)); +} diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl new file mode 100644 index 0000000000..67c6674f0c --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl @@ -0,0 +1,41 @@ +/**  + * @file twotexturecompareV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ +  +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; +ATTRIBUTE vec2 texcoord1; + +VARYING vec2 vary_texcoord0; +VARYING vec2 vary_texcoord1; + +void main() +{ +	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +	vary_texcoord0 = texcoord0; +	vary_texcoord1 = texcoord1; +} + diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 86a241fa58..3d7770c765 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3749,7 +3749,7 @@ U32 LLAppViewer::getObjectCacheVersion()  {  	// Viewer object cache version, change if object update  	// format changes. JC -	const U32 INDRA_OBJECT_CACHE_VERSION = 14; +	const U32 INDRA_OBJECT_CACHE_VERSION = 15;  	return INDRA_OBJECT_CACHE_VERSION;  } @@ -4333,11 +4333,6 @@ void LLAppViewer::idle()  				llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;  				gObjectList.mNumDeadObjectUpdates = 0;  			} -			if (gObjectList.mNumUnknownKills) -			{ -				llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl; -				gObjectList.mNumUnknownKills = 0; -			}  			if (gObjectList.mNumUnknownUpdates)  			{  				llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl; diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index aeecf054b8..86f0213282 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -40,7 +40,7 @@  #include "llsceneview.h"  #include "llviewertexture.h"  #include "llfloaterreg.h" - +#include "llscenemonitor.h"  //  // Globals  // @@ -66,6 +66,7 @@ LLDebugView::~LLDebugView()  	gDebugView = NULL;  	gTextureView = NULL;  	gSceneView = NULL; +	gSceneMonitorView = NULL;  }  void LLDebugView::init() @@ -98,6 +99,13 @@ void LLDebugView::init()  	gSceneView->setVisible(FALSE);  	addChild(gSceneView);  	gSceneView->setRect(rect); + +	gSceneMonitorView = new LLSceneMonitorView(r); +	gSceneMonitorView->setFollowsTop(); +	gSceneMonitorView->setFollowsLeft(); +	gSceneMonitorView->setVisible(FALSE); +	addChild(gSceneMonitorView); +	gSceneMonitorView->setRect(rect);  	r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f),   									 (S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f)); diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 6ef437cefb..ba970671af 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -49,6 +49,7 @@  #include "llspatialpartition.h"  #include "llviewerobjectlist.h"  #include "llviewerwindow.h" +#include "llvocache.h"  const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;  const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; @@ -76,7 +77,6 @@ LLTrace::MemStat	LLDrawable::sMemStat("LLDrawable");  //  // static -U32 LLDrawable::sCurVisible = 0;  U32 LLDrawable::sNumZombieDrawables = 0;  F32 LLDrawable::sCurPixelAngle = 0;  LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList; @@ -86,33 +86,59 @@ LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;  // static  void LLDrawable::incrementVisible()   { -	sCurVisible++; +	LLViewerOctreeEntryData::incrementVisible();  	sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView();  } -void LLDrawable::init() +LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry) +	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE), +	  mVObjp(vobj) +{ +	init(new_entry);  +} + +void LLDrawable::init(bool new_entry)  {  	// mXform  	mParent = NULL;  	mRenderType = 0;  	mCurrentScale = LLVector3(1,1,1); -	mDistanceWRTCamera = 0.0f; -	mPositionGroup.clear(); -	mExtents[0].clear(); -	mExtents[1].clear(); - +	mDistanceWRTCamera = 0.0f;	  	mState     = 0; -	mVObjp   = NULL; -	// mFaces -	mSpatialGroupp = NULL; -	mVisible = sCurVisible - 2;//invisible for the current frame and the last frame. -	mRadius = 0.f; -	mGeneration = -1; -	mBinRadius = 1.f; -	mBinIndex = -1; - +	// mFaces	 +	mRadius = 0.f;	 +	mGeneration = -1;	  	mSpatialBridge = NULL; + +	LLViewerOctreeEntry* entry = NULL; +	LLVOCacheEntry* vo_entry = NULL; +	if(!new_entry && mVObjp && getRegion() != NULL) +	{ +		vo_entry = getRegion()->getCacheEntryForOctree(mVObjp->getLocalID()); +		if(vo_entry) +		{ +			entry = vo_entry->getEntry();			 +		} +	} +	setOctreeEntry(entry); +	if(vo_entry) +	{ +		if(!entry) +		{ +			vo_entry->setOctreeEntry(mEntry); +		} +		else if(vo_entry->getNumOfChildren() > 0) +		{ +			getRegion()->addVisibleCacheEntry(vo_entry); //to load all children. +		} + +		getRegion()->addActiveCacheEntry(vo_entry);		 +	} + +	llassert(!vo_entry || vo_entry->getEntry() == mEntry); + +	initVisible(sCurVisible - 2);//invisible for the current frame and the last frame.  }  // static @@ -156,6 +182,7 @@ void LLDrawable::markDead()  		llwarns << "Warning!  Marking dead multiple times!" << llendl;  		return;  	} +	setState(DEAD);  	if (mSpatialBridge)  	{ @@ -165,8 +192,7 @@ void LLDrawable::markDead()  	sNumZombieDrawables++; -	// We're dead.  Free up all of our references to other objects -	setState(DEAD); +	// We're dead.  Free up all of our references to other objects	  	cleanupReferences();  //	sDeadList.put(this);  } @@ -220,6 +246,8 @@ void LLDrawable::cleanupReferences()  	gPipeline.unlinkDrawable(this); +	removeFromOctree(); +  	{  		LLFastTimer t(FTM_DEREF_DRAWABLE);  		// Cleanup references to other objects @@ -228,6 +256,21 @@ void LLDrawable::cleanupReferences()  	}  } +void LLDrawable::removeFromOctree() +{ +	if(!mEntry) +	{ +		return; +	} + +	mEntry->removeData(this); +	if(mEntry->hasVOCacheEntry()) +	{ +		getRegion()->removeActiveCacheEntry((LLVOCacheEntry*)mEntry->getVOCacheEntry(), this); +	} +	mEntry = NULL; +} +  void LLDrawable::cleanupDeadDrawables()  {  	/* @@ -428,7 +471,13 @@ void LLDrawable::makeActive()  		}  		updatePartition();  	} - +	else if (!isRoot() && !mParent->isActive()) //this should not happen, but occasionally it does... +	{ +		mParent->makeActive(); +		//NOTE: linked set will now NEVER become static +		mParent->setState(LLDrawable::ACTIVE_CHILD); +	} +	  	llassert(isAvatar() || isRoot() || mParent->isActive());  } @@ -717,7 +766,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)  		LLVOVolume* volume = getVOVolume();  		if (volume)  		{ -			if (getSpatialGroup()) +			if (getGroup())  			{  				pos.set(getPositionGroup().getF32ptr());  			} @@ -835,9 +884,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)  			}  		} -		mExtents[0].add(shift_vector); -		mExtents[1].add(shift_vector); -		mPositionGroup.add(shift_vector); +		shift(shift_vector);  	}  	else if (mSpatialBridge)  	{ @@ -845,9 +892,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)  	}  	else if (isAvatar())  	{ -		mExtents[0].add(shift_vector); -		mExtents[1].add(shift_vector); -		mPositionGroup.add(shift_vector); +		shift(shift_vector);  	}  	mVObjp->onShift(shift_vector); @@ -859,40 +904,24 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const  	return mXform.getPositionW();  } -const LLVector4a* LLDrawable::getSpatialExtents() const -{ -	return mExtents; -} - -void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max) -{  -	mExtents[0].load3(min.mV);  -	mExtents[1].load3(max.mV); -} - -void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max) -{  -	mExtents[0] = min;  -	mExtents[1] = max; -} - -void LLDrawable::setPositionGroup(const LLVector4a& pos) -{ -	mPositionGroup = pos; -} -  void LLDrawable::updateSpatialExtents()  {  	if (mVObjp)  	{ -		mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]); +		const LLVector4a* exts = getSpatialExtents(); +		LLVector4a extents[2]; +		extents[0] = exts[0]; +		extents[1] = exts[1]; + +		mVObjp->updateSpatialExtents(extents[0], extents[1]); +		setSpatialExtents(extents[0], extents[1]);  	}  	updateBinRadius();  	if (mSpatialBridge.notNull())  	{ -		mPositionGroup.splat(0.f); +		getGroupPosition().splat(0.f);  	}  } @@ -901,11 +930,11 @@ void LLDrawable::updateBinRadius()  {  	if (mVObjp.notNull())  	{ -		mBinRadius = llmin(mVObjp->getBinRadius(), 256.f); +		setBinRadius(llmin(mVObjp->getBinRadius(), 256.f));  	}  	else  	{ -		mBinRadius = llmin(getRadius()*4.f, 256.f); +		setBinRadius(llmin(getRadius()*4.f, 256.f));  	}  } @@ -939,26 +968,56 @@ void LLDrawable::updateUVMinMax()  {  } -LLSpatialGroup* LLDrawable::getSpatialGroup() const -{  -	llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1); -	return mSpatialGroupp;  +//virtual +bool LLDrawable::isVisible() const +{ +	if (LLViewerOctreeEntryData::isVisible()) +	{ +		return true; +	} +	 +	{ +		LLviewerOctreeGroup* group = mEntry->getGroup(); +		if (group && group->isVisible()) +		{ +			LLViewerOctreeEntryData::setVisible(); +			return true; +		} +	} + +	return false;  } -void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) +//virtual +bool LLDrawable::isRecentlyVisible() const  { -	//precondition: mSpatialGroupp MUST be null or DEAD or mSpatialGroupp MUST NOT contain this -	llassert(!mSpatialGroupp || mSpatialGroupp->isDead() || !mSpatialGroupp->hasElement(this)); - -	//precondition: groupp MUST be null or groupp MUST contain this -	llassert(!groupp || groupp->hasElement(this)); +	//currently visible or visible in the previous frame. +	bool vis = LLViewerOctreeEntryData::isRecentlyVisible(); -/*if (mSpatialGroupp && (groupp != mSpatialGroupp)) +	if(!vis)  	{ -		mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY); -	}*/ +		LLviewerOctreeGroup* group = getGroup(); +		if (group && group->isRecentlyVisible()) +		{ +			LLViewerOctreeEntryData::setVisible(); +			vis = TRUE ; +		} +	} + +	return vis ; +} + +void LLDrawable::setGroup(LLviewerOctreeGroup *groupp) +{ +	LLSpatialGroup* cur_groupp = (LLSpatialGroup*)getGroup(); +     +	//precondition: mGroupp MUST be null or DEAD or mGroupp MUST NOT contain this +	//llassert(!cur_groupp || cur_groupp->isDead() || !cur_groupp->hasElement(this)); + +	//precondition: groupp MUST be null or groupp MUST contain this +	llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this)); -	if (mSpatialGroupp != groupp && getVOVolume()) +	if (cur_groupp != groupp && getVOVolume())  	{ //NULL out vertex buffer references for volumes on spatial group change to maintain  		//requirement that every face vertex buffer is either NULL or points to a vertex buffer  		//contained by its drawable's spatial group @@ -974,10 +1033,10 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)  	//postcondition: if next group is NULL, previous group must be dead OR NULL OR binIndex must be -1  	//postcondition: if next group is NOT NULL, binIndex must not be -1 -	llassert(groupp == NULL ? (mSpatialGroupp == NULL || mSpatialGroupp->isDead()) || getBinIndex() == -1 : -							getBinIndex() != -1); +	//llassert(groupp == NULL ? (cur_groupp == NULL || cur_groupp->isDead()) || (!getEntry() || getEntry()->getBinIndex() == -1) : +	//						(getEntry() && getEntry()->getBinIndex() != -1)); -	mSpatialGroupp = groupp; +	LLViewerOctreeEntryData::setGroup(groupp);  }  LLSpatialPartition* LLDrawable::getSpatialPartition() @@ -996,11 +1055,11 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()  		{  			if (mVObjp->isHUDAttachment())  			{ -				setSpatialBridge(new LLHUDBridge(this)); +				setSpatialBridge(new LLHUDBridge(this, getRegion()));  			}  			else  			{ -				setSpatialBridge(new LLVolumeBridge(this)); +				setSpatialBridge(new LLVolumeBridge(this, getRegion()));  			}  		}  		return mSpatialBridge->asPartition(); @@ -1019,89 +1078,26 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()  	return retval;  } -const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. -//static  -S32 LLDrawable::getMinVisFrameRange() +//virtual +S32 LLDrawable::getMinVisFrameRange() const  { -	return MIN_VIS_FRAME_RANGE ; -} - -BOOL LLDrawable::isRecentlyVisible() const -{ -	//currently visible or visible in the previous frame. -	BOOL vis = isVisible() || (sCurVisible - mVisible < MIN_VIS_FRAME_RANGE)  ; - -	if(!vis) -	{ -		LLSpatialGroup* group = getSpatialGroup(); -		if (group && group->isRecentlyVisible()) -		{ -			mVisible = sCurVisible; -			vis = TRUE ; -		} -	} - -	return vis ; -} - -BOOL LLDrawable::isVisible() const -{ -	if (mVisible == sCurVisible) -	{ -		return TRUE; -	} -	 -#if 0 -	//disabling this code fixes DEV-20105.  Leaving in place in case some other bug pops up as a a result. -	//should be safe to just always ask the spatial group for visibility. -	if (isActive()) -	{ -		if (isRoot()) -		{ -			LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() : -									getSpatialGroup(); -			if (group && group->isVisible()) -			{ -				mVisible = sCurVisible; -				return TRUE; -			} -		} -		else -		{ -			if (getParent()->isVisible()) -			{ -				mVisible = sCurVisible; -				return TRUE; -			} -		} -	} -	else -#endif -	{ -		LLSpatialGroup* group = getSpatialGroup(); -		if (group && group->isVisible()) -		{ -			mVisible = sCurVisible; -			return TRUE; -		} -	} +	const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. -	return FALSE; +	return MIN_VIS_FRAME_RANGE ;  }  //=======================================  // Spatial Partition Bridging Drawable  //======================================= -LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask) -: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB) +LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask, LLViewerRegion* regionp) :  +	LLDrawable(root->getVObj(), true), +	LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB, regionp)  {  	mBridge = this;  	mDrawable = root;  	root->setSpatialBridge(this); -	mBinIndex = -1; -  	mRenderType = mDrawable->mRenderType;  	mDrawableType = mDrawable->mRenderType; @@ -1122,10 +1118,13 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat  LLSpatialBridge::~LLSpatialBridge()  {	 -	LLSpatialGroup* group = getSpatialGroup(); -	if (group) +	if(mEntry)  	{ -		group->mSpatialPartition->remove(this, group); +		LLSpatialGroup* group = getSpatialGroup(); +		if (group) +		{ +			group->mSpatialPartition->remove(this, group); +		}  	}  	//delete octree here so listeners will still be able to access bridge specific state @@ -1147,8 +1146,9 @@ void LLSpatialBridge::updateSpatialExtents()  		root->rebound();  	} +	const LLVector4a* root_bounds = root->getBounds();  	LLVector4a offset; -	LLVector4a size = root->mBounds[1]; +	LLVector4a size = root_bounds[1];  	//VECTORIZE THIS  	LLMatrix4a mat; @@ -1160,7 +1160,7 @@ void LLSpatialBridge::updateSpatialExtents()  	LLVector4a center;  	mat.affineTransform(t, center); -	mat.rotate(root->mBounds[0], offset); +	mat.rotate(root_bounds[0], offset);  	center.add(offset);  	LLVector4a v[4]; @@ -1182,12 +1182,9 @@ void LLSpatialBridge::updateSpatialExtents()  	scale.mul(size);  	mat.rotate(scale, v[3]); -	 -	LLVector4a& newMin = mExtents[0]; -	LLVector4a& newMax = mExtents[1]; -	 -	newMin = newMax = center; -	 +	LLVector4a newMin; +	LLVector4a newMax;	 +	newMin = newMax = center;	  	for (U32 i = 0; i < 4; i++)  	{  		LLVector4a delta; @@ -1200,19 +1197,21 @@ void LLSpatialBridge::updateSpatialExtents()  		newMin.setMin(newMin, min);  		newMax.setMax(newMax, max);  	} -	 +	setSpatialExtents(newMin, newMax); +  	LLVector4a diagonal;  	diagonal.setSub(newMax, newMin);  	mRadius = diagonal.getLength3().getF32() * 0.5f; -	mPositionGroup.setAdd(newMin,newMax); -	mPositionGroup.mul(0.5f); +	LLVector4a& pos = getGroupPosition(); +	pos.setAdd(newMin,newMax); +	pos.mul(0.5f);  	updateBinRadius();  }  void LLSpatialBridge::updateBinRadius()  { -	mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f); +	setBinRadius(llmin( mOctree->getSize()[0]*0.5f, 256.f));  }  LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) @@ -1247,7 +1246,7 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)  void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)  { -	mVisible = sCurVisible; +	LLViewerOctreeEntryData::setVisible();  #if 0 && !LL_RELEASE_FOR_DOWNLOAD  	//crazy paranoid rules checking @@ -1282,21 +1281,21 @@ void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results,  #endif  } -class LLOctreeMarkNotCulled: public LLOctreeTraveler<LLDrawable> +class LLOctreeMarkNotCulled: public OctreeTraveler  {  public:  	LLCamera* mCamera;  	LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { } -	virtual void traverse(const LLOctreeNode<LLDrawable>* node) +	virtual void traverse(const OctreeNode* node)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);  		group->setVisible(); -		LLOctreeTraveler<LLDrawable>::traverse(node); +		OctreeTraveler::traverse(node);  	} -	void visit(const LLOctreeNode<LLDrawable>* branch) +	void visit(const OctreeNode* branch)  	{  		gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera);  	} @@ -1340,7 +1339,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*  			}  			if (!group || -				LLDrawable::getCurrentFrame() - av->mVisible > 1 || +				LLDrawable::getCurrentFrame() - av->getVisible() > 1 ||  				impostor ||  				!loaded)  			{ @@ -1354,16 +1353,17 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*  	group->rebound();  	LLVector4a center; -	center.setAdd(mExtents[0], mExtents[1]); +	const LLVector4a* exts = getSpatialExtents(); +	center.setAdd(exts[0], exts[1]);  	center.mul(0.5f);  	LLVector4a size; -	size.setSub(mExtents[1], mExtents[0]); +	size.setSub(exts[1], exts[0]);  	size.mul(0.5f);  	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||  		LLPipeline::sImpostorRender ||  		(camera_in.AABBInFrustumNoFarClip(center, size) &&  -		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist))) +		AABBSphereIntersect(exts[0], exts[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))  	{  		if (!LLPipeline::sImpostorRender &&  			!LLPipeline::sShadowRender &&  @@ -1478,9 +1478,7 @@ BOOL LLSpatialBridge::updateMove()  void LLSpatialBridge::shiftPos(const LLVector4a& vec)  { -	mExtents[0].add(vec); -	mExtents[1].add(vec); -	mPositionGroup.add(vec); +	LLDrawable::shift(vec);  }  void LLSpatialBridge::cleanupReferences() @@ -1488,11 +1486,8 @@ void LLSpatialBridge::cleanupReferences()  	LLDrawable::cleanupReferences();  	if (mDrawable)  	{ -		/* +		mDrawable->setGroup(NULL); -		DON'T DO THIS -- this should happen through octree destruction - -			mDrawable->setSpatialGroup(NULL);  		if (mDrawable->getVObj())  		{  			LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); @@ -1503,10 +1498,10 @@ void LLSpatialBridge::cleanupReferences()  				LLDrawable* drawable = child->mDrawable;					  				if (drawable)  				{ -						drawable->setSpatialGroup(NULL); -					} +					drawable->setGroup(NULL);				  				} -		}*/ +			} +		}  		LLDrawable* drawablep = mDrawable;  		mDrawable = NULL; @@ -1575,8 +1570,8 @@ void LLDrawable::updateFaceSize(S32 idx)  	}  } -LLBridgePartition::LLBridgePartition() -: LLSpatialPartition(0, FALSE, 0)  +LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp) +: LLSpatialPartition(0, FALSE, 0, regionp)   {   	mDrawableType = LLPipeline::RENDER_TYPE_AVATAR;   	mPartitionType = LLViewerRegion::PARTITION_BRIDGE; @@ -1584,8 +1579,8 @@ LLBridgePartition::LLBridgePartition()  	mSlopRatio = 0.25f;  } -LLHUDBridge::LLHUDBridge(LLDrawable* drawablep) -: LLVolumeBridge(drawablep) +LLHUDBridge::LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp) +: LLVolumeBridge(drawablep, regionp)  {  	mDrawableType = LLPipeline::RENDER_TYPE_HUD;  	mPartitionType = LLViewerRegion::PARTITION_HUD; diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index c22cce246b..161f550bb6 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -42,6 +42,7 @@  #include "llviewerobject.h"  #include "llrect.h"  #include "llappviewer.h" // for gFrameTimeSeconds +#include "llvieweroctree.h"  class LLCamera;  class LLDrawPool; @@ -60,11 +61,11 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;  // All data for new renderer goes into this class.  LL_ALIGN_PREFIX(16)  class LLDrawable  -:	public LLRefCount, -	public LLTrace::MemTrackable<LLDrawable, 16> +:	public LLViewerOctreeEntryData, +	public LLTrace::MemTrackable<LLDrawable>  {  public: -	LLDrawable(const LLDrawable& rhs) +	LLDrawable(const LLDrawable& rhs) : LLViewerOctreeEntryData(rhs)  	{  		*this = rhs;  	} @@ -77,7 +78,7 @@ public:  	static void initClass(); -	LLDrawable()				{ init(); } +	LLDrawable(LLViewerObject *vobj, bool new_entry = false);  	void markDead();			// Mark this drawable as dead  	BOOL isDead() const			{ return isState(DEAD); } @@ -85,11 +86,9 @@ public:  	BOOL isLight() const; -	BOOL isVisible() const;	 -	BOOL isRecentlyVisible() const;	  	virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE); - +	LLSpatialGroup* getSpatialGroup()const          {return (LLSpatialGroup*)getGroup();}  	LLViewerRegion* getRegion()               const { return mVObjp->getRegion(); }  	const LLTextureEntry* getTextureEntry(U8 which) const { return mVObjp->getTE(which); }  	LLPointer<LLViewerObject>& getVObj()							  { return mVObjp; } @@ -102,16 +101,12 @@ public:  	const LLVector3&	  getPosition() const			{ return mXform.getPosition(); }  	const LLVector3&      getWorldPosition() const		{ return mXform.getPositionW(); }  	const LLVector3		  getPositionAgent() const; -	const LLVector4a&	  getPositionGroup() const		{ return mPositionGroup; }  	const LLVector3&	  getScale() const				{ return mCurrentScale; }  	void				  setScale(const LLVector3& scale) { mCurrentScale = scale; }  	const LLQuaternion&   getWorldRotation() const		{ return mXform.getWorldRotation(); }  	const LLQuaternion&   getRotation() const			{ return mXform.getRotation(); }  	F32			          getIntensity() const			{ return llmin(mXform.getScale().mV[0], 4.f); }  	S32					  getLOD() const				{ return mVObjp ? mVObjp->getLOD() : 1; } -	F32					  getBinRadius() const			{ return mBinRadius; } -	S32					  getBinIndex() const			{ return mBinIndex; } -	void				  setBinIndex(S32 index) const	{ mBinIndex = index; }  	void  getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); }  	LLXformMatrix*		getXform() { return &mXform; } @@ -142,7 +137,7 @@ public:  	void                setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep);  	void				mergeFaces(LLDrawable* src); -	void init(); +	void init(bool new_entry);  	void destroy();  	void update(); @@ -173,8 +168,12 @@ public:  	BOOL getLit() const							{ return isState(UNLIT) ? FALSE : TRUE; }  	void setLit(BOOL lit)						{ lit ? clearState(UNLIT) : setState(UNLIT); } +	bool isVisible() const; +	bool isRecentlyVisible() const; +  	virtual void cleanupReferences(); +	void setGroup(LLviewerOctreeGroup* group);  	void setRadius(const F32 radius);  	F32 getRadius() const						{ return mRadius; }  	F32 getVisibilityRadius() const; @@ -184,11 +183,6 @@ public:  	const LLVector3& getBounds(LLVector3& min, LLVector3& max) const;  	virtual void updateSpatialExtents();  	virtual void updateBinRadius(); -	const LLVector4a* getSpatialExtents() const; -	void setSpatialExtents(const LLVector3& min, const LLVector3& max); -	void setSpatialExtents(const LLVector4a& min, const LLVector4a& max); - -	void setPositionGroup(const LLVector4a& pos);  	void setRenderType(S32 type) 				{ mRenderType = type; }  	BOOL isRenderType(S32 type) 				{ return mRenderType == type; } @@ -197,10 +191,14 @@ public:  	// Debugging methods  	S32 findReferences(LLDrawable *drawablep); // Not const because of @#$! iterators... -	void setSpatialGroup(LLSpatialGroup *groupp); -	LLSpatialGroup *getSpatialGroup() const;  	LLSpatialPartition* getSpatialPartition(); +	virtual S32 getMinVisFrameRange()const; +	void removeFromOctree(); + +	void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } +	LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } +  	// Statics  	static void incrementVisible();  	static void cleanupDeadDrawables(); @@ -285,10 +283,6 @@ public:  		ACTIVE_CHILD	= 0x40000000,  	} EDrawableFlags; -private: //aligned members -	LL_ALIGN_16(LLVector4a		mExtents[2]); -	LL_ALIGN_16(LLVector4a		mPositionGroup); -	  public:  	LLXformMatrix       mXform; @@ -297,12 +291,6 @@ public:  	F32				mDistanceWRTCamera; -	static S32 getCurrentFrame() { return sCurVisible; } -	static S32 getMinVisFrameRange(); - -	void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } -	LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } -	  	static F32 sCurPixelAngle; //current pixels per radian  	static LLTrace::MemStat sMemStat; @@ -313,18 +301,13 @@ private:  	S32							mRenderType;  	LLPointer<LLViewerObject>	mVObjp;  	face_list_t					mFaces; -	LLSpatialGroup*				mSpatialGroupp;  	LLPointer<LLDrawable>		mSpatialBridge; -	mutable U32					mVisible;  	F32							mRadius; -	F32							mBinRadius; -	mutable S32					mBinIndex;  	S32							mGeneration;  	LLVector3					mCurrentScale; -	static U32					sCurVisible; // Counter for what value of mVisible means currently visible  	static U32					sNumZombieDrawables;  	static LLDynamicArrayPtr<LLPointer<LLDrawable> > sDeadList;  } LL_ALIGN_POSTFIX(16); diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp new file mode 100644 index 0000000000..189697dcf0 --- /dev/null +++ b/indra/newview/llscenemonitor.cpp @@ -0,0 +1,460 @@ +/**  + * @file llscenemonitor.cpp + * @brief monitor the scene loading process. + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llrendertarget.h" +#include "llscenemonitor.h" +#include "llviewerwindow.h" +#include "llviewerdisplay.h" +#include "llviewercontrol.h" +#include "llviewershadermgr.h" +#include "llui.h" +#include "llstartup.h" +#include "llappviewer.h" +#include "llwindow.h" +#include "llpointer.h" +#include "llspatialpartition.h" + +LLSceneMonitorView* gSceneMonitorView = NULL; + +// +//The procedures of monitoring when the scene finishes loading visually,  +//i.e., no pixel differences among frames, are: +//1, freeze all dynamic objects and avatars; +//2, (?) disable all sky and water; +//3, capture frames periodically, by calling "capture()"; +//4, compute pixel differences between two latest captured frames, by calling "compare()", results are stored at mDiff; +//5, compute the number of pixels in mDiff above some tolerance threshold in GPU, by calling "queryDiff() -> calcDiffAggregate()"; +//6, use gl occlusion query to fetch the result from GPU, by calling "fetchQueryResult()"; +//END. +// + +LLSceneMonitor::LLSceneMonitor() :  +	mEnabled(FALSE),  +	mDiff(NULL), +	mDiffResult(0.f), +	mDiffTolerance(0.1f), +	mCurTarget(NULL),  +	mNeedsUpdateDiff(FALSE), +	mHasNewDiff(FALSE), +	mHasNewQueryResult(FALSE), +	mDebugViewerVisible(FALSE), +	mQueryObject(0), +	mSamplingTime(1.0f), +	mDiffPixelRatio(0.5f) +{ +	mFrames[0] = NULL; +	mFrames[1] = NULL;	 +} + +LLSceneMonitor::~LLSceneMonitor() +{ +	destroyClass(); +} + +void LLSceneMonitor::destroyClass() +{ +	reset(); +} + +void LLSceneMonitor::reset() +{ +	delete mFrames[0]; +	delete mFrames[1]; +	delete mDiff; + +	mFrames[0] = NULL; +	mFrames[1] = NULL; +	mDiff = NULL; +	mCurTarget = NULL; + +	unfreezeScene(); + +	if(mQueryObject > 0) +	{ +		release_occlusion_query_object_name(mQueryObject); +		mQueryObject = 0; +	} +} + +void LLSceneMonitor::setDebugViewerVisible(BOOL visible)  +{ +	mDebugViewerVisible = visible; +} + +bool LLSceneMonitor::preCapture() +{ +	static LLCachedControl<bool> monitor_enabled(gSavedSettings,"SceneLoadingMonitorEnabled"); +	static LLFrameTimer timer;	 + +	mCurTarget = NULL; +	if (!LLGLSLShader::sNoFixedFunction) +	{ +		return false; +	} + +	BOOL enabled = (BOOL)monitor_enabled || mDebugViewerVisible; +	if(mEnabled != enabled) +	{ +		if(mEnabled) +		{ +			reset(); +			unfreezeScene(); +		} +		else +		{ +			freezeScene(); +		} + +		mEnabled = enabled; +	} + +	if(!mEnabled) +	{ +		return false; +	} + +	if(timer.getElapsedTimeF32() < mSamplingTime) +	{ +		return false; +	} +	timer.reset(); +	 +	S32 width = gViewerWindow->getWorldViewWidthRaw(); +	S32 height = gViewerWindow->getWorldViewHeightRaw(); +	 +	if(!mFrames[0]) +	{ +		mFrames[0] = new LLRenderTarget(); +		mFrames[0]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true); +		gGL.getTexUnit(0)->bind(mFrames[0]); +		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +		mCurTarget = mFrames[0]; +	} +	else if(!mFrames[1]) +	{ +		mFrames[1] = new LLRenderTarget(); +		mFrames[1]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true); +		gGL.getTexUnit(0)->bind(mFrames[1]); +		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +		mCurTarget = mFrames[1]; +	} +	else //swap +	{ +		mCurTarget = mFrames[0]; +		mFrames[0] = mFrames[1]; +		mFrames[1] = mCurTarget; +	} +	 +	if(mCurTarget->getWidth() != width || mCurTarget->getHeight() != height) //size changed +	{ +		mCurTarget->resize(width, height, GL_RGB); +	} + +	return true; +} + +void LLSceneMonitor::freezeAvatar(LLCharacter* avatarp) +{ +	mAvatarPauseHandles.push_back(avatarp->requestPause()); +} + +void LLSceneMonitor::freezeScene() +{ +	//freeze all avatars +	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); +		iter != LLCharacter::sInstances.end(); ++iter) +	{ +		freezeAvatar((LLCharacter*)(*iter)); +	} + +	// freeze everything else +	gSavedSettings.setBOOL("FreezeTime", TRUE); +} + +void LLSceneMonitor::unfreezeScene() +{ +	//thaw all avatars +	mAvatarPauseHandles.clear(); + +	// thaw everything else +	gSavedSettings.setBOOL("FreezeTime", FALSE); +} + +void LLSceneMonitor::capture() +{ +	static U32 last_capture_time = 0; + +	if(last_capture_time == gFrameCount) +	{ +		return; +	} +	last_capture_time = gFrameCount; + +	preCapture(); + +	if(!mCurTarget) +	{ +		return; +	} +	 +	U32 old_FBO = LLRenderTarget::sCurFBO; + +	gGL.getTexUnit(0)->bind(mCurTarget); +	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); //point to the main frame buffer. +		 +	glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, mCurTarget->getWidth(), mCurTarget->getHeight()); //copy the content +	 +	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);		 +	glBindFramebuffer(GL_FRAMEBUFFER, old_FBO); + +	mCurTarget = NULL; +	mNeedsUpdateDiff = TRUE; +} + +bool LLSceneMonitor::needsUpdate() const +{ +	return mNeedsUpdateDiff; +} + +void LLSceneMonitor::compare() +{ +	if(!mNeedsUpdateDiff) +	{ +		return; +	} +	mNeedsUpdateDiff = FALSE; + +	if(!mFrames[0] || !mFrames[1]) +	{ +		return; +	} +	if(mFrames[0]->getWidth() != mFrames[1]->getWidth() || mFrames[0]->getHeight() != mFrames[1]->getHeight()) +	{ +		return; //size does not match +	} + +	S32 width = gViewerWindow->getWindowWidthRaw(); +	S32 height = gViewerWindow->getWindowHeightRaw(); +	if(!mDiff) +	{ +		mDiff = new LLRenderTarget(); +		mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true); +	} +	else if(mDiff->getWidth() != width || mDiff->getHeight() != height) +	{ +		mDiff->resize(width, height, GL_RGBA); +	} + +	mDiff->bindTarget(); +	mDiff->clear(); +	 +	gTwoTextureCompareProgram.bind(); +	 +	gGL.getTexUnit(0)->activate(); +	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); +	gGL.getTexUnit(0)->bind(mFrames[0]); +	gGL.getTexUnit(0)->activate(); + +	gGL.getTexUnit(1)->activate(); +	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); +	gGL.getTexUnit(1)->bind(mFrames[1]); +	gGL.getTexUnit(1)->activate();	 +	 +	gl_rect_2d_simple_tex(width, height); +	 +	mDiff->flush();	 + +	gTwoTextureCompareProgram.unbind(); + +	gGL.getTexUnit(0)->disable(); +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	gGL.getTexUnit(1)->disable(); +	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); + +	mHasNewDiff = TRUE; +	 +	//send out the query request. +	queryDiff(); +} + +void LLSceneMonitor::queryDiff() +{ +	if(mDebugViewerVisible) +	{ +		return; +	} + +	calcDiffAggregate(); +} + +//calculate Diff aggregate information in GPU, and enable gl occlusion query to capture it. +void LLSceneMonitor::calcDiffAggregate() +{ +	if(!mHasNewDiff && !mDebugViewerVisible) +	{ +		return; +	}	 + +	if(!mQueryObject) +	{ +		mQueryObject = get_new_occlusion_query_object_name(); +	} + +	LLGLDepthTest depth(true, false, GL_ALWAYS); +	if(!mDebugViewerVisible) +	{ +		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); +	} + +	LLGLSLShader* cur_shader = NULL; +	 +	cur_shader = LLGLSLShader::sCurBoundShaderPtr; +	gOneTextureFilterProgram.bind(); +	gOneTextureFilterProgram.uniform1f("tolerance", mDiffTolerance); + +	if(mHasNewDiff) +	{ +		glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryObject); +	} + +	gl_draw_scaled_target(0, 0, S32(mDiff->getWidth() * mDiffPixelRatio), S32(mDiff->getHeight() * mDiffPixelRatio), mDiff); + +	if(mHasNewDiff) +	{ +		glEndQueryARB(GL_SAMPLES_PASSED_ARB); +		mHasNewDiff = FALSE;	 +		mHasNewQueryResult = TRUE; +	} +		 +	gOneTextureFilterProgram.unbind(); +	 +	if(cur_shader != NULL) +	{ +		cur_shader->bind(); +	} +	 +	if(!mDebugViewerVisible) +	{ +		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +	}	 +} + +void LLSceneMonitor::fetchQueryResult() +{ +	if(!mHasNewQueryResult) +	{ +		return; +	} +	mHasNewQueryResult = FALSE; + +	GLuint available = 0; +	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_AVAILABLE_ARB, &available); +	if(!available) +	{ +		return; +	} + +	GLuint count = 0; +	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_ARB, &count); +	 +	mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * mDiffPixelRatio * mDiffPixelRatio); //0.5 -> (front face + back face) + +	//llinfos << count << " : " << mDiffResult << llendl; +} +//------------------------------------------------------------------------------------------------------------- +//definition of class LLSceneMonitorView +//------------------------------------------------------------------------------------------------------------- +LLSceneMonitorView::LLSceneMonitorView(const LLRect& rect) +	:	LLFloater(LLSD()) +{ +	setRect(rect); +	setVisible(FALSE); +	 +	setCanMinimize(false); +	setCanClose(true); +} + +void LLSceneMonitorView::onClickCloseBtn() +{ +	setVisible(false);	 +} + +void LLSceneMonitorView::setVisible(BOOL visible) +{ +	LLSceneMonitor::getInstance()->setDebugViewerVisible(visible); + +	LLView::setVisible(visible); +} + +void LLSceneMonitorView::draw() +{ +	const LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget(); +	if(!target) +	{ +		return; +	} + +	F32 ratio = LLSceneMonitor::getInstance()->getDiffPixelRatio(); +	S32 height = (S32)(target->getHeight() * ratio); +	S32 width = (S32)(target->getWidth() * ratio); +	//S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f); +	//S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f); +	 +	LLRect new_rect; +	new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height); +	setRect(new_rect); + +	//draw background +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); +	 +	LLSceneMonitor::getInstance()->calcDiffAggregate(); + +	//show some texts +	LLColor4 color = LLColor4::white; +	S32 line_height = LLFontGL::getFontMonospace()->getLineHeight(); + +	S32 lines = 0; +	std::string num_str = llformat("Frame difference: %.6f", LLSceneMonitor::getInstance()->getDiffResult()); +	LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP); +	lines++; + +	num_str = llformat("Pixel tolerance: (R+G+B) < %.4f", LLSceneMonitor::getInstance()->getDiffTolerance()); +	LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP); +	lines++; + +	num_str = llformat("Sampling time: %.3f seconds", LLSceneMonitor::getInstance()->getSamplingTime()); +	LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP); + +	LLView::draw(); +} + diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h new file mode 100644 index 0000000000..02e3d57d46 --- /dev/null +++ b/indra/newview/llscenemonitor.h @@ -0,0 +1,106 @@ +/**  + * @file llscenemonitor.h + * @brief monitor the process of scene loading + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLSCENE_MONITOR_H +#define LL_LLSCENE_MONITOR_H + +#include "llsingleton.h" +#include "llmath.h" +#include "llfloater.h" +#include "llcharacter.h" + +class LLCharacter; +class LLRenderTarget; + +class LLSceneMonitor :  public LLSingleton<LLSceneMonitor> +{ +public: +	LLSceneMonitor(); +	~LLSceneMonitor(); + +	void destroyClass(); +	 +	void freezeAvatar(LLCharacter* avatarp); +	void setDebugViewerVisible(BOOL visible); + +	void capture(); //capture the main frame buffer +	void compare(); //compare the stored two buffers.	 +	void queryDiff();	 +	void fetchQueryResult(); +	void calcDiffAggregate(); +	void setDiffTolerance(F32 tol) {mDiffTolerance = tol;} + +	const LLRenderTarget* getDiffTarget() const {return mDiff;} +	F32  getDiffTolerance() const {return mDiffTolerance;} +	F32  getDiffResult() const { return mDiffResult;} +	F32  getSamplingTime() const { return mSamplingTime;} +	F32  getDiffPixelRatio() const { return mDiffPixelRatio;} +	bool isEnabled()const {return mEnabled;} +	bool needsUpdate() const; +	 +private: +	void freezeScene(); +	void unfreezeScene(); +	void reset(); +	bool preCapture(); + +private: +	BOOL mEnabled; +	BOOL mNeedsUpdateDiff; +	BOOL mHasNewDiff; +	BOOL mHasNewQueryResult; +	BOOL mDebugViewerVisible; + +	LLRenderTarget* mFrames[2]; +	LLRenderTarget* mDiff; +	LLRenderTarget* mCurTarget; + +	GLuint  mQueryObject; //used for glQuery +	F32     mDiffResult;  //aggregate results of mDiff. +	F32     mDiffTolerance; //pixels are filtered out when R+G+B < mDiffTolerance + +	F32     mSamplingTime; //time interval to capture frames, in seconds +	F32     mDiffPixelRatio; //ratio of pixels used for comparison against the original mDiff size along one dimension + +	std::vector<LLAnimPauseRequest> mAvatarPauseHandles; +}; + +class LLSceneMonitorView : public LLFloater +{ +public: +	LLSceneMonitorView(const LLRect& rect); + +	virtual void draw(); +	virtual void setVisible(BOOL visible); + +protected: +	virtual void onClickCloseBtn(); +}; + +extern LLSceneMonitorView* gSceneMonitorView; + +#endif + diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 88fb609d1c..0e2109c4af 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -126,106 +126,28 @@ protected:  static LLOcclusionQueryPool sQueryPool; -//static counter for frame to switch LOD on - -void sg_assert(BOOL expr) -{ -#if LL_OCTREE_PARANOIA_CHECK -	if (!expr) -	{ -		llerrs << "Octree invalid!" << llendl; -	} -#endif -} - -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) +GLuint get_new_occlusion_query_object_name()  { -	return AABBSphereIntersectR2(min, max, origin, rad*rad); +	return sQueryPool.allocate();  } -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) +void release_occlusion_query_object_name(GLuint name)  { -	F32 d = 0.f; -	F32 t; -	 -	if ((min-origin).magVecSquared() < r && -		(max-origin).magVecSquared() < r) -	{ -		return 2; -	} - -	for (U32 i = 0; i < 3; i++) -	{ -		if (origin.mV[i] < min.mV[i]) -		{ -			t = min.mV[i] - origin.mV[i]; -			d += t*t; -		} -		else if (origin.mV[i] > max.mV[i]) -		{ -			t = origin.mV[i] - max.mV[i]; -			d += t*t; -		} - -		if (d > r) -		{ -			return 0; -		} -	} - -	return 1; +	sQueryPool.release(name);  } +//static counter for frame to switch LOD on -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) -{ -	return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) +void sg_assert(BOOL expr)  { -	F32 d = 0.f; -	F32 t; -	 -	LLVector4a origina; -	origina.load3(origin.mV); - -	LLVector4a v; -	v.setSub(min, origina); -	 -	if (v.dot3(v) < r) -	{ -		v.setSub(max, origina); -		if (v.dot3(v) < r) -		{ -			return 2; -		} -	} - - -	for (U32 i = 0; i < 3; i++) +#if LL_OCTREE_PARANOIA_CHECK +	if (!expr)  	{ -		if (origin.mV[i] < min[i]) -		{ -			t = min[i] - origin.mV[i]; -			d += t*t; -		} -		else if (origin.mV[i] > max[i]) -		{ -			t = origin.mV[i] - max[i]; -			d += t*t; -		} - -		if (d > r) -		{ -			return 0; -		} +		llerrs << "Octree invalid!" << llendl;  	} - -	return 1; +#endif  } -  typedef enum  {  	b000 = 0x00, @@ -352,13 +274,13 @@ LLSpatialGroup::~LLSpatialGroup()  	{  		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;  	}*/ - +	  	if (gDebugGL)  	{  		gPipeline.checkReferences(this);  	} -	if (isState(DEAD)) +	if (hasState(DEAD))  	{  		sZombieGroups--;  	} @@ -371,7 +293,7 @@ LLSpatialGroup::~LLSpatialGroup()  		{  			if (mOcclusionQuery[i])  			{ -				sQueryPool.release(mOcclusionQuery[i]); +				release_occlusion_query_object_name(mOcclusionQuery[i]);  			}  		}  	} @@ -514,17 +436,8 @@ BOOL LLSpatialGroup::isHUDGroup()  BOOL LLSpatialGroup::isRecentlyVisible() const  { -	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ; -} - -BOOL LLSpatialGroup::isVisible() const -{ -	return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; -} - -void LLSpatialGroup::setVisible() -{ -	mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame(); +	const S32 MIN_VIS_FRAME_RANGE = 2; +	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < MIN_VIS_FRAME_RANGE ;  }  void LLSpatialGroup::validate() @@ -619,7 +532,7 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)  	OctreeNode* parent = mOctreeNode->getOctParent();  	if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&  -		(mOctreeNode->contains(drawablep) || +		(mOctreeNode->contains(drawablep->getEntry()) ||  		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&  				parent && parent->getElementCount() >= gOctreeMaxCapacity)))  	{ @@ -633,15 +546,14 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)  } -BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree) +BOOL LLSpatialGroup::addObject(LLDrawable *drawablep)  { -	if (!from_octree) +	if(!drawablep)  	{ -		mOctreeNode->insert(drawablep); +		return FALSE;  	} -	else  	{ -		drawablep->setSpatialGroup(this); +		drawablep->setGroup(this);  		setState(OBJECT_DIRTY | GEOM_DIRTY);  		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);  		gPipeline.markRebuild(this, TRUE); @@ -664,7 +576,7 @@ void LLSpatialGroup::rebuildGeom()  	{  		mSpatialPartition->rebuildGeom(this); -		if (isState(LLSpatialGroup::MESH_DIRTY)) +		if (hasState(LLSpatialGroup::MESH_DIRTY))  		{  			gPipeline.markMeshDirty(this);  		} @@ -686,7 +598,7 @@ static LLFastTimer::DeclareTimer FTM_GET_GEOMETRY("Get Geometry");  void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)  { -	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) +	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))  	{  		return;  	} @@ -751,103 +663,6 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)  } -BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) -{	 -	const OctreeNode* node = mOctreeNode; - -	if (node->isEmpty()) -	{	//don't do anything if there are no objects -		if (empty && mOctreeNode->getParent()) -		{	//only root is allowed to be empty -			OCT_ERRS << "Empty leaf found in octree." << llendl; -		} -		return FALSE; -	} - -	LLVector4a& newMin = mObjectExtents[0]; -	LLVector4a& newMax = mObjectExtents[1]; -	 -	if (isState(OBJECT_DIRTY)) -	{ //calculate new bounding box -		clearState(OBJECT_DIRTY); - -		//initialize bounding box to first element -		OctreeNode::const_element_iter i = node->getDataBegin(); -		LLDrawable* drawablep = *i; -		const LLVector4a* minMax = drawablep->getSpatialExtents(); - -		newMin = minMax[0]; -		newMax = minMax[1]; - -		for (++i; i != node->getDataEnd(); ++i) -		{ -			drawablep = *i; -			minMax = drawablep->getSpatialExtents(); -			 -			update_min_max(newMin, newMax, minMax[0]); -			update_min_max(newMin, newMax, minMax[1]); - -			//bin up the object -			/*for (U32 i = 0; i < 3; i++) -			{ -				if (minMax[0].mV[i] < newMin.mV[i]) -				{ -					newMin.mV[i] = minMax[0].mV[i]; -				} -				if (minMax[1].mV[i] > newMax.mV[i]) -				{ -					newMax.mV[i] = minMax[1].mV[i]; -				} -			}*/ -		} -		 -		mObjectBounds[0].setAdd(newMin, newMax); -		mObjectBounds[0].mul(0.5f); -		mObjectBounds[1].setSub(newMax, newMin); -		mObjectBounds[1].mul(0.5f); -	} -	 -	if (empty) -	{ -		minOut = newMin; -		maxOut = newMax; -	} -	else -	{ -		minOut.setMin(minOut, newMin); -		maxOut.setMax(maxOut, newMax); -	} -		 -	return TRUE; -} - -void LLSpatialGroup::unbound() -{ -	if (isState(DIRTY)) -	{ -		return; -	} - -	setState(DIRTY); -	 -	//all the parent nodes need to rebound this child -	if (mOctreeNode) -	{ -		OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); -		while (parent != NULL) -		{ -			LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0); -			if (group->isState(DIRTY)) -			{ -				return; -			} -			 -			group->setState(DIRTY); -			parent = (OctreeNode*) parent->getParent(); -		} -	} -} -  LLSpatialGroup* LLSpatialGroup::getParent()  {  	if (isDead()) @@ -871,17 +686,19 @@ LLSpatialGroup* LLSpatialGroup::getParent()  BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)  { +	if(!drawablep) +	{ +		return FALSE; +	} +  	unbound();  	if (mOctreeNode && !from_octree)  	{ -		if (!mOctreeNode->remove(drawablep)) -		{ -			OCT_ERRS << "Could not remove drawable from spatial group" << llendl; -		} +		drawablep->setGroup(NULL);  	}  	else  	{ -		drawablep->setSpatialGroup(NULL); +		drawablep->setGroup(NULL);  		setState(GEOM_DIRTY);  		gPipeline.markRebuild(this, TRUE); @@ -928,12 +745,12 @@ void LLSpatialGroup::shift(const LLVector4a &offset)  	}  } -class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler +class LLSpatialSetState : public OctreeTraveler  {  public:  	U32 mState;  	LLSpatialSetState(U32 state) : mState(state) { } -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	 +	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	  };  class LLSpatialSetStateDiff : public LLSpatialSetState @@ -941,24 +758,17 @@ class LLSpatialSetStateDiff : public LLSpatialSetState  public:  	LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { } -	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	virtual void traverse(const OctreeNode* n)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); -		if (!group->isState(mState)) +		if (!group->hasState(mState))  		{ -			LLSpatialGroup::OctreeTraveler::traverse(n); +			OctreeTraveler::traverse(n);  		}  	}  }; -void LLSpatialGroup::setState(U32 state)  -{  -	mState |= state;  -	 -	llassert(state <= LLSpatialGroup::STATE_MASK); -}	 -  void LLSpatialGroup::setState(U32 state, S32 mode)   {  	llassert(state <= LLSpatialGroup::STATE_MASK); @@ -982,12 +792,12 @@ void LLSpatialGroup::setState(U32 state, S32 mode)  	}  } -class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler +class LLSpatialClearState : public OctreeTraveler  {  public:  	U32 mState;  	LLSpatialClearState(U32 state) : mState(state) { } -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); } +	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }  };  class LLSpatialClearStateDiff : public LLSpatialClearState @@ -995,24 +805,17 @@ class LLSpatialClearStateDiff : public LLSpatialClearState  public:  	LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { } -	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	virtual void traverse(const OctreeNode* n)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); -		if (group->isState(mState)) +		if (group->hasState(mState))  		{ -			LLSpatialGroup::OctreeTraveler::traverse(n); +			OctreeTraveler::traverse(n);  		}  	}  }; -void LLSpatialGroup::clearState(U32 state) -{ -	llassert(state <= LLSpatialGroup::STATE_MASK); - -	mState &= ~state;  -} -  void LLSpatialGroup::clearState(U32 state, S32 mode)  {  	llassert(state <= LLSpatialGroup::STATE_MASK); @@ -1036,22 +839,15 @@ void LLSpatialGroup::clearState(U32 state, S32 mode)  	}  } -BOOL LLSpatialGroup::isState(U32 state) const -{  -	llassert(state <= LLSpatialGroup::STATE_MASK); - -	return mState & state ? TRUE : FALSE;  -} -  //=====================================  //		Occlusion State Set/Clear  //===================================== -class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler +class LLSpatialSetOcclusionState : public OctreeTraveler  {  public:  	U32 mState;  	LLSpatialSetOcclusionState(U32 state) : mState(state) { } -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	 +	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	  };  class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState @@ -1059,13 +855,13 @@ class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState  public:  	LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { } -	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	virtual void traverse(const OctreeNode* n)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);  		if (!group->isOcclusionState(mState))  		{ -			LLSpatialGroup::OctreeTraveler::traverse(n); +			OctreeTraveler::traverse(n);  		}  	}  }; @@ -1093,7 +889,7 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)  				if ((state & DISCARD_QUERY) && mOcclusionQuery[i])  				{ -					sQueryPool.release(mOcclusionQuery[i]); +					release_occlusion_query_object_name(mOcclusionQuery[i]);  					mOcclusionQuery[i] = 0;  				}  			} @@ -1104,19 +900,19 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)  		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;  		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])  		{ -			sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +			release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);  			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;  		}  	}  } -class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler +class LLSpatialClearOcclusionState : public OctreeTraveler  {  public:  	U32 mState;  	LLSpatialClearOcclusionState(U32 state) : mState(state) { } -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); } +	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }  };  class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState @@ -1124,13 +920,13 @@ class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState  public:  	LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { } -	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	virtual void traverse(const OctreeNode* n)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);  		if (group->isOcclusionState(mState))  		{ -			LLSpatialGroup::OctreeTraveler::traverse(n); +			OctreeTraveler::traverse(n);  		}  	}  }; @@ -1166,13 +962,11 @@ void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)  //		Octree Listener Implementation  //====================================== -LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : +LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLviewerOctreeGroup(node),  	mObjectBoxSize(1.f), -	mState(0),  	mGeometryBytes(0),  	mSurfaceArea(0.f),  	mBuilt(0.f), -	mOctreeNode(node),  	mSpatialPartition(part),  	mVertexBuffer(NULL),   	mBufferUsage(part->mBufferUsage), @@ -1191,17 +985,11 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :  	mViewAngle.splat(0.f);  	mLastUpdateViewAngle.splat(-1.f); -	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =  -		mObjectExtents[0] = mObjectExtents[1] = mViewAngle; - +	  	sg_assert(mOctreeNode->getListenerCount() == 0); -	mOctreeNode->addListener(this);  	setState(SG_INITIAL_STATE_MASK);  	gPipeline.markRebuild(this, TRUE); -	mBounds[0] = node->getCenter(); -	mBounds[1] = node->getSize(); -  	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;  	mLODHash = part->mLODSeed; @@ -1235,7 +1023,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)  	}  #if !LL_RELEASE_FOR_DOWNLOAD -	if (isState(LLSpatialGroup::OBJECT_DIRTY)) +	if (hasState(LLSpatialGroup::OBJECT_DIRTY))  	{  		llerrs << "Spatial group dirty on distance update." << llendl;  	} @@ -1266,7 +1054,7 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)  		dist = eye.getLength3().getF32();  		eye.normalize3fast(); -		if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) +		if (!group->hasState(LLSpatialGroup::ALPHA_DIRTY))  		{  			if (!group->mSpatialPartition->isBridge())  			{ @@ -1343,7 +1131,7 @@ BOOL LLSpatialGroup::needsUpdate()  BOOL LLSpatialGroup::changeLOD()  { -	if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) +	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))  	{ ///a rebuild is going to happen, update distance and LoD  		return TRUE;  	} @@ -1371,29 +1159,36 @@ BOOL LLSpatialGroup::changeLOD()  	return FALSE;  } -void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep) +void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)  { -	addObject(drawablep, FALSE, TRUE); +	addObject((LLDrawable*)entry->getDrawable());  	unbound();  	setState(OBJECT_DIRTY);  } -void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable) +void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)  { -	removeObject(drawable, TRUE); -	setState(OBJECT_DIRTY); +	removeObject((LLDrawable*)entry->getDrawable(), TRUE); +	LLviewerOctreeGroup::handleRemoval(node, entry);  }  void LLSpatialGroup::handleDestruction(const TreeNode* node)  {  	setState(DEAD); -	 +  	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)  	{ -		LLDrawable* drawable = *i; -		if (drawable->getSpatialGroup() == this) +		LLViewerOctreeEntry* entry = *i; +		if (entry->getGroup() == this)  		{ -			drawable->setSpatialGroup(NULL); +			if(entry->hasDrawable()) +			{ +				((LLDrawable*)entry->getDrawable())->setGroup(NULL); +			} +			else +			{ +				llerrs << "No Drawable found in the entry." << llendl; +			}  		}  	} @@ -1415,16 +1210,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)  	mOctreeNode = NULL;  } -void LLSpatialGroup::handleStateChange(const TreeNode* node) -{ -	//drop bounding box upon state change -	if (mOctreeNode != node) -	{ -		mOctreeNode = (OctreeNode*) node; -	} -	unbound(); -} -  void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)   {  	if (child->getListenerCount() == 0) @@ -1441,11 +1226,6 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c  	assert_states_valid(this);  } -void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) -{ -	unbound(); -} -  void LLSpatialGroup::destroyGL(bool keep_occlusion)   {  	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); @@ -1467,7 +1247,7 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)  		{  			if (mOcclusionQuery[i])  			{ -				sQueryPool.release(mOcclusionQuery[i]); +				release_occlusion_query_object_name(mOcclusionQuery[i]);  				mOcclusionQuery[i] = 0;  			}  		} @@ -1476,7 +1256,11 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)  	for (LLSpatialGroup::element_iter i = getDataBegin(); i != getDataEnd(); ++i)  	{ -		LLDrawable* drawable = *i; +		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +		if(!drawable) +		{ +			continue; +		}  		for (S32 j = 0; j < drawable->getNumFaces(); j++)  		{  			LLFace* facep = drawable->getFace(j); @@ -1488,69 +1272,6 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)  	}  } -BOOL LLSpatialGroup::rebound() -{ -	if (!isState(DIRTY)) -	{	//return TRUE if we're not empty -		return TRUE; -	} -	 -	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) -	{ -		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); -		group->rebound(); -		 -		//copy single child's bounding box -		mBounds[0] = group->mBounds[0]; -		mBounds[1] = group->mBounds[1]; -		mExtents[0] = group->mExtents[0]; -		mExtents[1] = group->mExtents[1]; -		 -		group->setState(SKIP_FRUSTUM_CHECK); -	} -	else if (mOctreeNode->isLeaf()) -	{ //copy object bounding box if this is a leaf -		boundObjects(TRUE, mExtents[0], mExtents[1]); -		mBounds[0] = mObjectBounds[0]; -		mBounds[1] = mObjectBounds[1]; -	} -	else -	{ -		LLVector4a& newMin = mExtents[0]; -		LLVector4a& newMax = mExtents[1]; -		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); -		group->clearState(SKIP_FRUSTUM_CHECK); -		group->rebound(); -		//initialize to first child -		newMin = group->mExtents[0]; -		newMax = group->mExtents[1]; - -		//first, rebound children -		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) -		{ -			group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); -			group->clearState(SKIP_FRUSTUM_CHECK); -			group->rebound(); -			const LLVector4a& max = group->mExtents[1]; -			const LLVector4a& min = group->mExtents[0]; - -			newMax.setMax(newMax, max); -			newMin.setMin(newMin, min); -		} - -		boundObjects(FALSE, newMin, newMax); -		 -		mBounds[0].setAdd(newMin, newMax); -		mBounds[0].mul(0.5f); -		mBounds[1].setSub(newMax, newMin); -		mBounds[1].mul(0.5f); -	} -	 -	clearState(DIRTY); - -	return TRUE; -} -  static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");  static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait"); @@ -1607,7 +1328,7 @@ void LLSpatialGroup::checkOcclusion()  				}  				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])  				{ //delete the query to avoid holding onto hundreds of pending queries -					sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +					release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);  					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;  				} @@ -1679,7 +1400,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)  					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])  					{  						LLFastTimer t(FTM_OCCLUSION_ALLOCATE); -						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); +						mOcclusionQuery[LLViewerCamera::sCurCameraID] = get_new_occlusion_query_object_name();  					}  					// Depth clamp all water to avoid it being culled as a result of being @@ -1769,9 +1490,10 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)  //============================================== -LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage) +LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp)  : mRenderByGroup(render_by_group), mBridge(NULL)  { +	mRegionp = regionp;  	mOcclusionEnabled = TRUE;  	mDrawableType = 0;  	mPartitionType = LLViewerRegion::PARTITION_NONE; @@ -1781,37 +1503,32 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32  	mBufferUsage = buffer_usage;  	mDepthMask = FALSE;  	mSlopRatio = 0.25f; -	mInfiniteFarClip = FALSE; +	mInfiniteFarClip = FALSE;	 -	LLVector4a center, size; -	center.splat(0.f); -	size.splat(1.f); - -	mOctree = new LLSpatialGroup::OctreeRoot(center,size, -											NULL);  	new LLSpatialGroup(mOctree, this);  }  LLSpatialPartition::~LLSpatialPartition() -{ -	delete mOctree; -	mOctree = NULL; +{	  } -  LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)  {  	drawablep->updateSpatialExtents();  	//keep drawable from being garbage collected  	LLPointer<LLDrawable> ptr = drawablep; -		 -	assert_octree_valid(mOctree); -	mOctree->insert(drawablep); -	assert_octree_valid(mOctree); +			 +	if(!drawablep->getGroup()) +	{ +		assert_octree_valid(mOctree); +		mOctree->insert(drawablep->getEntry()); +		assert_octree_valid(mOctree); +	}	  	LLSpatialGroup* group = drawablep->getSpatialGroup(); +	llassert(group != NULL);  	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))  	{ @@ -1829,11 +1546,9 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)  	}  	else  	{ -		drawablep->setSpatialGroup(NULL); +		drawablep->setGroup(NULL);  	} -	drawablep->setSpatialGroup(NULL); -  	assert_octree_valid(mOctree);  	return TRUE; @@ -1883,13 +1598,13 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL  	put(drawablep, was_visible);  } -class LLSpatialShift : public LLSpatialGroup::OctreeTraveler +class LLSpatialShift : public OctreeTraveler  {  public:  	const LLVector4a& mOffset;  	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { } -	virtual void visit(const LLSpatialGroup::OctreeNode* branch)  +	virtual void visit(const OctreeNode* branch)   	{   		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);   	} @@ -1901,17 +1616,17 @@ void LLSpatialPartition::shift(const LLVector4a &offset)  	shifter.traverse(mOctree);  } -class LLOctreeCull : public LLSpatialGroup::OctreeTraveler +class LLOctreeCull : public LLViewerOctreeCull  {  public: -	LLOctreeCull(LLCamera* camera) -		: mCamera(camera), mRes(0) { } +	LLOctreeCull(LLCamera* camera) : LLViewerOctreeCull(camera) {} -	virtual bool earlyFail(LLSpatialGroup* group) +	virtual bool earlyFail(LLviewerOctreeGroup* base_group)  	{ +		LLSpatialGroup* group = (LLSpatialGroup*)base_group;  		group->checkOcclusion(); -		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node +		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node  		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled  			group->isOcclusionState(LLSpatialGroup::OCCLUDED))  		{ @@ -1921,79 +1636,30 @@ public:  		return false;  	} -	 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n) -	{ -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - -		if (earlyFail(group)) -		{ -			return; -		} -		if (mRes == 2 ||  -			(mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))) -		{	//fully in, just add everything -			LLSpatialGroup::OctreeTraveler::traverse(n); -		} -		else -		{ -			mRes = frustumCheck(group); -				 -			if (mRes) -			{ //at least partially in, run on down -				LLSpatialGroup::OctreeTraveler::traverse(n); -			} - -			mRes = 0; -		} -	} -	 -	virtual S32 frustumCheck(const LLSpatialGroup* group) +	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)  	{ -		S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +		S32 res = AABBInFrustumNoFarClipGroupBounds(group);  		if (res != 0)  		{ -			res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); +			res = llmin(res, AABBSphereIntersectGroupExtents(group));  		}  		return res;  	} -	virtual S32 frustumCheckObjects(const LLSpatialGroup* group) +	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)  	{ -		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +		S32 res = AABBInFrustumNoFarClipObjectBounds(group);  		if (res != 0)  		{ -			res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); +			res = llmin(res, AABBSphereIntersectObjectExtents(group));  		}  		return res;  	} -	virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group) -	{ -		if (branch->getElementCount() == 0) //no elements -		{ -			return false; -		} -		else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box -		{ -			return true; -		} -		else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum -		{ -			return false; -		} -		 -		return true; -	} - -	virtual void preprocess(LLSpatialGroup* group) -	{ -		 -	} -	 -	virtual void processGroup(LLSpatialGroup* group) +	virtual void processGroup(LLviewerOctreeGroup* base_group)  	{ +		LLSpatialGroup* group = (LLSpatialGroup*)base_group;  		if (group->needsUpdate() ||  			group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)  		{ @@ -2001,21 +1667,6 @@ public:  		}  		gPipeline.markNotCulled(group, *mCamera);  	} -	 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch)  -	{	 -		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - -		preprocess(group); -		 -		if (checkObjects(branch, group)) -		{ -			processGroup(group); -		} -	} - -	LLCamera *mCamera; -	S32 mRes;  };  class LLOctreeCullNoFarClip : public LLOctreeCull @@ -2024,14 +1675,14 @@ public:  	LLOctreeCullNoFarClip(LLCamera* camera)   		: LLOctreeCull(camera) { } -	virtual S32 frustumCheck(const LLSpatialGroup* group) +	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)  	{ -		return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +		return AABBInFrustumNoFarClipGroupBounds(group);  	} -	virtual S32 frustumCheckObjects(const LLSpatialGroup* group) +	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)  	{ -		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +		S32 res = AABBInFrustumNoFarClipObjectBounds(group);  		return res;  	}  }; @@ -2042,14 +1693,14 @@ public:  	LLOctreeCullShadow(LLCamera* camera)  		: LLOctreeCull(camera) { } -	virtual S32 frustumCheck(const LLSpatialGroup* group) +	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)  	{ -		return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); +		return AABBInFrustumGroupBounds(group);  	} -	virtual S32 frustumCheckObjects(const LLSpatialGroup* group) +	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)  	{ -		return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); +		return AABBInFrustumObjectBounds(group);  	}  }; @@ -2059,9 +1710,11 @@ public:  	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)  		: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { } -	virtual bool earlyFail(LLSpatialGroup* group) +	virtual bool earlyFail(LLviewerOctreeGroup* base_group)  	{ -		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node +		LLSpatialGroup* group = (LLSpatialGroup*)base_group; + +		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node  			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled  			group->isOcclusionState(LLSpatialGroup::OCCLUDED))  		{ @@ -2071,7 +1724,7 @@ public:  		return false;  	} -	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	virtual void traverse(const OctreeNode* n)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -2080,10 +1733,10 @@ public:  			return;  		} -		if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) || +		if ((mRes && group->hasState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||  			mRes == 2)  		{	//don't need to do frustum check -			LLSpatialGroup::OctreeTraveler::traverse(n); +			OctreeTraveler::traverse(n);  		}  		else  		{   @@ -2091,31 +1744,35 @@ public:  			if (mRes)  			{ //at least partially in, run on down -				LLSpatialGroup::OctreeTraveler::traverse(n); +				OctreeTraveler::traverse(n);  			}  			mRes = 0;  		}  	} -	virtual void processGroup(LLSpatialGroup* group) +	virtual void processGroup(LLviewerOctreeGroup* base_group)  	{ -		llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->isEmpty()) +		LLSpatialGroup* group = (LLSpatialGroup*)base_group; +		 +		llassert(!group->hasState(LLSpatialGroup::DIRTY) && !group->isEmpty())  		if (mRes < 2)  		{ -			if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0) +			if (AABBInFrustumObjectBounds(group) > 0)  			{  				mEmpty = FALSE; -				update_min_max(mMin, mMax, group->mObjectExtents[0]); -				update_min_max(mMin, mMax, group->mObjectExtents[1]); +				const LLVector4a* exts = group->getObjectExtents(); +				update_min_max(mMin, mMax, exts[0]); +				update_min_max(mMin, mMax, exts[1]);  			}  		}  		else  		{  			mEmpty = FALSE; -			update_min_max(mMin, mMax, group->mExtents[0]); -			update_min_max(mMin, mMax, group->mExtents[1]); +			const LLVector4a* exts = group->getExtents(); +			update_min_max(mMin, mMax, exts[0]); +			update_min_max(mMin, mMax, exts[1]);  		}  	} @@ -2130,10 +1787,12 @@ public:  	LLOctreeCullDetectVisible(LLCamera* camera)  		: LLOctreeCullShadow(camera), mResult(FALSE) { } -	virtual bool earlyFail(LLSpatialGroup* group) +	virtual bool earlyFail(LLviewerOctreeGroup* base_group)  	{ +		LLSpatialGroup* group = (LLSpatialGroup*)base_group; +  		if (mResult || //already found a node, don't check any more -			(group->mOctreeNode->getParent() &&	//never occlusion cull the root node +			(group->getOctreeNode()->getParent() &&	//never occlusion cull the root node  			 LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled  			 group->isOcclusionState(LLSpatialGroup::OCCLUDED)))  		{ @@ -2143,9 +1802,9 @@ public:  		return false;  	} -	virtual void processGroup(LLSpatialGroup* group) +	virtual void processGroup(LLviewerOctreeGroup* base_group)  	{ -		if (group->isVisible()) +		if (base_group->isVisible())  		{  			mResult = TRUE;  		} @@ -2160,17 +1819,21 @@ public:  	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)  		: LLOctreeCull(camera), mResults(results) { } -	virtual bool earlyFail(LLSpatialGroup* group) { return false; } -	virtual void preprocess(LLSpatialGroup* group) { } +	virtual bool earlyFail(LLviewerOctreeGroup* group) { return false; } +	virtual void preprocess(LLviewerOctreeGroup* group) { } -	virtual void processGroup(LLSpatialGroup* group) +	virtual void processGroup(LLviewerOctreeGroup* base_group)  	{ -		LLSpatialGroup::OctreeNode* branch = group->mOctreeNode; +		LLSpatialGroup* group = (LLSpatialGroup*)base_group; +		OctreeNode* branch = group->getOctreeNode(); -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) +		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)  		{ -			LLDrawable* drawable = *i; -			 +			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +			if(!drawable) +			{ +				continue; +			}  			if (!drawable->isDead())  			{  				if (drawable->isSpatialBridge()) @@ -2283,17 +1946,21 @@ void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)  	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));  } -class LLOctreeDirty : public LLOctreeTraveler<LLDrawable> +class LLOctreeDirty : public OctreeTraveler  {  public: -	virtual void visit(const LLOctreeNode<LLDrawable>* state) +	virtual void visit(const OctreeNode* state)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);  		group->destroyGL();  		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  		{ -			LLDrawable* drawable = *i; +			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +			if(!drawable) +			{ +				continue; +			}  			if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)  			{  				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); @@ -2352,6 +2019,8 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)  S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)  { +	llassert(results != NULL && for_select); +  #if LL_OCTREE_PARANOIA_CHECK  	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();  #endif @@ -2365,13 +2034,28 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result  	((LLSpatialGroup*)mOctree->getListener(0))->validate();  #endif +	LLOctreeSelect selecter(&camera, results); +	selecter.traverse(mOctree); -	if (for_select) +	return 0; +} + +S32 LLSpatialPartition::cull(LLCamera &camera) +{ +#if LL_OCTREE_PARANOIA_CHECK +	((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); +#endif  	{ -		LLOctreeSelect selecter(&camera, results); -		selecter.traverse(mOctree); +		LLFastTimer ftm(FTM_CULL_REBOUND);		 +		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); +		group->rebound();  	} -	else if (LLPipeline::sShadowRender) + +#if LL_OCTREE_PARANOIA_CHECK +	((LLSpatialGroup*)mOctree->getListener(0))->validate(); +#endif + +	if (LLPipeline::sShadowRender)  	{  		LLFastTimer ftm(FTM_FRUSTUM_CULL);  		LLOctreeCullShadow culler(&camera); @@ -2404,9 +2088,10 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)  	LLVector4a fudge;  	fudge.splat(vel); -	const LLVector4a& c = group->mBounds[0]; +	const LLVector4a* bounds = group->getBounds(); +	const LLVector4a& c = bounds[0];  	LLVector4a r; -	r.setAdd(group->mBounds[1], fudge); +	r.setAdd(bounds[1], fudge);  	/*if (r.magVecSquared() > 1024.0*1024.0)  	{ @@ -2531,7 +2216,8 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask)  	}  	else  	{ -		drawBox(group->mBounds[0], group->mBounds[1]); +		const LLVector4a* bounds = group->getBounds(); +		drawBox(bounds[0], bounds[1]);  	}  } @@ -2595,13 +2281,19 @@ void renderOctree(LLSpatialGroup* group)  			gGL.diffuseColor4f(1,0,0,group->mBuilt);  			gGL.flush();  			glLineWidth(5.f); -			drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); + +			const LLVector4a* bounds = group->getObjectBounds(); +			drawBoxOutline(bounds[0], bounds[1]);  			gGL.flush();  			glLineWidth(1.f);  			gGL.flush();  			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  			{ -				LLDrawable* drawable = *i; +				LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +				if(!drawable) +				{ +					continue; +				}  				if (!group->mSpatialPartition->isBridge())  				{  					gGL.pushMatrix(); @@ -2659,9 +2351,10 @@ void renderOctree(LLSpatialGroup* group)  	gGL.diffuseColor4fv(col.mV);  	LLVector4a fudge;  	fudge.splat(0.001f); -	LLVector4a size = group->mObjectBounds[1]; -	size.mul(1.01f); -	size.add(fudge); + +	//LLVector4a size = group->mObjectBounds[1]; +	//size.mul(1.01f); +	//size.add(fudge);  	//{  	//	LLGLDepthTest depth(GL_TRUE, GL_FALSE); @@ -2677,7 +2370,9 @@ void renderOctree(LLSpatialGroup* group)  		//drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);  		gGL.diffuseColor4f(0,1,1,1); -		drawBoxOutline(group->mBounds[0],group->mBounds[1]); + +		const LLVector4a* bounds = group->getBounds(); +		drawBoxOutline(bounds[0], bounds[1]);  		//draw bounding box for draw info  		/*if (group->mSpatialPartition->mRenderByGroup) @@ -3444,9 +3139,13 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)  void renderPhysicsShapes(LLSpatialGroup* group)  { -	for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) +	for (OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  	{ -		LLDrawable* drawable = *i; +		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +		if(!drawable) +		{ +			continue; +		}  		LLVOVolume* volume = drawable->getVOVolume();  		if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )  		{ @@ -4003,17 +3702,18 @@ void renderAgentTarget(LLVOAvatar* avatar)  	}  } -class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> +class LLOctreeRenderNonOccluded : public OctreeTraveler  {  public:  	LLCamera* mCamera;  	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {} -	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	virtual void traverse(const OctreeNode* node)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); -		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) +		const LLVector4a* bounds = group->getBounds(); +		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))  		{  			node->accept(this);  			stop_glerror(); @@ -4053,17 +3753,17 @@ public:  		}  	} -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) +	virtual void visit(const OctreeNode* branch)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - -		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) +		const LLVector4a* bounds = group->getBounds(); +		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))  		{  			return;  		} -		LLVector4a nodeCenter = group->mBounds[0]; -		LLVector4a octCenter = group->mOctreeNode->getCenter(); +		LLVector4a nodeCenter = bounds[0]; +		LLVector4a octCenter = group->getOctreeNode()->getCenter();  		group->rebuildGeom();  		group->rebuildMesh(); @@ -4073,15 +3773,20 @@ public:  			if (!group->isEmpty())  			{  				gGL.diffuseColor3f(0,0,1); -				drawBoxOutline(group->mObjectBounds[0], -								group->mObjectBounds[1]); + +				const LLVector4a* obj_bounds = group->getObjectBounds(); +				drawBoxOutline(obj_bounds[0], obj_bounds[1]);  			}  		} -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) +		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)  		{ -			LLDrawable* drawable = *i; -					 +			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +			if(!drawable) +			{ +				continue; +			} +  			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))  			{  				renderBoundingBox(drawable);			 @@ -4203,17 +3908,18 @@ public:  }; -class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable> +class LLOctreeRenderPhysicsShapes : public OctreeTraveler  {  public:  	LLCamera* mCamera;  	LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {} -	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	virtual void traverse(const OctreeNode* node)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); -		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) +		const LLVector4a* bounds = group->getBounds(); +		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))  		{  			node->accept(this);  			stop_glerror(); @@ -4231,23 +3937,24 @@ public:  		}  	} -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) +	virtual void visit(const OctreeNode* branch)  	{  	}  }; -class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable> +class LLOctreePushBBoxVerts : public OctreeTraveler  {  public:  	LLCamera* mCamera;  	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {} -	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	virtual void traverse(const OctreeNode* node)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); -		if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1])) +		const LLVector4a* bounds = group->getBounds(); +		if (!mCamera || mCamera->AABBInFrustum(bounds[0], bounds[1]))  		{  			node->accept(this); @@ -4258,19 +3965,23 @@ public:  		}  	} -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) +	virtual void visit(const OctreeNode* branch)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); -		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) +		const LLVector4a* bounds = group->getBounds(); +		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))  		{  			return;  		} -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) +		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)  		{ -			LLDrawable* drawable = *i; -						 +			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +			if(!drawable) +			{ +				continue; +			}  			renderBoundingBox(drawable, FALSE);			  		}  	} @@ -4282,7 +3993,7 @@ void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)  	pusher.traverse(mOctree);  } -class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable> +class LLOctreeStateCheck : public OctreeTraveler  {  public:  	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS]; @@ -4295,7 +4006,7 @@ public:  		}  	} -	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	virtual void traverse(const OctreeNode* node)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); @@ -4322,7 +4033,7 @@ public:  	} -	virtual void visit(const LLOctreeNode<LLDrawable>* state) +	virtual void visit(const OctreeNode* state)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); @@ -4334,7 +4045,7 @@ public:  			}  		} -		if (group->isState(LLSpatialGroup::DIRTY)) +		if (group->hasState(LLSpatialGroup::DIRTY))  		{  			assert_parent_state(group, LLSpatialGroup::DIRTY);  		} @@ -4345,7 +4056,7 @@ public:  		LLSpatialGroup* parent = group->getParent();  		while (parent)  		{ -			if (!parent->isState(state)) +			if (!parent->hasState(state))  			{  				llerrs << "Spatial group failed parent state check." << llendl;  			} @@ -4460,7 +4171,7 @@ BOOL LLSpatialPartition::isVisible(const LLVector3& v)  	return TRUE;  } -class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler +class LLOctreeIntersect : public OctreeTraveler  {  public:  	LLVector3 mStart; @@ -4487,21 +4198,21 @@ public:  	{  	} -	virtual void visit(const LLSpatialGroup::OctreeNode* branch)  +	virtual void visit(const OctreeNode* branch)   	{	 -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) +		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)  		{  			check(*i);  		}  	} -	virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node) +	virtual LLDrawable* check(const OctreeNode* node)  	{  		node->accept(this);  		for (U32 i = 0; i < node->getChildCount(); i++)  		{ -			const LLSpatialGroup::OctreeNode* child = node->getChild(i); +			const OctreeNode* child = node->getChild(i);  			LLVector3 res;  			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0); @@ -4509,8 +4220,9 @@ public:  			LLVector4a size;  			LLVector4a center; -			size = group->mBounds[1]; -			center = group->mBounds[0]; +			const LLVector4a* bounds = group->getBounds(); +			size = bounds[1]; +			center = bounds[0];  			LLVector3 local_start = mStart;  			LLVector3 local_end   = mEnd; @@ -4537,8 +4249,9 @@ public:  		return mHit;  	} -	virtual bool check(LLDrawable* drawable) +	virtual bool check(LLViewerOctreeEntry* entry)  	{	 +		LLDrawable* drawable = (LLDrawable*)entry->getDrawable();  		LLVector3 local_start = mStart;  		LLVector3 local_end = mEnd; @@ -4932,5 +4645,3 @@ void LLCullResult::assertDrawMapsEmpty()  	}  } - - diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index b1706d9d35..a2e2bf45d6 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -45,22 +45,21 @@  #define SG_STATE_INHERIT_MASK (OCCLUDED)  #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY) +class LLViewerOctreePartition;  class LLSpatialPartition;  class LLSpatialBridge;  class LLSpatialGroup;  class LLTextureAtlas;  class LLTextureAtlasSlot; +class LLViewerRegion; -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad); -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared); - -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad); -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);  void pushVerts(LLFace* face, U32 mask);  // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera  U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);  U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center); +GLuint get_new_occlusion_query_object_name(); +void release_occlusion_query_object_name(GLuint name);  class LLDrawInfo : public LLRefCount   { @@ -192,13 +191,13 @@ public:  };  LL_ALIGN_PREFIX(16) -class LLSpatialGroup : public LLOctreeListener<LLDrawable> +class LLSpatialGroup : public LLviewerOctreeGroup  {  	friend class LLSpatialPartition;  	friend class LLOctreeStateCheck;  public: -	LLSpatialGroup(const LLSpatialGroup& rhs) +	LLSpatialGroup(const LLSpatialGroup& rhs) : LLviewerOctreeGroup(rhs)  	{  		*this = rhs;  	} @@ -229,16 +228,7 @@ public:  	typedef std::map<U32, drawmap_elem_t > draw_map_t;	  	typedef std::vector<LLPointer<LLVertexBuffer> > buffer_list_t;  	typedef std::map<LLFace*, buffer_list_t> buffer_texture_map_t; -	typedef std::map<U32, buffer_texture_map_t> buffer_map_t; - -	typedef LLOctreeListener<LLDrawable>	BaseType; -	typedef LLOctreeListener<LLDrawable>	OctreeListener; -	typedef LLTreeNode<LLDrawable>			TreeNode; -	typedef LLOctreeNode<LLDrawable>		OctreeNode; -	typedef LLOctreeRoot<LLDrawable>		OctreeRoot; -	typedef LLOctreeTraveler<LLDrawable>	OctreeTraveler; -	typedef LLOctreeNode<LLDrawable>::element_iter element_iter; -	typedef LLOctreeNode<LLDrawable>::element_list element_list; +	typedef std::map<U32, buffer_texture_map_t> buffer_map_t;	  	struct CompareDistanceGreater  	{ @@ -275,18 +265,15 @@ public:  	typedef enum  	{ -		DEAD					= 0x00000001, -		DIRTY					= 0x00000002, -		OBJECT_DIRTY			= 0x00000004, -		GEOM_DIRTY				= 0x00000008, -		ALPHA_DIRTY				= 0x00000010, -		SKIP_FRUSTUM_CHECK		= 0x00000020, -		IN_IMAGE_QUEUE			= 0x00000040, -		IMAGE_DIRTY				= 0x00000080, -		MESH_DIRTY				= 0x00000100, -		NEW_DRAWINFO			= 0x00000200, -		IN_BUILD_Q1				= 0x00000400, -		IN_BUILD_Q2				= 0x00000800, +		DEAD					= LLviewerOctreeGroup::INVALID_STATE, +		GEOM_DIRTY				= (DEAD << 1), +		ALPHA_DIRTY				= (GEOM_DIRTY << 1), +		IN_IMAGE_QUEUE			= (ALPHA_DIRTY << 1), +		IMAGE_DIRTY				= (IN_IMAGE_QUEUE << 1), +		MESH_DIRTY				= (IMAGE_DIRTY << 1), +		NEW_DRAWINFO			= (MESH_DIRTY << 1), +		IN_BUILD_Q1				= (NEW_DRAWINFO << 1), +		IN_BUILD_Q2				= (IN_BUILD_Q1 << 1),  		STATE_MASK				= 0x0000FFFF,  	} eSpatialState; @@ -301,12 +288,8 @@ public:  	LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part);  	BOOL isHUDGroup() ; -	BOOL isDead()							{ return isState(DEAD); } -	BOOL isState(U32 state) const;	 +	BOOL isDead()							{ return hasState(DEAD); }  	BOOL isOcclusionState(U32 state) const	{ return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; } -	U32 getState()							{ return mState; } -	void setState(U32 state);	 -	void clearState(U32 state);	  	void clearDrawMap();  	void validate(); @@ -315,23 +298,18 @@ public:  	void setState(U32 state, S32 mode);  	void clearState(U32 state, S32 mode); +	void clearState(U32 state)     {mState &= ~state;}	  	void setOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);  	void clearOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);  	LLSpatialGroup* getParent(); - -	BOOL addObject(LLDrawable *drawablep, BOOL add_all = FALSE, BOOL from_octree = FALSE); +	BOOL addObject(LLDrawable *drawablep);  	BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);  	BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group -	BOOL isVisible() const;  	BOOL isRecentlyVisible() const; -	void setVisible();  	void shift(const LLVector4a &offset); -	BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax); -	void unbound(); -	BOOL rebound();  	void checkOcclusion(); //read back last occlusion query (if any)  	void doOcclusion(LLCamera* camera); //issue occlusion query  	void destroyGL(bool keep_occlusion = false); @@ -343,28 +321,18 @@ public:  	void rebuildGeom();  	void rebuildMesh(); +	void setState(U32 state)       {mState |= state;}  	void dirtyGeom() { setState(GEOM_DIRTY); } -	void dirtyMesh() { setState(MESH_DIRTY); } - -	//octree wrappers to make code more readable -	element_list& getData() { return mOctreeNode->getData(); } -	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); } -	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); } -	bool hasElement(LLDrawable* drawablep) { return std::find(mOctreeNode->getDataBegin(), mOctreeNode->getDataEnd(), drawablep) != mOctreeNode->getDataEnd(); } - -	U32 getElementCount() const { return mOctreeNode->getElementCount(); } -	bool isEmpty() const { return mOctreeNode->isEmpty(); } +	void dirtyMesh() { setState(MESH_DIRTY); }		  	void drawObjectBox(LLColor4 col);  	 //LISTENER FUNCTIONS -	virtual void handleInsertion(const TreeNode* node, LLDrawable* face); -	virtual void handleRemoval(const TreeNode* node, LLDrawable* face); +	virtual void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* face); +	virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* face);  	virtual void handleDestruction(const TreeNode* node); -	virtual void handleStateChange(const TreeNode* node);  	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child); -	virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child); - +	  //-------------------  //for atlas use  //------------------- @@ -386,21 +354,6 @@ public:  public: -	typedef enum -	{ -		BOUNDS = 0, -		EXTENTS = 2, -		OBJECT_BOUNDS = 4, -		OBJECT_EXTENTS = 6, -		VIEW_ANGLE = 8, -		LAST_VIEW_ANGLE = 9, -		V4_COUNT = 10 -	} eV4Index; - -	LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects) -	LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children -	LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node -	LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node  	LL_ALIGN_16(LLVector4a mViewAngle);  	LL_ALIGN_16(LLVector4a mLastUpdateViewAngle); @@ -421,7 +374,6 @@ private:  protected:  	virtual ~LLSpatialGroup(); -	U32 mState;  	U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS];  	U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS]; @@ -436,7 +388,6 @@ public:  	F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node  	F32 mBuilt; -	OctreeNode* mOctreeNode;  	LLSpatialPartition* mSpatialPartition;  	LLPointer<LLVertexBuffer> mVertexBuffer; @@ -444,8 +395,7 @@ public:  	U32 mBufferUsage;  	draw_map_t mDrawMap; -	 -	S32 mVisible[LLViewerCamera::NUM_CAMERAS]; +		  	F32 mDistance;  	F32 mDepth;  	F32 mLastUpdateDistance; @@ -468,10 +418,10 @@ public:  	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);  }; -class LLSpatialPartition: public LLGeometryManager +class LLSpatialPartition: public LLViewerOctreePartition, public LLGeometryManager  {  public: -	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage); +	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage, LLViewerRegion* regionp);  	virtual ~LLSpatialPartition();  	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE); @@ -498,7 +448,8 @@ public:  	virtual void rebuildMesh(LLSpatialGroup* group);  	BOOL visibleObjectsInFrustum(LLCamera& camera); -	S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results = NULL, BOOL for_select = FALSE); // Cull on arbitrary frustum +	/*virtual*/ S32 cull(LLCamera &camera); // Cull on arbitrary frustum +	S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select); // Cull on arbitrary frustum  	BOOL isVisible(const LLVector3& v);  	bool isHUDPartition() ; @@ -513,23 +464,21 @@ public:  	void resetVertexBuffers();  	BOOL isOcclusionEnabled();  	BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax); - +	  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; +	U32   mDrawableType;  	const BOOL mRenderByGroup;  	U32 mLODSeed;  	U32 mLODPeriod;	//number of frames between LOD updates for a given spatial group (staggered by mLODSeed)  	U32 mVertexDataMask;  	F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25); -	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering -	U32 mDrawableType; -	U32 mPartitionType; +	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering	  };  // class for creating bridges between spatial partitions @@ -541,7 +490,7 @@ protected:  public:  	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_vector_t; -	LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask); +	LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask, LLViewerRegion* regionp);  	void destroyTree(); @@ -564,7 +513,7 @@ public:  }; -class LLCullResult  +class LLCullResult  {  public:  	LLCullResult(); @@ -663,7 +612,7 @@ private:  class LLWaterPartition : public LLSpatialPartition  {  public: -	LLWaterPartition(); +	LLWaterPartition(LLViewerRegion* regionp);  	virtual void getGeometry(LLSpatialGroup* group) {  }  	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }  }; @@ -672,14 +621,14 @@ public:  class LLVoidWaterPartition : public LLWaterPartition  {  public: -	LLVoidWaterPartition(); +	LLVoidWaterPartition(LLViewerRegion* regionp);  };  //spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp)  class LLTerrainPartition : public LLSpatialPartition  {  public: -	LLTerrainPartition(); +	LLTerrainPartition(LLViewerRegion* regionp);  	virtual void getGeometry(LLSpatialGroup* group);  	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);  }; @@ -688,7 +637,7 @@ public:  class LLTreePartition : public LLSpatialPartition  {  public: -	LLTreePartition(); +	LLTreePartition(LLViewerRegion* regionp);  	virtual void getGeometry(LLSpatialGroup* group) { }  	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } @@ -698,7 +647,7 @@ public:  class LLParticlePartition : public LLSpatialPartition  {  public: -	LLParticlePartition(); +	LLParticlePartition(LLViewerRegion* regionp);  	virtual void rebuildGeom(LLSpatialGroup* group);  	virtual void getGeometry(LLSpatialGroup* group);  	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); @@ -710,14 +659,14 @@ protected:  class LLHUDParticlePartition : public LLParticlePartition  {  public: -	LLHUDParticlePartition(); +	LLHUDParticlePartition(LLViewerRegion* regionp);  };  //spatial partition for grass (implemented in LLVOGrass.cpp)  class LLGrassPartition : public LLSpatialPartition  {  public: -	LLGrassPartition(); +	LLGrassPartition(LLViewerRegion* regionp);  	virtual void getGeometry(LLSpatialGroup* group);  	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count);  protected: @@ -747,7 +696,7 @@ class LLVolumeGeometryManager: public LLGeometryManager  class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryManager  {  public: -	LLVolumePartition(); +	LLVolumePartition(LLViewerRegion* regionp);  	virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); }  	virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); }  	virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); } @@ -758,7 +707,7 @@ public:  class LLVolumeBridge : public LLSpatialBridge, public LLVolumeGeometryManager  {  public: -	LLVolumeBridge(LLDrawable* drawable); +	LLVolumeBridge(LLDrawable* drawable, LLViewerRegion* regionp);  	virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); }  	virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); }  	virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); } @@ -768,7 +717,7 @@ public:  class LLHUDBridge : public LLVolumeBridge  {  public: -	LLHUDBridge(LLDrawable* drawablep); +	LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp);  	virtual void shiftPos(const LLVector4a& vec);  	virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);  }; @@ -777,7 +726,7 @@ public:  class LLBridgePartition : public LLSpatialPartition  {  public: -	LLBridgePartition(); +	LLBridgePartition(LLViewerRegion* regionp);  	virtual void getGeometry(LLSpatialGroup* group) { }  	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) {  }  }; @@ -785,7 +734,7 @@ public:  class LLHUDPartition : public LLBridgePartition  {  public: -	LLHUDPartition(); +	LLHUDPartition(LLViewerRegion* regionp);  	virtual void shift(const LLVector4a &offset);  }; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index d62101d159..fba636e8ef 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2358,6 +2358,10 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image  	mHttpMetricsHeaders = new LLCore::HttpHeaders;  	mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml");  	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault(); + +	//reset the texture timer. +	gTextureTimer.reset(); +	gTextureTimer.pause();  }  LLTextureFetch::~LLTextureFetch() diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 1d54e50bb9..7a6351c880 100755 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -49,6 +49,8 @@  #include "llviewertexturelist.h"  #include "llvovolume.h"  #include "llviewerstats.h" +#include "llworld.h" +#include "llviewerobjectlist.h"  // For avatar texture view  #include "llvoavatarself.h" @@ -517,6 +519,9 @@ void LLGLTexMemBar::draw()  	LLUnit<LLUnits::Bytes, F32> total_texture_downloaded = gTotalTextureData;  	LLUnit<LLUnits::Bytes, F32> total_object_downloaded = gTotalObjectData;  	U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ; +	U32 total_active_cached_objects = LLWorld::getInstance()->getNumOfActiveCachedObjects(); +	U32 total_objects = gObjectList.getNumObjects(); +  	//----------------------------------------------------------------------------  	LLGLSUIDefault gls_ui;  	LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); @@ -549,9 +554,11 @@ void LLGLTexMemBar::draw()  	U32 cache_read(0U), cache_write(0U), res_wait(0U);  	LLAppViewer::getTextureFetch()->getStateStats(&cache_read, &cache_write, &res_wait); -	text = llformat("Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d Cread: %u Cwrite: %u Rwait: %u", +	text = llformat("Net Tot Tex: %.1f MB Tot Obj: %.1f MB #Objs/#Cached: %d/%d Tot Htp: %d Cread: %u Cwrite: %u Rwait: %u",  					total_texture_downloaded.value(),  					total_object_downloaded.value(), +					total_objects,  +					total_active_cached_objects,  					total_http_requests,  					cache_read,  					cache_write, diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 41a08398bb..fe83f80caa 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -77,6 +77,7 @@  #include "llwlparammanager.h"  #include "llwaterparammanager.h"  #include "llpostprocess.h" +#include "llscenemonitor.h"  extern LLPointer<LLViewerTexture> gStartTexture;  extern bool gShiftFrame; @@ -991,6 +992,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  		LLPipeline::sUnderWaterRender = FALSE; +		{ +			//capture the frame buffer. +			LLSceneMonitor::getInstance()->capture(); +		} +  		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");  		if (!for_snapshot)  		{ @@ -1224,6 +1230,15 @@ void render_ui(F32 zoom_factor, int subfield)  		glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));  	} +	if(LLSceneMonitor::getInstance()->needsUpdate()) +	{ +		gGL.pushMatrix(); +		gViewerWindow->setup2DRender(); +		LLSceneMonitor::getInstance()->compare(); +		gViewerWindow->setup3DRender(); +		gGL.popMatrix(); +	} +  	{  		BOOL to_texture = gPipeline.canUseVertexShaders() &&  							LLPipeline::sRenderGlow; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 3ca410cf73..9a0cb432be 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -122,6 +122,7 @@  #include "llwindow.h"  #include "llpathfindingmanager.h"  #include "boost/unordered_map.hpp" +#include "llscenemonitor.h"  using namespace LLVOAvatarDefines; @@ -529,7 +530,10 @@ class LLAdvancedToggleConsole : public view_listener_t  		{  			toggle_visibility( (void*)gSceneView);  		} - +		else if ("scene monitor" == console_type) +		{ +			toggle_visibility( (void*)gSceneMonitorView); +		}  #if MEM_TRACK_MEM  		else if ("memory view" == console_type)  		{ @@ -557,9 +561,9 @@ class LLAdvancedCheckConsole : public view_listener_t  		{  			new_value = LLFloaterReg::instanceVisible("fast_timers");  		} -		else if ("scene view" == console_type) +		else if ("scene monitor" == console_type)  		{ -			new_value = get_visibility( (void*) gSceneView); +			new_value = get_visibility( (void*) gSceneMonitorView);  		}  #if MEM_TRACK_MEM  		else if ("memory view" == console_type) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6da93f0653..7a2025ed5b 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4483,30 +4483,42 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_  static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Kill Objects"); +const U32 KILLOBJECT_DELETE_OPCODE = 0; +  void process_kill_object(LLMessageSystem *mesgsys, void **user_data)  {  	LLFastTimer t(FTM_PROCESS_OBJECTS); -	LLUUID		id; -	U32			local_id; -	S32			i; -	S32			num_objects; +	LLUUID id; -	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); +	U32 ip = mesgsys->getSenderIP(); +	U32 port = mesgsys->getSenderPort(); +	LLViewerRegion* regionp = NULL; +	{ +		LLHost host(ip, port); +		regionp = LLWorld::getInstance()->getRegion(host); +	} -	for (i = 0; i < num_objects; i++) +	bool delete_object = false; +	S32	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); +	for (S32 i = 0; i < num_objects; ++i)  	{ +		U32	local_id;  		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); +		if (local_id == KILLOBJECT_DELETE_OPCODE) +		{ +			// This local_id is invalid, but was sent by the server to flag +			// all subsequent local_id's as objects that were actually deleted +			// rather than unsubscribed from interestlist. +			delete_object = true; +			continue; +		} -		LLViewerObjectList::getUUIDFromLocal(id, -											local_id, -											gMessageSystem->getSenderIP(), -											gMessageSystem->getSenderPort()); +		LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port);   		if (id == LLUUID::null)  		{  			LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; -			gObjectList.mNumUnknownKills++;  			continue;  		}  		else @@ -4514,34 +4526,35 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)  			LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL;  		} -		// ...don't kill the avatar -		if (!(id == gAgentID)) +		if (id == gAgentID)  		{ -			LLViewerObject *objectp = gObjectList.findObject(id); -			if (objectp) -			{ -				// Display green bubble on kill -				if ( gShowObjectUpdates ) -				{ -					LLColor4 color(0.f,1.f,0.f,1.f); -					gPipeline.addDebugBlip(objectp->getPositionAgent(), color); -				} +			// never kill our avatar +			continue; +		} -				// Do the kill -				gObjectList.killObject(objectp); -			} -			else +		LLViewerObject *objectp = gObjectList.findObject(id); +		if (objectp) +		{ +			// Display green bubble on kill +			if ( gShowObjectUpdates )  			{ -				LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL; -				gObjectList.mNumUnknownKills++; +				LLColor4 color(0.f,1.f,0.f,1.f); +				gPipeline.addDebugBlip(objectp->getPositionAgent(), color);  			} + +			// Do the kill +			gObjectList.killObject(objectp); +		} + +		if(delete_object) +		{ +			regionp->killCacheEntry(local_id);  		}  		// We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab,          // which is using the object, release the mouse capture correctly when the object dies.          // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical().  		LLSelectMgr::getInstance()->removeObjectFromSelections(id); -  	}  } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 61dc66065c..f5f5bdffbd 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -100,6 +100,7 @@  #include "lltrans.h"  #include "llsdutil.h"  #include "llmediaentry.h" +#include "llvocache.h"  //#define DEBUG_UPDATE_TYPE @@ -326,6 +327,22 @@ void LLViewerObject::deleteTEImages()  	mTEImages = NULL;  } +//if enabled, add this object to vo cache tree when removed from rendering. +void LLViewerObject::EnableToCacheTree(bool enabled) +{ +	if(mDrawable.notNull() && mDrawable->getEntry() && mDrawable->getEntry()->hasVOCacheEntry()) +	{ +		if(enabled) +		{ +			((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry())->addState(LLVOCacheEntry::ADD_TO_CACHE_TREE); +		} +		else +		{ +			((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry())->clearState(LLVOCacheEntry::ADD_TO_CACHE_TREE); +		} +	} +} +  void LLViewerObject::markDead()  {  	if (!mDead) @@ -348,7 +365,7 @@ void LLViewerObject::markDead()  			childp = mChildList.back();  			if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)  			{ -				//llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl; +				//llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl;				  				childp->setParent(NULL); // LLViewerObject::markDead 1  				childp->markDead();  			} @@ -889,10 +906,11 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  	}  	// Coordinates of objects on simulators are region-local. -	U64 region_handle; -	mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); +	U64 region_handle = 0;	 +	if(mesgsys != NULL)  	{ +		mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);  		LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);  		if(regionp != mRegionp && regionp && mRegionp)//region cross  		{ @@ -918,11 +936,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  		return retval;  	} -	U16 time_dilation16; -	mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); -	F32 time_dilation = ((F32) time_dilation16) / 65535.f; -	mTimeDilation = time_dilation; -	mRegionp->setTimeDilation(time_dilation); +	if(mesgsys != NULL) +	{ +		U16 time_dilation16; +		mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); +		F32 time_dilation = ((F32) time_dilation16) / 65535.f; +		mTimeDilation = time_dilation; +		mRegionp->setTimeDilation(time_dilation); +	}  	// this will be used to determine if we've really changed position  	// Use getPosition, not getPositionRegion, since this is what we're comparing directly against. @@ -1695,13 +1716,16 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  				// Preload these five flags for every object.  				// Finer shades require the object to be selected, and the selection manager  				// stores the extended permission info. -				U32 flags; -				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); -				// keep local flags and overwrite remote-controlled flags -				mFlags = (mFlags & FLAGS_LOCAL) | flags; +				if(mesgsys != NULL) +				{ +					U32 flags; +					mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); +					// keep local flags and overwrite remote-controlled flags +					mFlags = (mFlags & FLAGS_LOCAL) | flags;  					// ...new objects that should come in selected need to be added to the selected list -				mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); +					mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); +				}  			}  			break; @@ -1729,10 +1753,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  			{  				// No parent now, new parent in message -> attach to that parent if possible  				LLUUID parent_uuid; -				LLViewerObjectList::getUUIDFromLocal(parent_uuid, + +				if(mesgsys != NULL) +				{ +					LLViewerObjectList::getUUIDFromLocal(parent_uuid,  														parent_id,  														mesgsys->getSenderIP(),  														mesgsys->getSenderPort()); +				} +				else +				{ +					LLViewerObjectList::getUUIDFromLocal(parent_uuid, +														parent_id, +														mRegionp->getHost().getAddress(), +														mRegionp->getHost().getPort()); +				}  				LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); @@ -1808,9 +1843,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  					//  					//parent_id -					U32 ip = mesgsys->getSenderIP(); -					U32 port = mesgsys->getSenderPort(); +					U32 ip, port;  +					if(mesgsys != NULL) +					{ +						ip = mesgsys->getSenderIP(); +						port = mesgsys->getSenderPort(); +					} +					else +					{ +						ip = mRegionp->getHost().getAddress(); +						port = mRegionp->getHost().getPort(); +					}  					gObjectList.orphanize(this, parent_id, ip, port);  					// Hide particles, icon and HUD @@ -1848,10 +1892,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  				else  				{  					LLUUID parent_uuid; -					LLViewerObjectList::getUUIDFromLocal(parent_uuid, + +					if(mesgsys != NULL) +					{ +						LLViewerObjectList::getUUIDFromLocal(parent_uuid,  														parent_id,  														gMessageSystem->getSenderIP(),  														gMessageSystem->getSenderPort()); +					} +					else +					{ +						LLViewerObjectList::getUUIDFromLocal(parent_uuid, +														parent_id, +														mRegionp->getHost().getAddress(), +														mRegionp->getHost().getPort()); +					}  					sent_parentp = gObjectList.findObject(parent_uuid);  					if (isAvatar()) @@ -1872,8 +1927,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  						//  						// Switching parents, but we don't know the new parent.  						// -						U32 ip = mesgsys->getSenderIP(); -						U32 port = mesgsys->getSenderPort(); +						U32 ip, port;  +					 +						if(mesgsys != NULL) +						{ +							ip = mesgsys->getSenderIP(); +							port = mesgsys->getSenderPort(); +						} +						else +						{ +							ip = mRegionp->getHost().getAddress(); +							port = mRegionp->getHost().getPort(); +						}  						// We're an orphan, flag things appropriately.  						gObjectList.orphanize(this, parent_id, ip, port); @@ -1957,7 +2022,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  	new_rot.normQuat(); -	if (sPingInterpolate) +	if (sPingInterpolate && mesgsys != NULL)  	{   		LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());  		if (cdp) @@ -1980,16 +2045,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  	// If we're going to skip this message, why are we   	// doing all the parenting, etc above? -	U32 packet_id = mesgsys->getCurrentRecvPacketID();  -	if (packet_id < mLatestRecvPacketID &&  -		mLatestRecvPacketID - packet_id < 65536) +	if(mesgsys != NULL)  	{ -		//skip application of this message, it's old -		return retval; +		U32 packet_id = mesgsys->getCurrentRecvPacketID();  +		if (packet_id < mLatestRecvPacketID &&  +			mLatestRecvPacketID - packet_id < 65536) +		{ +			//skip application of this message, it's old +			return retval; +		} +		mLatestRecvPacketID = packet_id;  	} -	mLatestRecvPacketID = packet_id; -  	// Set the change flags for scale  	if (new_scale != getScale())  	{ diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index bdff88f8ca..20254bfe02 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -136,6 +136,7 @@ public:  	BOOL isDead() const									{return mDead;}  	BOOL isOrphaned() const								{ return mOrphaned; }  	BOOL isParticleSource() const; +	void EnableToCacheTree(bool enabled);  	virtual LLVOAvatar* asAvatar(); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index fc3b7e7942..0335cd769b 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -76,6 +76,7 @@  #include "object_flags.h"  #include "llappviewer.h" +#include "llvocache.h"  extern F32 gMinObjectDistance;  extern BOOL gAnimateTextures; @@ -106,7 +107,6 @@ LLViewerObjectList::LLViewerObjectList()  	mNumNewObjects = 0;  	mWasPaused = FALSE;  	mNumDeadObjectUpdates = 0; -	mNumUnknownKills = 0;  	mNumUnknownUpdates = 0;  } @@ -228,9 +228,15 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,  										   U32 i,   										   const EObjectUpdateType update_type,   										   LLDataPacker* dpp,  -										   BOOL just_created) +										   bool just_created, +										   bool from_cache)  { -	LLMessageSystem* msg = gMessageSystem; +	LLMessageSystem* msg = NULL; +	 +	if(!from_cache) +	{ +		msg = gMessageSystem; +	}  	// ignore returned flags  	objectp->processUpdateMessage(msg, user_data, i, update_type, dpp); @@ -254,7 +260,18 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,  	// RN: this must be called after we have a drawable   	// (from gPipeline.addObject)  	// so that the drawable parent is set properly -	findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); +	if(msg != NULL) +	{ +		findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); +	} +	else +	{ +		LLViewerRegion* regionp = objectp->getRegion(); +		if(regionp != NULL) +		{ +			findOrphans(objectp, regionp->getHost().getAddress(), regionp->getHost().getPort()); +		} +	}  	// If we're just wandering around, don't create new objects selected.  	if (just_created  @@ -277,10 +294,88 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,  static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); +LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp) +{ +	LLDataPacker *cached_dpp = entry->getDP(); + +	if (!cached_dpp) +	{ +		return NULL; //nothing cached. +	} +	 +	LLViewerObject *objectp; +	U32			    local_id; +	LLPCode		    pcode = 0; +	LLUUID		    fullid; +	LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance(); + +	// Cache Hit. +	cached_dpp->reset(); +	cached_dpp->unpackUUID(fullid, "ID"); +	cached_dpp->unpackU32(local_id, "LocalID"); +	cached_dpp->unpackU8(pcode, "PCode"); + +	objectp = findObject(fullid); + +	if (objectp) +	{ +		if(!objectp->isDead() && (objectp->mLocalID != entry->getLocalID() || +			objectp->getRegion() != regionp)) +		{ +			removeFromLocalIDTable(objectp); +			setUUIDAndLocal(fullid, entry->getLocalID(), +							regionp->getHost().getAddress(), +							regionp->getHost().getPort()); +				 +			if (objectp->mLocalID != entry->getLocalID()) +			{	// Update local ID in object with the one sent from the region +				objectp->mLocalID = entry->getLocalID(); +			} +			 +			if (objectp->getRegion() != regionp) +			{	// Object changed region, so update it +				objectp->updateRegion(regionp); // for LLVOAvatar +			} +		} +		else +		{ +			return objectp; //already loaded. +		} +	} + +	bool justCreated = false; +	if (!objectp) +	{ +		objectp = createObjectFromCache(pcode, regionp, fullid, entry->getLocalID()); +		 +		if (!objectp) +		{ +			llinfos << "createObject failure for object: " << fullid << llendl; +			recorder.objectUpdateFailure(entry->getLocalID(), OUT_FULL_CACHED, 0); +			return NULL; +		} +		justCreated = true; +		mNumNewObjects++; +		sCacheHitRate.sample(100.f); +	} + +	if (objectp->isDead()) +	{ +		llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl; +	} +		 +	processUpdateCore(objectp, NULL, 0, OUT_FULL_CACHED, cached_dpp, justCreated, true); +		 +	recorder.log(0.2f); +	LLVOAvatar::cullAvatarsByPixelArea(); + +	return objectp; +} +  void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  											 void **user_data,  											 const EObjectUpdateType update_type, -											 bool cached, bool compressed) +											 bool compressed)  {  	LLFastTimer t(FTM_PROCESS_OBJECTS);	 @@ -299,7 +394,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);  	// I don't think this case is ever hit.  TODO* Test this. -	if (!cached && !compressed && update_type != OUT_FULL) +	if (!compressed && update_type != OUT_FULL)  	{  		//llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;  		gTerseObjectUpdates += num_objects; @@ -343,7 +438,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  	U8 compressed_dpbuffer[2048];  	LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048); -	LLDataPacker *cached_dpp = NULL;  	LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance();  	for (i = 0; i < num_objects; i++) @@ -353,43 +447,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  		BOOL justCreated = FALSE;  		S32	msg_size = 0; -		if (cached) -		{ -			U32 id; -			U32 crc; -			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); -			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); -			msg_size += sizeof(U32) * 2; -		 -			// Lookup data packer and add this id to cache miss lists if necessary. -			U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; -			cached_dpp = regionp->getDP(id, crc, cache_miss_type); -			if (cached_dpp) -			{ -				// Cache Hit. -				cached_dpp->reset(); -				cached_dpp->unpackUUID(fullid, "ID"); -				cached_dpp->unpackU32(local_id, "LocalID"); -				cached_dpp->unpackU8(pcode, "PCode"); -			} -			else -			{ -				// Cache Miss. -				recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size); - -				continue; // no data packer, skip this object -			} -		} -		else if (compressed) +		if (compressed)  		{ -			S32							uncompressed_length = 2048; -			compressed_dp.reset(); - -			U32 flags = 0; -			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? -			{ -				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); -			} +			S32	uncompressed_length = 2048; +			compressed_dp.reset();			  			uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);  			mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); @@ -485,9 +546,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  					continue;  				}  			} -			else if (cached) // Cache hit only? -			{ -			}  			else  			{  				if (update_type != OUT_FULL) @@ -520,8 +578,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			}  			justCreated = TRUE;  			mNumNewObjects++; -			sCacheHitRate.sample(cached ? 100.f : 0.f); -  		} @@ -540,16 +596,17 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);  			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?  			{ -				bCached = true; -				LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); -				recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size); +				U32 flags = 0; +				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); +			 +				if(!(flags & FLAGS_TEMPORARY_ON_REZ)) +				{ +					bCached = true; +					LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); +					recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size); +				}  			}  		} -		else if (cached) // Cache hit only? -		{ -			objectp->mLocalID = local_id; -			processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated); -		}  		else  		{  			if (update_type == OUT_FULL) @@ -572,14 +629,51 @@ void LLViewerObjectList::processCompressedObjectUpdate(LLMessageSystem *mesgsys,  											 void **user_data,  											 const EObjectUpdateType update_type)  { -	processObjectUpdate(mesgsys, user_data, update_type, false, true); +	processObjectUpdate(mesgsys, user_data, update_type, true);  }  void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,  											 void **user_data,  											 const EObjectUpdateType update_type)  { -	processObjectUpdate(mesgsys, user_data, update_type, true, false); +	//processObjectUpdate(mesgsys, user_data, update_type, true, false); + +	S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); +	gFullObjectUpdates += num_objects; + +	U64 region_handle; +	mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);	 +	LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); +	if (!regionp) +	{ +		llwarns << "Object update from unknown region! " << region_handle << llendl; +		return; +	} + +	LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance(); + +	for (S32 i = 0; i < num_objects; i++) +	{ +		S32	msg_size = 0; +		U32 id; +		U32 crc; +		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); +		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); +		msg_size += sizeof(U32) * 2; +		 +		// Lookup data packer and add this id to cache miss lists if necessary. +		U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; +		if(!regionp->probeCache(id, crc, cache_miss_type)) +		{ +			// Cache Miss. +			recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size); + +			continue; // no data packer, skip this object +		} +		sCacheHitRate.sample(100.f); +	} + +	return;  }	  void LLViewerObjectList::dirtyAllObjectInventory() @@ -1230,7 +1324,7 @@ void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)  	}  } -BOOL LLViewerObjectList::killObject(LLViewerObject *objectp) +BOOL LLViewerObjectList::killObject(LLViewerObject *objectp, bool cache_enabled)  {  	// Don't ever kill gAgentAvatarp, just force it to the agent's region  	// unless region is NULL which is assumed to mean you are logging out. @@ -1245,16 +1339,8 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)  	if (objectp)  	{ -		if (objectp->isDead()) -		{ -			// This object is already dead.  Don't need to do more. -			return TRUE; -		} -		else -		{ -			objectp->markDead(); -		} - +		objectp->EnableToCacheTree(cache_enabled); //enable to add to VO cache tree if set. +		objectp->markDead(); // does the right thing if object already dead  		return TRUE;  	} @@ -1890,7 +1976,30 @@ LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLVi  	return objectp;  } +LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id) +{ +	llassert_always(uuid.notNull()); + +	LLViewerObject *objectp = LLViewerObject::createObject(uuid, pcode, regionp); +	if (!objectp) +	{ +// 		llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << llendl; +		return NULL; +	} +	objectp->mLocalID = local_id; +	mUUIDObjectMap[uuid] = objectp; +	setUUIDAndLocal(uuid, +					local_id, +					regionp->getHost().getAddress(), +					regionp->getHost().getPort()); +	mObjects.push_back(objectp); +	 +	updateActive(objectp); + +	return objectp; +} +   LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp,  												 const LLUUID &uuid, const U32 local_id, const LLHost &sender)  { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 9a36b66302..b92be61fae 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -40,6 +40,7 @@  class LLCamera;  class LLNetMap;  class LLDebugBeacon; +class LLVOCacheEntry;  const U32 CLOSE_BIN_SIZE = 10;  const U32 NUM_BINS = 128; @@ -65,12 +66,13 @@ public:  	inline LLViewerObject *findObject(const LLUUID &id);  	LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object +	LLViewerObject *createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id);  	LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp,  								 const LLUUID &uuid, const U32 local_id, const LLHost &sender);  	LLViewerObject *replaceObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); // TomY: hack to switch VO instances on the fly -	BOOL killObject(LLViewerObject *objectp); +	BOOL killObject(LLViewerObject *objectp, bool cache_enabled = false);  	void killObjects(LLViewerRegion *regionp); // Kill all objects owned by a particular region.  	void killAllObjects();  	void removeDrawable(LLDrawable* drawablep); @@ -78,8 +80,10 @@ public:  	void cleanDeadObjects(const BOOL use_timer = TRUE);	// Clean up the dead object list.  	// Simulator and viewer side object updates... -	void processUpdateCore(LLViewerObject* objectp, void** data, U32 block, const EObjectUpdateType update_type, LLDataPacker* dpp, BOOL justCreated); -	void processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool cached=false, bool compressed=false); +	void processUpdateCore(LLViewerObject* objectp, void** data, U32 block, const EObjectUpdateType update_type,  +		                   LLDataPacker* dpp, bool justCreated, bool from_cache = false); +	LLViewerObject* processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp); +	void processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool compressed=false);  	void processCompressedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type);  	void processCachedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type);  	void updateApparentAngles(LLAgent &agent); @@ -188,7 +192,6 @@ public:  	S32 mNumUnknownUpdates;  	S32 mNumDeadObjectUpdates; -	S32 mNumUnknownKills;  	S32 mNumDeadObjects;  protected:  	std::vector<U64>	mOrphanParents;	// LocalID/ip,port of orphaned objects diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp new file mode 100644 index 0000000000..cfa24c32ed --- /dev/null +++ b/indra/newview/llvieweroctree.cpp @@ -0,0 +1,800 @@ +/**  + * @file llvieweroctree.cpp + * @brief LLViewerOctreeGroup class implementation and supporting functions + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llvieweroctree.h" +#include "llviewerregion.h" + +//----------------------------------------------------------------------------------- +//static variables definitions +//----------------------------------------------------------------------------------- +U32 LLViewerOctreeEntryData::sCurVisible = 0; + +//----------------------------------------------------------------------------------- +//some global functions definitions +//----------------------------------------------------------------------------------- +S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) +{ +	return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) +{ +	F32 d = 0.f; +	F32 t; +	 +	if ((min-origin).magVecSquared() < r && +		(max-origin).magVecSquared() < r) +	{ +		return 2; +	} + +	for (U32 i = 0; i < 3; i++) +	{ +		if (origin.mV[i] < min.mV[i]) +		{ +			t = min.mV[i] - origin.mV[i]; +			d += t*t; +		} +		else if (origin.mV[i] > max.mV[i]) +		{ +			t = origin.mV[i] - max.mV[i]; +			d += t*t; +		} + +		if (d > r) +		{ +			return 0; +		} +	} + +	return 1; +} + + +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) +{ +	return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) +{ +	F32 d = 0.f; +	F32 t; +	 +	LLVector4a origina; +	origina.load3(origin.mV); + +	LLVector4a v; +	v.setSub(min, origina); +	 +	if (v.dot3(v) < r) +	{ +		v.setSub(max, origina); +		if (v.dot3(v) < r) +		{ +			return 2; +		} +	} + + +	for (U32 i = 0; i < 3; i++) +	{ +		if (origin.mV[i] < min[i]) +		{ +			t = min[i] - origin.mV[i]; +			d += t*t; +		} +		else if (origin.mV[i] > max[i]) +		{ +			t = origin.mV[i] - max[i]; +			d += t*t; +		} + +		if (d > r) +		{ +			return 0; +		} +	} + +	return 1; +} + +//----------------------------------------------------------------------------------- +//class LLViewerOctreeEntry definitions +//----------------------------------------------------------------------------------- +LLViewerOctreeEntry::LLViewerOctreeEntry()  +	: mGroup(NULL), +	  mBinRadius(0.f), +	  mBinIndex(-1) +{ +	mPositionGroup.clear(); +	mExtents[0].clear(); +	mExtents[1].clear();	 + +	for(S32 i = 0; i < NUM_DATA_TYPE; i++) +	{ +		mData[i] = NULL; +	} +} + +LLViewerOctreeEntry::~LLViewerOctreeEntry() +{ +	llassert(!mGroup); +} + +void LLViewerOctreeEntry::addData(LLViewerOctreeEntryData* data) +{ +	//llassert(mData[data->getDataType()] == NULL);	 +	llassert(data != NULL); + +	mData[data->getDataType()] = data; +} + +void LLViewerOctreeEntry::removeData(LLViewerOctreeEntryData* data) +{ +	//llassert(data->getDataType() != LLVOCACHEENTRY); //can not remove VOCache entry + +	if(!mData[data->getDataType()]) +	{ +		return; +	} + +	mData[data->getDataType()] = NULL; +	 +	if(mGroup != NULL && !mData[LLDRAWABLE]) +	{ +		LLviewerOctreeGroup* group = mGroup; +		mGroup = NULL; +		group->removeFromGroup(data); + +		llassert(mBinIndex == -1);				 +	} +} + +//called by group handleDestruction() ONLY when group is destroyed by octree. +void LLViewerOctreeEntry::nullGroup() +{ +	mGroup = NULL; +} + +void LLViewerOctreeEntry::setGroup(LLviewerOctreeGroup* group) +{ +	if(mGroup == group) +	{ +		return; +	} + +	if(mGroup) +	{ +		LLviewerOctreeGroup* group = mGroup; +		mGroup = NULL; +		group->removeFromGroup(this); + +		llassert(mBinIndex == -1); +	} + +	mGroup = group; +} + +//----------------------------------------------------------------------------------- +//class LLViewerOctreeEntryData definitions +//----------------------------------------------------------------------------------- +LLViewerOctreeEntryData::~LLViewerOctreeEntryData() +{ +	if(mEntry) +	{ +		mEntry->removeData(this); +	} +} + +LLViewerOctreeEntryData::LLViewerOctreeEntryData(LLViewerOctreeEntry::eEntryDataType_t data_type) +	: mDataType(data_type), +	  mEntry(NULL) +{ +} + +//virtual +void LLViewerOctreeEntryData::setOctreeEntry(LLViewerOctreeEntry* entry) +{ +	if(mEntry.notNull()) +	{ +		return;  +	} + +	if(!entry) +	{ +		mEntry = new LLViewerOctreeEntry(); +	} +	else +	{ +		mEntry = entry; +	} +	mEntry->addData(this); +} + +void LLViewerOctreeEntryData::setSpatialExtents(const LLVector3& min, const LLVector3& max) +{  +	mEntry->mExtents[0].load3(min.mV);  +	mEntry->mExtents[1].load3(max.mV); +} + +void LLViewerOctreeEntryData::setSpatialExtents(const LLVector4a& min, const LLVector4a& max) +{  +	mEntry->mExtents[0] = min;  +	mEntry->mExtents[1] = max; +} + +void LLViewerOctreeEntryData::setPositionGroup(const LLVector4a& pos) +{ +	mEntry->mPositionGroup = pos; +} + +const LLVector4a* LLViewerOctreeEntryData::getSpatialExtents() const  +{ +	return mEntry->getSpatialExtents(); +} + +//virtual +void LLViewerOctreeEntryData::setGroup(LLviewerOctreeGroup* group) +{ +	mEntry->setGroup(group); +} + +void LLViewerOctreeEntryData::shift(const LLVector4a &shift_vector) +{ +	mEntry->mExtents[0].add(shift_vector); +	mEntry->mExtents[1].add(shift_vector); +	mEntry->mPositionGroup.add(shift_vector); +} + +LLviewerOctreeGroup* LLViewerOctreeEntryData::getGroup()const         +{ +	return mEntry.notNull() ? mEntry->mGroup : NULL; +} + +const LLVector4a& LLViewerOctreeEntryData::getPositionGroup() const   +{ +	return mEntry->getPositionGroup(); +}	 + +//virtual +bool LLViewerOctreeEntryData::isVisible() const +{ +	if(mEntry) +	{ +		return mEntry->mVisible == sCurVisible; +	} +	return false; +} + +//virtual +bool LLViewerOctreeEntryData::isRecentlyVisible() const +{ +	if(!mEntry) +	{ +		return false; +	} + +	if(isVisible()) +	{ +		return true; +	} +	if(getGroup() && getGroup()->isRecentlyVisible()) +	{ +		setVisible(); +		return true; +	} + +	return (sCurVisible - mEntry->mVisible < getMinVisFrameRange()); +} + +void LLViewerOctreeEntryData::setVisible() const +{ +	if(mEntry) +	{ +		mEntry->mVisible = sCurVisible; +	} +} + +//----------------------------------------------------------------------------------- +//class LLviewerOctreeGroup definitions +//----------------------------------------------------------------------------------- + +LLviewerOctreeGroup::~LLviewerOctreeGroup() +{ +	if(LLViewerRegion::sCurRegionp && isVisible()) +	{ +		LLViewerRegion::sCurRegionp->clearVisibleGroup(this); +	} +} + +LLviewerOctreeGroup::LLviewerOctreeGroup(OctreeNode* node) : +	mOctreeNode(node), +	mState(CLEAN) +{ +	LLVector4a tmp; +	tmp.splat(0.f); +	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =  +		mObjectExtents[0] = mObjectExtents[1] = tmp; +	 +	mBounds[0] = node->getCenter(); +	mBounds[1] = node->getSize(); + +	mOctreeNode->addListener(this); +} + +bool LLviewerOctreeGroup::hasElement(LLViewerOctreeEntryData* data)  +{  +	if(!data->getEntry()) +	{ +		return false; +	} +	return std::find(getDataBegin(), getDataEnd(), data->getEntry()) != getDataEnd();  +} + +bool LLviewerOctreeGroup::removeFromGroup(LLViewerOctreeEntryData* data) +{ +	return removeFromGroup(data->getEntry()); +} + +bool LLviewerOctreeGroup::removeFromGroup(LLViewerOctreeEntry* entry) +{ +	llassert(entry != NULL); +	llassert(!entry->getGroup()); + +	unbound(); +	if (mOctreeNode) +	{ +		if (!mOctreeNode->remove(entry)) +		{ +			OCT_ERRS << "Could not remove LLVOCacheEntry from LLVOCacheOctreeGroup" << llendl; +			return false; +		} +	} +	setState(OBJECT_DIRTY); + +	return true; +} + +//virtual  +void LLviewerOctreeGroup::unbound() +{ +	if (isDirty()) +	{ +		return; +	} + +	setState(DIRTY); +	 +	//all the parent nodes need to rebound this child +	if (mOctreeNode) +	{ +		OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); +		while (parent != NULL) +		{ +			LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) parent->getListener(0); +			if (!group || group->isDirty()) +			{ +				return; +			} +			 +			group->setState(DIRTY); +			parent = (OctreeNode*) parent->getParent(); +		} +	} +} +	 +//virtual  +void LLviewerOctreeGroup::rebound() +{ +	if (!isDirty()) +	{	 +		return; +	} +	 +	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) +	{ +		LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) mOctreeNode->getChild(0)->getListener(0); +		group->rebound(); +		 +		//copy single child's bounding box +		mBounds[0] = group->mBounds[0]; +		mBounds[1] = group->mBounds[1]; +		mExtents[0] = group->mExtents[0]; +		mExtents[1] = group->mExtents[1]; +		 +		group->setState(SKIP_FRUSTUM_CHECK); +	} +	else if (mOctreeNode->isLeaf()) +	{ //copy object bounding box if this is a leaf +		boundObjects(TRUE, mExtents[0], mExtents[1]); +		mBounds[0] = mObjectBounds[0]; +		mBounds[1] = mObjectBounds[1]; +	} +	else +	{ +		LLVector4a& newMin = mExtents[0]; +		LLVector4a& newMax = mExtents[1]; +		LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) mOctreeNode->getChild(0)->getListener(0); +		group->clearState(SKIP_FRUSTUM_CHECK); +		group->rebound(); +		//initialize to first child +		newMin = group->mExtents[0]; +		newMax = group->mExtents[1]; + +		//first, rebound children +		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) +		{ +			group = (LLviewerOctreeGroup*) mOctreeNode->getChild(i)->getListener(0); +			group->clearState(SKIP_FRUSTUM_CHECK); +			group->rebound(); +			const LLVector4a& max = group->mExtents[1]; +			const LLVector4a& min = group->mExtents[0]; + +			newMax.setMax(newMax, max); +			newMin.setMin(newMin, min); +		} + +		boundObjects(FALSE, newMin, newMax); +		 +		mBounds[0].setAdd(newMin, newMax); +		mBounds[0].mul(0.5f); +		mBounds[1].setSub(newMax, newMin); +		mBounds[1].mul(0.5f); +	} +	 +	clearState(DIRTY); + +	return; +} + +//virtual  +void LLviewerOctreeGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* obj) +{ +	obj->setGroup(this);	 +	unbound(); +	setState(OBJECT_DIRTY); +} +	 +//virtual  +void LLviewerOctreeGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* obj) +{ +	obj->setGroup(NULL); +	unbound(); +	setState(OBJECT_DIRTY); +} +	 +//virtual  +void LLviewerOctreeGroup::handleDestruction(const TreeNode* node) +{ +	for (OctreeNode::element_iter i = mOctreeNode->getDataBegin(); i != mOctreeNode->getDataEnd(); ++i) +	{ +		LLViewerOctreeEntry* obj = *i; +		if (obj && obj->getGroup() == this) +		{ +			obj->nullGroup(); +			//obj->setGroup(NULL); +		} +	} +	mOctreeNode = NULL; +} +	 +//virtual  +void LLviewerOctreeGroup::handleStateChange(const TreeNode* node) +{ +	//drop bounding box upon state change +	if (mOctreeNode != node) +	{ +		mOctreeNode = (OctreeNode*) node; +	} +	unbound(); +} +	 +//virtual  +void LLviewerOctreeGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) +{ +	if (child->getListenerCount() == 0) +	{ +		new LLviewerOctreeGroup(child); +	} +	else +	{ +		OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl; +	} + +	unbound(); +	 +	//((LLviewerOctreeGroup*)child->getListener(0))->unbound(); +} +	 +//virtual  +void LLviewerOctreeGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) +{ +	unbound(); +} + +LLviewerOctreeGroup* LLviewerOctreeGroup::getParent() +{ +	if(!mOctreeNode) +	{ +		return NULL; +	} +	 +	OctreeNode* parent = mOctreeNode->getOctParent(); + +	if (parent) +	{ +		return (LLviewerOctreeGroup*) parent->getListener(0); +	} + +	return NULL; +} + +//virtual  +bool LLviewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) +{ +	const OctreeNode* node = mOctreeNode; + +	if (node->isEmpty()) +	{	//don't do anything if there are no objects +		if (empty && mOctreeNode->getParent()) +		{	//only root is allowed to be empty +			OCT_ERRS << "Empty leaf found in octree." << llendl; +		} +		return false; +	} + +	LLVector4a& newMin = mObjectExtents[0]; +	LLVector4a& newMax = mObjectExtents[1]; +	 +	if (hasState(OBJECT_DIRTY)) +	{ //calculate new bounding box +		clearState(OBJECT_DIRTY); + +		//initialize bounding box to first element +		OctreeNode::const_element_iter i = node->getDataBegin(); +		LLViewerOctreeEntry* entry = *i; +		const LLVector4a* minMax = entry->getSpatialExtents(); + +		newMin = minMax[0]; +		newMax = minMax[1]; + +		for (++i; i != node->getDataEnd(); ++i) +		{ +			entry = *i; +			minMax = entry->getSpatialExtents(); +			 +			update_min_max(newMin, newMax, minMax[0]); +			update_min_max(newMin, newMax, minMax[1]); +		} +		 +		mObjectBounds[0].setAdd(newMin, newMax); +		mObjectBounds[0].mul(0.5f); +		mObjectBounds[1].setSub(newMax, newMin); +		mObjectBounds[1].mul(0.5f); +	} +	 +	if (empty) +	{ +		minOut = newMin; +		maxOut = newMax; +	} +	else +	{ +		minOut.setMin(minOut, newMin); +		maxOut.setMax(maxOut, newMax); +	} +		 +	return TRUE; +} + +//virtual  +BOOL LLviewerOctreeGroup::isVisible() const +{ +	return mVisible[LLViewerCamera::sCurCameraID] >= LLViewerOctreeEntryData::getCurrentFrame() ? TRUE : FALSE; +} + +//virtual  +BOOL LLviewerOctreeGroup::isRecentlyVisible() const  +{ +	return FALSE; +} + +void LLviewerOctreeGroup::setVisible() +{ +	mVisible[LLViewerCamera::sCurCameraID] = LLViewerOctreeEntryData::getCurrentFrame(); +} +//----------------------------------------------------------------------------------- +//class LLViewerOctreePartition definitions +//----------------------------------------------------------------------------------- +LLViewerOctreePartition::LLViewerOctreePartition() : mRegionp(NULL) +{ +	LLVector4a center, size; +	center.splat(0.f); +	size.splat(1.f); + +	mOctree = new OctreeRoot(center,size, NULL); +} +	 +LLViewerOctreePartition::~LLViewerOctreePartition() +{ +	delete mOctree; +	mOctree = NULL; +} + +//----------------------------------------------------------------------------------- +//class LLViewerOctreeCull definitions +//----------------------------------------------------------------------------------- + +//virtual  +bool LLViewerOctreeCull::earlyFail(LLviewerOctreeGroup* group) +{	 +	return false; +} +	 +//virtual  +void LLViewerOctreeCull::traverse(const OctreeNode* n) +{ +	LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) n->getListener(0); + +	if (earlyFail(group)) +	{ +		return; +	} +		 +	if (mRes == 2 ||  +		(mRes && group->hasState(LLviewerOctreeGroup::SKIP_FRUSTUM_CHECK))) +	{	//fully in, just add everything +		OctreeTraveler::traverse(n); +	} +	else +	{ +		mRes = frustumCheck(group); +				 +		if (mRes) +		{ //at least partially in, run on down +			OctreeTraveler::traverse(n); +		} + +		mRes = 0; +	} +} +	 +//------------------------------------------ +//agent space group culling +S32 LLViewerOctreeCull::AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +} + +S32 LLViewerOctreeCull::AABBSphereIntersectGroupExtents(const LLviewerOctreeGroup* group) +{ +	return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist); +} + +S32 LLViewerOctreeCull::AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); +} +//------------------------------------------ + +//------------------------------------------ +//agent space object set culling +S32 LLViewerOctreeCull::AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +} + +S32 LLViewerOctreeCull::AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group) +{ +	return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist); +} + +S32 LLViewerOctreeCull::AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); +} +//------------------------------------------ + +//------------------------------------------ +//local regional space group culling +S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInRegionFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +} + +S32 LLViewerOctreeCull::AABBInRegionFrustumGroupBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInRegionFrustum(group->mBounds[0], group->mBounds[1]); +} + +S32 LLViewerOctreeCull::AABBRegionSphereIntersectGroupExtents(const LLviewerOctreeGroup* group, const LLVector3& shift) +{ +	return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin() - shift, mCamera->mFrustumCornerDist); +} +//------------------------------------------ + +//------------------------------------------ +//local regional space object culling +S32 LLViewerOctreeCull::AABBInRegionFrustumObjectBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInRegionFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); +} + +S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group) +{ +	return mCamera->AABBInRegionFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +} + +S32 LLViewerOctreeCull::AABBRegionSphereIntersectObjectExtents(const LLviewerOctreeGroup* group, const LLVector3& shift) +{ +	return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin() - shift, mCamera->mFrustumCornerDist); +} +//------------------------------------------ + +//virtual  +bool LLViewerOctreeCull::checkObjects(const OctreeNode* branch, const LLviewerOctreeGroup* group) +{ +	if (branch->getElementCount() == 0) //no elements +	{ +		return false; +	} +	else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box +	{ +		return true; +	} +	else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum +	{ +		return false; +	} +		 +	return true; +} + +//virtual  +void LLViewerOctreeCull::preprocess(LLviewerOctreeGroup* group) +{		 +} +	 +//virtual  +void LLViewerOctreeCull::processGroup(LLviewerOctreeGroup* group) +{ +} +	 +//virtual  +void LLViewerOctreeCull::visit(const OctreeNode* branch)  +{	 +	LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) branch->getListener(0); + +	preprocess(group); +		 +	if (checkObjects(branch, group)) +	{ +		processGroup(group); +	} +} + diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h new file mode 100644 index 0000000000..a35c551949 --- /dev/null +++ b/indra/newview/llvieweroctree.h @@ -0,0 +1,327 @@ +/**  + * @file llvieweroctree.h + * @brief LLViewerObjectOctree.cpp header file, defining all supporting classes. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_VIEWEROCTREE_H +#define LL_VIEWEROCTREE_H + +#include <vector> +#include <map> + +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "llvector4a.h" +#include "llquaternion.h" +#include "lloctree.h" +#include "llviewercamera.h" + +class LLViewerRegion; +class LLViewerOctreeEntryData; +class LLviewerOctreeGroup; +class LLViewerOctreeEntry; + +typedef LLOctreeListener<LLViewerOctreeEntry>	OctreeListener; +typedef LLTreeNode<LLViewerOctreeEntry>			TreeNode; +typedef LLOctreeNode<LLViewerOctreeEntry>		OctreeNode; +typedef LLOctreeRoot<LLViewerOctreeEntry>		OctreeRoot; +typedef LLOctreeTraveler<LLViewerOctreeEntry>	OctreeTraveler; + +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad); +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared); + +S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad); +S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared); + +//defines data needed for octree of an entry +LL_ALIGN_PREFIX(16) +class LLViewerOctreeEntry : public LLRefCount +{ +	friend class LLViewerOctreeEntryData; + +public: +	typedef enum +	{ +		LLDRAWABLE = 0, +		LLVOCACHEENTRY, +		NUM_DATA_TYPE +	}eEntryDataType_t; + +	~LLViewerOctreeEntry(); +public: +	LLViewerOctreeEntry(); +	 +	void nullGroup(); //called by group handleDestruction() only +	void setGroup(LLviewerOctreeGroup* group); +	void removeData(LLViewerOctreeEntryData* data); + +	LLViewerOctreeEntryData* getData(U32 data_type)const {return mData[data_type];} +	bool                     hasData(U32 data_type)const {return mData[data_type] != NULL;} + +	LLViewerOctreeEntryData* getDrawable() const {return mData[LLDRAWABLE];} +	bool                     hasDrawable() const {return mData[LLDRAWABLE] != NULL;} +	LLViewerOctreeEntryData* getVOCacheEntry() const {return mData[LLVOCACHEENTRY];} +	bool                     hasVOCacheEntry() const {return mData[LLVOCACHEENTRY] != NULL;} + +	const LLVector4a* getSpatialExtents() const {return mExtents;}  +	const LLVector4a& getPositionGroup() const  {return mPositionGroup;}	 +	LLviewerOctreeGroup* getGroup()const        {return mGroup;} +	 +	F32  getBinRadius() const                   {return mBinRadius;} +	S32	 getBinIndex() const			        {return mBinIndex; } +	void setBinIndex(S32 index) const	        {mBinIndex = index; } + +	void* operator new(size_t size) +	{ +		return ll_aligned_malloc_16(size); +	} + +	void operator delete(void* ptr) +	{ +		ll_aligned_free_16(ptr); +	} + +private: +	void addData(LLViewerOctreeEntryData* data);			 + +private: +	LLViewerOctreeEntryData*    mData[NUM_DATA_TYPE]; //do not use LLPointer here. +	LLviewerOctreeGroup*        mGroup; + +	//aligned members +	LL_ALIGN_16(LLVector4a		mExtents[2]); +	LL_ALIGN_16(LLVector4a		mPositionGroup); +	F32				            mBinRadius; +	mutable S32		            mBinIndex; +	mutable U32		            mVisible;	 + +} LL_ALIGN_POSTFIX(16); + +//defines an abstract class for entry data +LL_ALIGN_PREFIX(16) +class LLViewerOctreeEntryData : public LLRefCount +{ +protected: +	~LLViewerOctreeEntryData(); + +public: +	LLViewerOctreeEntryData(const LLViewerOctreeEntryData& rhs) +	{ +		*this = rhs; +	} +	LLViewerOctreeEntryData(LLViewerOctreeEntry::eEntryDataType_t data_type); +	 +	LLViewerOctreeEntry::eEntryDataType_t getDataType() const {return mDataType;} +	LLViewerOctreeEntry* getEntry() {return mEntry;} +	 +	virtual void setOctreeEntry(LLViewerOctreeEntry* entry); + +	virtual S32  getMinVisFrameRange()const = 0; + +	F32                  getBinRadius() const   {return mEntry->getBinRadius();} +	const LLVector4a*    getSpatialExtents() const; +	LLviewerOctreeGroup* getGroup()const; +	const LLVector4a&    getPositionGroup() const; +	 +	void setBinRadius(F32 rad)  {mEntry->mBinRadius = rad;} +	void setSpatialExtents(const LLVector3& min, const LLVector3& max); +	void setSpatialExtents(const LLVector4a& min, const LLVector4a& max); +	void setPositionGroup(const LLVector4a& pos); +	 +	virtual void setGroup(LLviewerOctreeGroup* group); +	void         shift(const LLVector4a &shift_vector); + +	U32          getVisible() const {return mEntry ? mEntry->mVisible : 0;} +	void         setVisible() const; +	virtual bool isVisible() const; +	virtual bool isRecentlyVisible() const;	 +	 +	static S32 getCurrentFrame() { return sCurVisible; } + +protected: +	LLVector4a& getGroupPosition()  {return mEntry->mPositionGroup;} +	void        initVisible(U32 visible) {mEntry->mVisible = visible;} + +	static void incrementVisible() {sCurVisible++;} +protected: +	LLPointer<LLViewerOctreeEntry>        mEntry; +	LLViewerOctreeEntry::eEntryDataType_t mDataType; +	static  U32                           sCurVisible; // Counter for what value of mVisible means currently visible +}LL_ALIGN_POSTFIX(16); + + +//defines an octree group for an octree node, which contains multiple entries. +LL_ALIGN_PREFIX(16) +class LLviewerOctreeGroup : public LLOctreeListener<LLViewerOctreeEntry> +{ +	friend class LLViewerOctreeCull; +protected: +	~LLviewerOctreeGroup(); + +public: +	enum +	{ +		CLEAN              = 0x00000000, +		DIRTY              = 0x00000001, +		OBJECT_DIRTY       = 0x00000002, +		SKIP_FRUSTUM_CHECK = 0x00000004, +		INVALID_STATE      = 0x00000008, +	}; + +public: +	typedef LLOctreeNode<LLViewerOctreeEntry>::element_iter element_iter; +	typedef LLOctreeNode<LLViewerOctreeEntry>::element_list element_list; + +	LLviewerOctreeGroup(OctreeNode* node); +	LLviewerOctreeGroup(const LLviewerOctreeGroup& rhs) +	{ +		*this = rhs; +	} + +	void* operator new(size_t size) +	{ +		return ll_aligned_malloc_16(size); +	} + +	void operator delete(void* ptr) +	{ +		ll_aligned_free_16(ptr); +	} + +	bool removeFromGroup(LLViewerOctreeEntryData* data); +	bool removeFromGroup(LLViewerOctreeEntry* entry); + +	virtual void unbound(); +	virtual void rebound(); + +	void setVisible(); +	BOOL isVisible() const; +	virtual BOOL isRecentlyVisible() const; +	bool isEmpty() const { return mOctreeNode->isEmpty(); } + +	U32  getState()				   {return mState; } +	bool isDirty() const           {return mState & DIRTY;} +	bool hasState(U32 state) const {return mState & state;} +	void setState(U32 state)       {mState |= state;} +	void clearState(U32 state)     {mState &= ~state;}	 + +	//LISTENER FUNCTIONS +	virtual void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* obj); +	virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* obj); +	virtual void handleDestruction(const TreeNode* node); +	virtual void handleStateChange(const TreeNode* node); +	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child); +	virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child); + +	OctreeNode*          getOctreeNode() {return mOctreeNode;} +	LLviewerOctreeGroup* getParent(); + +	const LLVector4a* getBounds() const        {return mBounds;} +	const LLVector4a* getExtents() const       {return mExtents;} +	const LLVector4a* getObjectBounds() const  {return mObjectBounds;} +	const LLVector4a* getObjectExtents() const {return mObjectExtents;} + +	//octree wrappers to make code more readable +	element_list& getData() { return mOctreeNode->getData(); } +	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); } +	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); } +	U32 getElementCount() const { return mOctreeNode->getElementCount(); } +	bool hasElement(LLViewerOctreeEntryData* data); +	 +private: +	virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut);	 +	 +protected: +	U32         mState; +	OctreeNode* mOctreeNode;	 + +	LL_ALIGN_16(LLVector4a mBounds[2]);        // bounding box (center, size) of this node and all its children (tight fit to objects) +	LL_ALIGN_16(LLVector4a mObjectBounds[2]);  // bounding box (center, size) of objects in this node +	LL_ALIGN_16(LLVector4a mExtents[2]);       // extents (min, max) of this node and all its children +	LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node + +public: +	S32         mVisible[LLViewerCamera::NUM_CAMERAS]; +}LL_ALIGN_POSTFIX(16); + +class LLViewerOctreePartition +{ +public: +	LLViewerOctreePartition(); +	virtual ~LLViewerOctreePartition(); + +	// Cull on arbitrary frustum +	virtual S32 cull(LLCamera &camera) = 0; + +public:	 +	U32              mPartitionType; +	OctreeNode*      mOctree; +	LLViewerRegion*  mRegionp; // the region this partition belongs to. +}; + +class LLViewerOctreeCull : public OctreeTraveler +{ +public: +	LLViewerOctreeCull(LLCamera* camera) +		: mCamera(camera), mRes(0) { } + +	virtual bool earlyFail(LLviewerOctreeGroup* group); +	virtual void traverse(const OctreeNode* n); +	 +	//agent space group cull +	S32 AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group);	 +	S32 AABBSphereIntersectGroupExtents(const LLviewerOctreeGroup* group); +	S32 AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group); + +	//agent space object set cull +	S32 AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group); +	S32 AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group);	 +	S32 AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group); +	 +	//local region space group cull +	S32 AABBInRegionFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group); +	S32 AABBInRegionFrustumGroupBounds(const LLviewerOctreeGroup* group); +	S32 AABBRegionSphereIntersectGroupExtents(const LLviewerOctreeGroup* group, const LLVector3& shift); + +	//local region space object set cull +	S32 AABBInRegionFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group); +	S32 AABBInRegionFrustumObjectBounds(const LLviewerOctreeGroup* group); +	S32 AABBRegionSphereIntersectObjectExtents(const LLviewerOctreeGroup* group, const LLVector3& shift);	 +	 +	virtual S32 frustumCheck(const LLviewerOctreeGroup* group) = 0; +	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group) = 0; + +	virtual bool checkObjects(const OctreeNode* branch, const LLviewerOctreeGroup* group); +	virtual void preprocess(LLviewerOctreeGroup* group); +	virtual void processGroup(LLviewerOctreeGroup* group); +	virtual void visit(const OctreeNode* branch); +	 +protected: +	LLCamera *mCamera; +	S32 mRes; +}; + +#endif diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 6bd9f66b9c..8acdc08b00 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -151,8 +151,8 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 bo  	if (group != NULL)  	{ -		LLVector3 center(group->mOctreeNode->getCenter().getF32ptr()); -		LLVector3 size(group->mOctreeNode->getSize().getF32ptr()); +		LLVector3 center(group->getOctreeNode()->getCenter().getF32ptr()); +		LLVector3 size(group->getOctreeNode()->getSize().getF32ptr());  		size += LLVector3(0.01f, 0.01f, 0.01f);  		mMinObjPos = center - size;  		mMaxObjPos = center + size; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 7e81e9714f..7d2e08c1c6 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -70,6 +70,7 @@  #include "stringize.h"  #include "llviewercontrol.h"  #include "llsdserialize.h" +#include "llvieweroctree.h"  #ifdef LL_WINDOWS  	#pragma warning(disable:4355) @@ -85,6 +86,9 @@ const F32 CAP_REQUEST_TIMEOUT = 18;  // Even though we gave up on login, keep trying for caps after we are logged in:  const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; +LLViewerRegion* LLViewerRegion::sCurRegionp = NULL; +BOOL LLViewerRegion::sVOCacheCullingEnabled = FALSE; +  typedef std::map<std::string, std::string> CapabilityMap;  class LLViewerRegionImpl { @@ -97,6 +101,8 @@ public:  			mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN),  			mSeedCapAttempts(0),  			mHttpResponderID(0), +			mLastCameraUpdate(0), +			mLastCameraOrigin(),  		    // I'd prefer to set the LLCapabilityListener name to match the region  		    // name -- it's disappointing that's not available at construction time.  		    // We could instead store an LLCapabilityListener*, making @@ -133,7 +139,14 @@ public:  	// Misc  	LLVLComposition *mCompositionp;		// Composition layer for the surface -	LLVOCacheEntry::vocache_entry_map_t		mCacheMap; +	LLVOCacheEntry::vocache_entry_map_t	  mCacheMap; //all cached entries +	LLVOCacheEntry::vocache_entry_set_t   mActiveSet; //all active entries; +	LLVOCacheEntry::vocache_entry_set_t   mWaitingSet; //entries waiting for LLDrawable to be generated.	 +	std::set< LLviewerOctreeGroup* >      mVisibleGroups; //visible groupa +	LLVOCachePartition*                   mVOCachePartition; +	LLVOCacheEntry::vocache_entry_set_t   mVisibleEntries; //must-be-created visible entries wait for objects creation.	 +	LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation. +  	// time?  	// LRU info? @@ -157,7 +170,10 @@ public:  	LLCapabilityListener mCapabilityListener;  	//spatial partitions for objects in this region -	std::vector<LLSpatialPartition*> mObjectPartition; +	std::vector<LLViewerOctreePartition*> mObjectPartition; + +	LLVector3 mLastCameraOrigin; +	U32       mLastCameraUpdate;  };  // support for secondlife:///app/region/{REGION} SLapps @@ -292,7 +308,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,  	mReleaseNotesRequested(FALSE),  	mCapabilitiesReceived(false),  	mBitsReceived(0.f), -	mPacketsReceived(0.f) +	mPacketsReceived(0.f), +	mDead(FALSE)  {  	mWidth = region_width_meters;  	mImpl->mOriginGlobal = from_region_handle(handle);  @@ -324,17 +341,20 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,  	//create object partitions  	//MUST MATCH declaration of eObjectPartitions -	mImpl->mObjectPartition.push_back(new LLHUDPartition());		//PARTITION_HUD -	mImpl->mObjectPartition.push_back(new LLTerrainPartition());	//PARTITION_TERRAIN -	mImpl->mObjectPartition.push_back(new LLVoidWaterPartition());	//PARTITION_VOIDWATER -	mImpl->mObjectPartition.push_back(new LLWaterPartition());		//PARTITION_WATER -	mImpl->mObjectPartition.push_back(new LLTreePartition());		//PARTITION_TREE -	mImpl->mObjectPartition.push_back(new LLParticlePartition());	//PARTITION_PARTICLE -	mImpl->mObjectPartition.push_back(new LLGrassPartition());		//PARTITION_GRASS -	mImpl->mObjectPartition.push_back(new LLVolumePartition());	//PARTITION_VOLUME -	mImpl->mObjectPartition.push_back(new LLBridgePartition());	//PARTITION_BRIDGE -	mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE +	mImpl->mObjectPartition.push_back(new LLHUDPartition(this));		//PARTITION_HUD +	mImpl->mObjectPartition.push_back(new LLTerrainPartition(this));	//PARTITION_TERRAIN +	mImpl->mObjectPartition.push_back(new LLVoidWaterPartition(this));	//PARTITION_VOIDWATER +	mImpl->mObjectPartition.push_back(new LLWaterPartition(this));		//PARTITION_WATER +	mImpl->mObjectPartition.push_back(new LLTreePartition(this));		//PARTITION_TREE +	mImpl->mObjectPartition.push_back(new LLParticlePartition(this));	//PARTITION_PARTICLE +	mImpl->mObjectPartition.push_back(new LLGrassPartition(this));		//PARTITION_GRASS +	mImpl->mObjectPartition.push_back(new LLVolumePartition(this));	//PARTITION_VOLUME +	mImpl->mObjectPartition.push_back(new LLBridgePartition(this));	//PARTITION_BRIDGE +	mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE +	mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE  	mImpl->mObjectPartition.push_back(NULL);						//PARTITION_NONE + +	mImpl->mVOCachePartition = getVOCachePartition();  } @@ -355,6 +375,12 @@ void LLViewerRegion::initStats()  LLViewerRegion::~LLViewerRegion()   { +	mDead = TRUE; +	mImpl->mActiveSet.clear(); +	mImpl->mVisibleEntries.clear(); +	mImpl->mVisibleGroups.clear(); +	mImpl->mWaitingSet.clear(); +  	gVLManager.cleanupData(this);  	// Can't do this on destruction, because the neighbor pointers might be invalid.  	// This should be reference counted... @@ -367,12 +393,12 @@ LLViewerRegion::~LLViewerRegion()  	delete mParcelOverlay;  	delete mImpl->mLandp;  	delete mImpl->mEventPoll; -	LLHTTPSender::clearSender(mImpl->mHost); -	 -	saveObjectCache(); +	LLHTTPSender::clearSender(mImpl->mHost);	  	std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); +	saveObjectCache(); +  	delete mImpl;  	mImpl = NULL;  } @@ -438,10 +464,6 @@ void LLViewerRegion::saveObjectCache()  		mCacheDirty = FALSE;  	} -	for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) -	{ -		delete iter->second; -	}  	mImpl->mCacheMap.clear();  } @@ -719,8 +741,354 @@ void LLViewerRegion::dirtyHeights()  	}  } +void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry) +{ +	U32 state = LLVOCacheEntry::INACTIVE; + +	if(old_entry) +	{ +		old_entry->copyTo(new_entry); +		state = old_entry->getState();		 +		killCacheEntry(old_entry); +	} + +	mImpl->mCacheMap[new_entry->getLocalID()] = new_entry; + +	if(state == LLVOCacheEntry::ACTIVE) +	{ +		llassert(new_entry->getEntry()->hasDrawable()); +		mImpl->mActiveSet.insert(new_entry); +	} +	else if(state == LLVOCacheEntry::WAITING) +	{ +		mImpl->mWaitingSet.insert(new_entry); +	} +	else if(old_entry && new_entry->getEntry()) +	{ +		addToVOCacheTree(new_entry); +	} +	new_entry->setState(state); +} + +//physically delete the cache entry +void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry) +{	 +	if(!entry) +	{ +		return; +	} + +	//remove from active list and waiting list +	if(entry->isState(LLVOCacheEntry::ACTIVE)) +	{ +		mImpl->mActiveSet.erase(entry); +	} +	else +	{ +		if(entry->isState(LLVOCacheEntry::WAITING)) +		{ +			mImpl->mWaitingSet.erase(entry); +		} +		 +		//remove from mVOCachePartition +		removeFromVOCacheTree(entry); +	} + +	//remove from the forced visible list +	mImpl->mVisibleEntries.erase(entry); + +	//kill LLViewerObject if exists +	//this should be done by the rendering pipeline automatically. +	 +	entry->setState(LLVOCacheEntry::INACTIVE); +	 +	//remove from mCacheMap, real deletion +	mImpl->mCacheMap.erase(entry->getLocalID()); +} + +//physically delete the cache entry	 +void LLViewerRegion::killCacheEntry(U32 local_id)  +{ +	killCacheEntry(getCacheEntry(local_id)); +} + +U32 LLViewerRegion::getNumOfActiveCachedObjects() const +{ +	return  mImpl->mActiveSet.size(); +} + +void LLViewerRegion::addActiveCacheEntry(LLVOCacheEntry* entry) +{ +	if(!entry || mDead) +	{ +		return; +	} + +	if(entry->isState(LLVOCacheEntry::WAITING)) +	{ +		mImpl->mWaitingSet.erase(entry); +	} + +	entry->setState(LLVOCacheEntry::ACTIVE); +	entry->setVisible(); + +	llassert(entry->getEntry()->hasDrawable()); +	mImpl->mActiveSet.insert(entry); +} + +void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep) +{ +	if(mDead) +	{ +		return; +	} + +	if(drawablep->getParent()) //child object +	{ +		LLViewerOctreeEntry* parent_oct_entry = drawablep->getParent()->getEntry(); +		if(parent_oct_entry && parent_oct_entry->hasVOCacheEntry()) +		{ +			LLVOCacheEntry* parent = (LLVOCacheEntry*)parent_oct_entry->getVOCacheEntry(); +			parent->addChild(entry); +		} +	} +	else //insert to vo cache tree. +	{ +		//shift to the local regional space from agent space +		const LLVector3 pos = drawablep->getVObj()->getPositionRegion(); +		LLVector4a vec(pos[0], pos[1], pos[2]); +		LLVector4a shift;  +		shift.setSub(vec, entry->getPositionGroup()); +		entry->shift(shift); +		 +		addToVOCacheTree(entry); +	} + +	mImpl->mVisibleEntries.erase(entry); +	mImpl->mActiveSet.erase(entry); +	mImpl->mWaitingSet.erase(entry); +	entry->setState(LLVOCacheEntry::INACTIVE); +} + +void LLViewerRegion::addVisibleGroup(LLviewerOctreeGroup* group) +{ +	if(mDead || group->isEmpty()) +	{ +		return; +	} +	group->setVisible(); +	mImpl->mVisibleGroups.insert(group); +} + +void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry) +{ +	if(!sVOCacheCullingEnabled) +	{ +		return; +	} + +	if(mDead || !entry || !entry->getEntry()) +	{ +		return; +	} +	if(entry->getGroup()) //already in octree. +	{ +		return; +	} +	if(!entry->hasState(LLVOCacheEntry::ADD_TO_CACHE_TREE)) +	{ +		return; //can not add to vo cache tree. +	} + +	mImpl->mVOCachePartition->addEntry(entry->getEntry()); +} + +void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry) +{ +	if(mDead || !entry || !entry->getEntry()) +	{ +		return; +	} +	if(!entry->getGroup()) +	{ +		return; +	} + +	mImpl->mVOCachePartition->removeEntry(entry->getEntry()); +} + +//add the visible entries +void LLViewerRegion::addVisibleCacheEntry(LLVOCacheEntry* entry) +{ +	if(mDead || !entry) +	{ +		return;  +	} + +	if(entry->isState(LLVOCacheEntry::IN_QUEUE)) +	{ +		return; +	} + +	if(entry->isState(LLVOCacheEntry::INACTIVE)) +	{ +		entry->setState(LLVOCacheEntry::IN_QUEUE); +	} +	mImpl->mVisibleEntries.insert(entry); +} + +void LLViewerRegion::clearVisibleGroup(LLviewerOctreeGroup* group) +{ +	if(mDead) +	{ +		return; +	} + +	llassert(!group->getOctreeNode() || group->isEmpty()); + +	mImpl->mVisibleGroups.erase(group); +} + +F32 LLViewerRegion::updateVisibleEntries(F32 max_time) +{ +	if(mImpl->mVisibleGroups.empty() && mImpl->mVisibleEntries.empty()) +	{ +		return max_time; +	} + +	LLTimer update_timer; + +	const LLVector3 camera_origin = LLViewerCamera::getInstance()->getOrigin(); +	const U32 cur_frame = LLViewerOctreeEntryData::getCurrentFrame(); +	bool needs_update = ((cur_frame - mImpl->mLastCameraUpdate) > 5) && ((camera_origin - mImpl->mLastCameraOrigin).lengthSquared() > 10.f);	 + +	//process visible entries +	max_time *= 0.5f; //only use up to half available time to update entries. + +#if 1 +	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();) +	{ +		LLVOCacheEntry* vo_entry = *iter; +		vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate); + +		if(vo_entry->getState() < LLVOCacheEntry::WAITING) +		{			 +			mImpl->mWaitingList.insert(vo_entry); +		} + +		LLVOCacheEntry* child; +		S32 num_child = vo_entry->getNumOfChildren(); +		S32 num_done = 0; +		for(S32 i = 0; i < num_child; i++) +		{ +			child = vo_entry->getChild(i); +			if(child->getState() < LLVOCacheEntry::WAITING) +			{ +				child->setSceneContribution(vo_entry->getSceneContribution()); +				mImpl->mWaitingList.insert(child); +			} +			else +			{ +				num_done++; +			} +		} +		if(num_done == num_child) +		{ +			vo_entry->clearChildrenList(); +		} + +		if(!vo_entry->getNumOfChildren()) +		{ +			if(vo_entry->getState() >= LLVOCacheEntry::WAITING) +			{ +				iter = mImpl->mVisibleEntries.erase(iter); +			} +			else +			{ +				++iter; +			} +		} +		else +		{ +			++iter; +		} + +		//if(update_timer.getElapsedTimeF32() > max_time) +		//{ +		//	break; +		//} +	} +#endif + +	//process visible groups +	std::set< LLviewerOctreeGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin(); +	for(; group_iter != mImpl->mVisibleGroups.end(); ++group_iter) +	{ +		LLviewerOctreeGroup* group = *group_iter; +		if(!group->getOctreeNode() || group->isEmpty()) +		{ +			continue; +		} + +		for (LLviewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) +		{ +			if((*i)->hasVOCacheEntry()) +			{ +				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry(); + +				vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);				 +				mImpl->mWaitingList.insert(vo_entry); +			} +		} + +		//if(update_timer.getElapsedTimeF32() > max_time) +		//{ +		//	break; +		//} +	} +	mImpl->mVisibleGroups.clear(); + +	if(needs_update) +	{ +		mImpl->mLastCameraOrigin = camera_origin; +		mImpl->mLastCameraUpdate = cur_frame; +	} + +	return 2.0f * max_time - update_timer.getElapsedTimeF32(); +} + +F32 LLViewerRegion::createVisibleObjects(F32 max_time) +{ +	if(mImpl->mWaitingList.empty()) +	{ +		return max_time; +	} + +	LLTimer update_timer; +	S32 max_num_objects = 64; //minimum number of new objects to be added +	for(LLVOCacheEntry::vocache_entry_priority_list_t::iterator iter = mImpl->mWaitingList.begin(); +		iter != mImpl->mWaitingList.end(); ++iter) +	{ +		LLVOCacheEntry* vo_entry = *iter; +			 +		if(vo_entry->getState() < LLVOCacheEntry::WAITING) +		{ +			addNewObject(vo_entry); +			if(max_num_objects-- < 0 && update_timer.getElapsedTimeF32() > max_time) +			{ +				break; +			} +		} +	} +	mImpl->mWaitingList.clear(); + +	return max_time - update_timer.getElapsedTimeF32(); +} +  BOOL LLViewerRegion::idleUpdate(F32 max_update_time)  { +	LLTimer update_timer; +  	// did_update returns TRUE if we did at least one significant update  	BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); @@ -730,9 +1098,98 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)  		mParcelOverlay->idleUpdate();  	} +	max_update_time -= update_timer.getElapsedTimeF32(); +	if(max_update_time < 0.f || mImpl->mCacheMap.empty()) +	{ +		return did_update; +	} + +	sCurRegionp = this; + +	//kill invisible objects +	max_update_time = killInvisibleObjects(max_update_time);	 +	 +	max_update_time = updateVisibleEntries(max_update_time); +	createVisibleObjects(max_update_time); + +	mImpl->mVisibleGroups.clear(); +	mImpl->mWaitingList.clear(); + +	sCurRegionp = NULL;  	return did_update;  } +F32 LLViewerRegion::killInvisibleObjects(F32 max_time) +{ +	if(!sVOCacheCullingEnabled) +	{ +		return max_time; +	} + +	std::vector<LLDrawable*> delete_list; +	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin(); +		iter != mImpl->mActiveSet.end(); ++iter) +	{ +		if(!(*iter)->isRecentlyVisible()) +		{ +			killObject((*iter), delete_list); +		} +	} +	for(S32 i = 0; i < delete_list.size(); i++) +	{ +		gObjectList.killObject(delete_list[i]->getVObj(), true); +	} +	delete_list.clear(); + +	return max_time; +} + +void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list) +{ +	//kill the object. +	LLDrawable* drawablep = (LLDrawable*)entry->getEntry()->getDrawable(); +	llassert(drawablep); + +	if(!drawablep->getParent()) +	{ +		LLViewerObject::const_child_list_t& child_list = drawablep->getVObj()->getChildren(); +		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +			iter != child_list.end(); iter++) +		{ +			LLViewerObject* child = *iter; +			if(child->mDrawable->isRecentlyVisible()) +			{ +				//set the parent group visible if any of its children visible. +				((LLViewerOctreeEntryData*)drawablep)->setVisible(); +				return; +			} +		} +		delete_list.push_back(drawablep);				 +	}				 +} + +LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry) +{ +	LLViewerObject* obj = NULL; +	if(!entry->getEntry()->hasDrawable()) //not added to the rendering pipeline yet +	{ +		//add the object +		obj = gObjectList.processObjectUpdateFromCache(entry, this); +		if(obj) +		{ +			if(!entry->isState(LLVOCacheEntry::ACTIVE)) +			{ +				mImpl->mWaitingSet.insert(entry); +				entry->setState(LLVOCacheEntry::WAITING); +			} +		} +	} +	else +	{ +		llerrs << "Object is already created." << llendl; +	} +	return obj; +}  // As above, but forcibly do the update.  void LLViewerRegion::forceUpdate() @@ -1191,8 +1648,9 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec  {  	U32 local_id = objectp->getLocalID();  	U32 crc = objectp->getCRC(); +	eCacheUpdateResult result; -	LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); +	LLVOCacheEntry* entry = getCacheEntry(local_id);  	if (entry)  	{ @@ -1201,41 +1659,72 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec  		{  			// Record a hit  			entry->recordDupe(); -			return CACHE_UPDATE_DUPE; +			result = CACHE_UPDATE_DUPE;  		} +		else +		{ +			// Update the cache entry +			LLPointer<LLVOCacheEntry> new_entry = new LLVOCacheEntry(local_id, crc, dp); +			replaceCacheEntry(entry, new_entry); +			entry = new_entry; -		// Update the cache entry -		mImpl->mCacheMap.erase(local_id); -		delete entry; +			result = CACHE_UPDATE_CHANGED; +		} +	} +	else +	{ +		// we haven't seen this object before +		// Create new entry and add to map +		result = CACHE_UPDATE_ADDED; +		//if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) +		//{ +		//	delete mImpl->mCacheMap.begin()->second ; +		//	mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); +		//	result = CACHE_UPDATE_REPLACED; +		// +		//}  		entry = new LLVOCacheEntry(local_id, crc, dp); +  		mImpl->mCacheMap[local_id] = entry; -		return CACHE_UPDATE_CHANGED;  	} -	// we haven't seen this object before - -	// Create new entry and add to map -	eCacheUpdateResult result = CACHE_UPDATE_ADDED; -	if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) +	if(objectp->mDrawable.notNull() && !entry->getEntry())  	{ -		delete mImpl->mCacheMap.begin()->second ; -		mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); -		result = CACHE_UPDATE_REPLACED; -		 +		entry->setOctreeEntry(objectp->mDrawable->getEntry()); +	} +	if(entry->getEntry() && entry->getEntry()->hasDrawable() && entry->isState(LLVOCacheEntry::INACTIVE)) +	{ +		addActiveCacheEntry(entry);  	} -	entry = new LLVOCacheEntry(local_id, crc, dp); -	mImpl->mCacheMap[local_id] = entry;  	return result;  } +LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id) +{ +	LLVOCacheEntry* entry = getCacheEntry(local_id); +	removeFromVOCacheTree(entry); + +	return entry; +} + +LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id) +{ +	LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.find(local_id); +	if(iter != mImpl->mCacheMap.end()) +	{ +		return iter->second; +	} +	return NULL; +} +  // Get data packer for this object, if we have cached data  // AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) +bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)  {  	//llassert(mCacheLoaded);  This assert failes often, changing to early-out -- davep, 2010/10/18 -	LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); +	LLVOCacheEntry* entry = getCacheEntry(local_id);  	if (entry)  	{ @@ -1244,24 +1733,31 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)  		{  			// Record a hit  			entry->recordHit(); -		cache_miss_type = CACHE_MISS_TYPE_NONE; -			return entry->getDP(crc); +			cache_miss_type = CACHE_MISS_TYPE_NONE; + +			if(entry->getGroup() || !entry->isState(LLVOCacheEntry::INACTIVE)) +			{ +				return true; +			} + +			addVisibleCacheEntry(entry); +			return true;  		}  		else  		{  			// llinfos << "CRC miss for " << local_id << llendl; -		cache_miss_type = CACHE_MISS_TYPE_CRC; +			cache_miss_type = CACHE_MISS_TYPE_CRC;  			mCacheMissCRC.put(local_id);  		}  	}  	else  	{  		// llinfos << "Cache miss for " << local_id << llendl; -	cache_miss_type = CACHE_MISS_TYPE_FULL; +		cache_miss_type = CACHE_MISS_TYPE_FULL;  		mCacheMissFull.put(local_id);  	} -	return NULL; +	return false;  }  void LLViewerRegion::addCacheMissFull(const U32 local_id) @@ -1784,9 +2280,18 @@ void LLViewerRegion::logActiveCapabilities() const  LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type)  { -	if (type < mImpl->mObjectPartition.size()) +	if (type < mImpl->mObjectPartition.size() && type < PARTITION_VO_CACHE) +	{ +		return (LLSpatialPartition*)mImpl->mObjectPartition[type]; +	} +	return NULL; +} + +LLVOCachePartition* LLViewerRegion::getVOCachePartition() +{ +	if(PARTITION_VO_CACHE < mImpl->mObjectPartition.size())  	{ -		return mImpl->mObjectPartition[type]; +		return (LLVOCachePartition*)mImpl->mObjectPartition[PARTITION_VO_CACHE];  	}  	return NULL;  } diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 756c0dc61f..9252923aa3 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -65,8 +65,11 @@ class LLDataPacker;  class LLDataPackerBinaryBuffer;  class LLHost;  class LLBBox; - +class LLSpatialGroup; +class LLDrawable;  class LLViewerRegionImpl; +class LLviewerOctreeGroup; +class LLVOCachePartition;  class LLViewerRegion: public LLCapabilityProvider // implements this interface  { @@ -83,7 +86,8 @@ public:  		PARTITION_GRASS,  		PARTITION_VOLUME,  		PARTITION_BRIDGE, -		PARTITION_HUD_PARTICLE, +		PARTITION_HUD_PARTICLE,		 +		PARTITION_VO_CACHE,  		PARTITION_NONE,  		NUM_PARTITIONS  	} eObjectPartitions; @@ -215,6 +219,12 @@ public:  	F32	getWidth() const						{ return mWidth; }  	BOOL idleUpdate(F32 max_update_time); +	void addVisibleGroup(LLviewerOctreeGroup* group); +	void addVisibleCacheEntry(LLVOCacheEntry* entry); +	void addActiveCacheEntry(LLVOCacheEntry* entry); +	void removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep);	 +	void killCacheEntry(U32 local_id); //physically delete the cache entry	 +	void clearVisibleGroup(LLviewerOctreeGroup* group);  	// Like idleUpdate, but forces everything to complete regardless of  	// how long it takes. @@ -304,8 +314,9 @@ public:  	} eCacheUpdateResult;  	// handle a full update message -	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); -	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type); +	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);	 +	LLVOCacheEntry* getCacheEntryForOctree(U32 local_id); +	bool probeCache(U32 local_id, U32 crc, U8 &cache_miss_type);  	void requestCacheMisses();  	void addCacheMissFull(const U32 local_id); @@ -321,7 +332,9 @@ public:      virtual std::string getDescription() const;  	std::string getHttpUrl() const { return mHttpUrl ;} +	U32 getNumOfActiveCachedObjects() const;  	LLSpatialPartition* getSpatialPartition(U32 type); +	LLVOCachePartition* getVOCachePartition();  	bool objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const;  	bool childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const; @@ -330,6 +343,19 @@ public:  	void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions );  	void getNeighboringRegionsStatus( std::vector<S32>& regions ); +private: +	void addToVOCacheTree(LLVOCacheEntry* entry); +	LLViewerObject* addNewObject(LLVOCacheEntry* entry); +	void killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list); +	LLVOCacheEntry* getCacheEntry(U32 local_id); +	void removeFromVOCacheTree(LLVOCacheEntry* entry); +	void replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry); +	void killCacheEntry(LLVOCacheEntry* entry); //physically delete the cache entry	 + +	F32 killInvisibleObjects(F32 max_time); +	F32 createVisibleObjects(F32 max_time); +	F32 updateVisibleEntries(F32 max_time); //update visible entries +  public:  	struct CompareDistance  	{ @@ -363,6 +389,8 @@ public:  	LLDynamicArray<U32> mMapAvatars;  	LLDynamicArray<LLUUID> mMapAvatarIDs; +	static LLViewerRegion* sCurRegionp; +	static BOOL sVOCacheCullingEnabled; //vo cache culling enabled or not.  private:  	LLViewerRegionImpl * mImpl; @@ -406,18 +434,17 @@ private:  	// Maps local ids to cache entries.  	// Regions can have order 10,000 objects, so assume  	// a structure of size 2^14 = 16,000 -	BOOL									mCacheLoaded; -	BOOL                                    mCacheDirty; +	BOOL	mCacheLoaded; +	BOOL    mCacheDirty; +	BOOL	mAlive;					// can become false if circuit disconnects +	BOOL	mCapabilitiesReceived; +	BOOL    mReleaseNotesRequested; +	BOOL    mDead;  //if true, this region is in the process of deleting.  	LLDynamicArray<U32>						mCacheMissFull;  	LLDynamicArray<U32>						mCacheMissCRC; - -	bool	mAlive;					// can become false if circuit disconnects -	bool	mCapabilitiesReceived; -	caps_received_signal_t mCapabilitiesReceivedSignal; - -	BOOL mReleaseNotesRequested; +	caps_received_signal_t mCapabilitiesReceivedSignal;		  	LLSD mSimulatorFeatures;  }; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 4b0e0598f6..1aa36eafee 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -78,6 +78,8 @@ LLGLSLShader	gGlowCombineProgram;  LLGLSLShader	gSplatTextureRectProgram;  LLGLSLShader	gGlowCombineFXAAProgram;  LLGLSLShader	gTwoTextureAddProgram; +LLGLSLShader	gTwoTextureCompareProgram; +LLGLSLShader	gOneTextureFilterProgram;  LLGLSLShader	gOneTextureNoColorProgram;  LLGLSLShader	gDebugProgram;  LLGLSLShader	gClipProgram; @@ -672,6 +674,8 @@ void LLViewerShaderMgr::unloadShaders()  	gSplatTextureRectProgram.unload();  	gGlowCombineFXAAProgram.unload();  	gTwoTextureAddProgram.unload(); +	gTwoTextureCompareProgram.unload(); +	gOneTextureFilterProgram.unload();  	gOneTextureNoColorProgram.unload();  	gSolidColorProgram.unload(); @@ -2708,6 +2712,37 @@ BOOL LLViewerShaderMgr::loadShadersInterface()  	if (success)  	{ +		gTwoTextureCompareProgram.mName = "Two Texture Compare Shader"; +		gTwoTextureCompareProgram.mShaderFiles.clear(); +		gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareV.glsl", GL_VERTEX_SHADER_ARB)); +		gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareF.glsl", GL_FRAGMENT_SHADER_ARB)); +		gTwoTextureCompareProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; +		success = gTwoTextureCompareProgram.createShader(NULL, NULL); +		if (success) +		{ +			gTwoTextureCompareProgram.bind(); +			gTwoTextureCompareProgram.uniform1i("tex0", 0); +			gTwoTextureCompareProgram.uniform1i("tex1", 1); +		} +	} + +	if (success) +	{ +		gOneTextureFilterProgram.mName = "One Texture Filter Shader"; +		gOneTextureFilterProgram.mShaderFiles.clear(); +		gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterV.glsl", GL_VERTEX_SHADER_ARB)); +		gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterF.glsl", GL_FRAGMENT_SHADER_ARB)); +		gOneTextureFilterProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; +		success = gOneTextureFilterProgram.createShader(NULL, NULL); +		if (success) +		{ +			gOneTextureFilterProgram.bind(); +			gOneTextureFilterProgram.uniform1i("tex0", 0); +		} +	} + +	if (success) +	{  		gOneTextureNoColorProgram.mName = "One Texture No Color Shader";  		gOneTextureNoColorProgram.mShaderFiles.clear();  		gOneTextureNoColorProgram.mShaderFiles.push_back(make_pair("interface/onetexturenocolorV.glsl", GL_VERTEX_SHADER_ARB)); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index d6dd645e8c..3e7c615f23 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -233,7 +233,11 @@ extern LLGLSLShader			gAlphaMaskProgram;  //output tex0[tc0] + tex1[tc1]  extern LLGLSLShader			gTwoTextureAddProgram; -						 +//output tex0[tc0] - tex1[tc1] +extern LLGLSLShader			gTwoTextureCompareProgram; +//discard some fragments based on user-set color tolerance +extern LLGLSLShader			gOneTextureFilterProgram; +  extern LLGLSLShader			gOneTextureNoColorProgram;  //object shaders diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index cdb7bde123..482f6a77a3 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -223,7 +223,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval )  		}  		else  		{ -			llwarns << "Couldn't open " << STATS_FILE_NAME << " for logging." << llendl; +			//llwarns << "Couldn't open " << STATS_FILE_NAME << " for logging." << llendl;  			return;  		}  	} diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 1ffa83c529..76210563bb 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -966,6 +966,12 @@ void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw)  	//nothing here.  } +BOOL LLViewerTexture::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ +	llassert(mGLTexturep.notNull()) ; +	return mGLTexturep->setSubImageFromFrameBuffer(fb_x, fb_y, x_pos, y_pos, width, height); +} +  void LLViewerTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes)  {  	llassert(mGLTexturep.notNull()) ; diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 837d4b21a2..0a9778ce76 100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -212,6 +212,7 @@ public:  	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLViewerTexture::OTHER);  	virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ; +	BOOL       setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);  	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option);  	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);  	void       setAddressMode(LLTexUnit::eTextureAddressMode mode); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f349714556..1d43f96fb7 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -102,6 +102,7 @@  #include "lldebugmessagebox.h"  #include "llsdutil.h" +#include "llscenemonitor.h"  extern F32 SPEED_ADJUST_MAX;  extern F32 SPEED_ADJUST_MAX_SEC; @@ -771,6 +772,11 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mLastPelvisToFoot = 0.0f;  	mPelvisFixup = 0.0f;  	mLastPelvisFixup = 0.0f; + +	if(LLSceneMonitor::getInstance()->isEnabled()) +	{ +		LLSceneMonitor::getInstance()->freezeAvatar((LLCharacter*)this); +	}  }  std::string LLVOAvatar::avString() const diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 7c20e8eae7..cd033c84bf 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -808,8 +808,10 @@ U32  LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys,  		updateMeshTextures();  		// unpack the texture UUIDs to the texture slots -		retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); - +		if(mesgsys != NULL) +		{ +			retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); +		}  		// need to trigger a few operations to get the avatar to use the new bakes  		for (U32 i = 0; i < mBakedTextureDatas.size(); i++)  		{ diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 7db19c5c1b..86cfbb1d74 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -29,6 +29,10 @@  #include "llerror.h"  #include "llregionhandle.h"  #include "llviewercontrol.h" +#include "llviewerobjectlist.h" +#include "lldrawable.h" +#include "llviewerregion.h" +#include "pipeline.h"  BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes)   { @@ -46,12 +50,16 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)  //---------------------------------------------------------------------------  LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp) -	: +	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),  	mLocalID(local_id),  	mCRC(crc),  	mHitCount(0),  	mDupeCount(0), -	mCRCChangeCount(0) +	mCRCChangeCount(0), +	mState(INACTIVE), +	mRepeatedVisCounter(0), +	mVisFrameRange(64), +	mSceneContrib(0.f)  {  	mBuffer = new U8[dp.getBufferSize()];  	mDP.assignBuffer(mBuffer, dp.getBufferSize()); @@ -59,24 +67,35 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &  }  LLVOCacheEntry::LLVOCacheEntry() -	: +	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),  	mLocalID(0),  	mCRC(0),  	mHitCount(0),  	mDupeCount(0),  	mCRCChangeCount(0), -	mBuffer(NULL) +	mBuffer(NULL), +	mState(INACTIVE), +	mRepeatedVisCounter(0), +	mVisFrameRange(64), +	mSceneContrib(0.f)  {  	mDP.assignBuffer(mBuffer, 0);  }  LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) -	: mBuffer(NULL) +	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),  +	mBuffer(NULL), +	mState(INACTIVE), +	mRepeatedVisCounter(0), +	mVisFrameRange(64), +	mSceneContrib(0.f)  {  	S32 size = -1;  	BOOL success;  	mDP.assignBuffer(mBuffer, 0); +	setOctreeEntry(NULL); +  	success = check_read(apr_file, &mLocalID, sizeof(U32));  	if(success)  	{ @@ -96,6 +115,36 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)  	}  	if(success)  	{ +		success = check_read(apr_file, &mState, sizeof(U32)); +	} +	if(success) +	{ +		F32 ext[8]; +		success = check_read(apr_file, (void*)ext, sizeof(F32) * 8); + +		LLVector4a exts[2]; +		exts[0].load4a(ext); +		exts[1].load4a(&ext[4]); +	 +		setSpatialExtents(exts[0], exts[1]); +	} +	if(success) +	{ +		LLVector4 pos; +		success = check_read(apr_file, (void*)pos.mV, sizeof(LLVector4)); + +		LLVector4a pos_; +		pos_.load4a(pos.mV); +		setPositionGroup(pos_); +	} +	if(success) +	{ +		F32 rad; +		success = check_read(apr_file, &rad, sizeof(F32)); +		setBinRadius(rad); +	} +	if(success) +	{  		success = check_read(apr_file, &size, sizeof(S32));  		// Corruption in the cache entries @@ -132,32 +181,100 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)  		mDupeCount = 0;  		mCRCChangeCount = 0;  		mBuffer = NULL; +		mEntry = NULL; +		mState = 0;  	}  }  LLVOCacheEntry::~LLVOCacheEntry()  {  	mDP.freeBuffer(); +	//llassert(mState == INACTIVE);  } +//virtual  +void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry) +{ +	if(!entry && mDP.getBufferSize() > 0) +	{ +		LLUUID fullid; +		mDP.reset(); +		mDP.unpackUUID(fullid, "ID"); +		mDP.reset(); -// New CRC means the object has changed. -void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp) +		LLViewerObject* obj = gObjectList.findObject(fullid); +		if(obj && obj->mDrawable) +		{ +			entry = obj->mDrawable->getEntry(); +		} +	} + +	LLViewerOctreeEntryData::setOctreeEntry(entry); +} + +void LLVOCacheEntry::copyTo(LLVOCacheEntry* new_entry)  { -	if (  (mCRC != crc) -		||(mDP.getBufferSize() == 0)) +	//copy LLViewerOctreeEntry +	if(mEntry.notNull())  	{ -		mCRC = crc; -		mHitCount = 0; -		mCRCChangeCount++; +		new_entry->setOctreeEntry(mEntry); +		mEntry = NULL; +	} + +	//copy children +	S32 num_children = getNumOfChildren(); +	for(S32 i = 0; i < num_children; i++) +	{ +		new_entry->addChild(getChild(i)); +	} +} + +void LLVOCacheEntry::setState(U32 state) +{ +	mState &= 0xffff0000; //clear the low 16 bits +	state &= 0x0000ffff;  //clear the high 16 bits; +	mState |= state; -		mDP.freeBuffer(); -		mBuffer = new U8[dp.getBufferSize()]; -		mDP.assignBuffer(mBuffer, dp.getBufferSize()); -		mDP = dp; +	if(getState() == ACTIVE) +	{ +		const S32 MIN_REAVTIVE_INTERVAL = 20; +		U32 last_visible = getVisible(); +		 +		setVisible(); + +		if(getVisible() - last_visible < MIN_REAVTIVE_INTERVAL + mVisFrameRange) +		{ +			mRepeatedVisCounter++; +		} +		else +		{ +			mRepeatedVisCounter = 0; +			mVisFrameRange = 64; +		} + +		if(mRepeatedVisCounter > 2)  +		{ +			//if repeatedly becomes visible immediately after invisible, enlarge the visible frame range + +			mRepeatedVisCounter = 0; +			mVisFrameRange *= 2; +		}  	}  } +//virtual  +S32  LLVOCacheEntry::getMinVisFrameRange()const +{ +	return mVisFrameRange; +} + +void LLVOCacheEntry::addChild(LLVOCacheEntry* entry) +{ +	llassert(entry != NULL); + +	mChildrenList.push_back(entry); +} +	  LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)  {  	if (  (mCRC != crc) @@ -170,6 +287,16 @@ LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)  	return &mDP;  } +LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP() +{ +	if (mDP.getBufferSize() == 0) +	{ +		//llinfos << "Not getting cache entry, invalid!" << llendl; +		return NULL; +	} +	 +	return &mDP; +}  void LLVOCacheEntry::recordHit()  { @@ -189,6 +316,11 @@ void LLVOCacheEntry::dump() const  BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const  { +	if(!mEntry) +	{ +		return FALSE; +	} +  	BOOL success;  	success = check_write(apr_file, (void*)&mLocalID, sizeof(U32));  	if(success) @@ -209,6 +341,33 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const  	}  	if(success)  	{ +		U32 state = mState & 0xffff0000; //only store the high 16 bits. +		success = check_write(apr_file, (void*)&state, sizeof(U32)); +	} +	if(success) +	{ +		const LLVector4a* exts = getSpatialExtents() ; +		LLVector4 ext(exts[0][0], exts[0][1], exts[0][2], exts[0][3]); +		success = check_write(apr_file, ext.mV, sizeof(LLVector4));		 +		if(success) +		{ +			ext.set(exts[1][0], exts[1][1], exts[1][2], exts[1][3]); +			success = check_write(apr_file, ext.mV, sizeof(LLVector4));		 +		} +	} +	if(success) +	{ +		const LLVector4a pos_ = getPositionGroup() ; +		LLVector4 pos(pos_[0], pos_[1], pos_[2], pos_[3]); +		success = check_write(apr_file, pos.mV, sizeof(LLVector4));		 +	} +	if(success) +	{ +		F32 rad = getBinRadius(); +		success = check_write(apr_file, (void*)&rad, sizeof(F32)); +	} +	if(success) +	{  		S32 size = mDP.getBufferSize();  		success = check_write(apr_file, (void*)&size, sizeof(S32)); @@ -221,6 +380,121 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const  	return success ;  } +void LLVOCacheEntry::calcSceneContribution(const LLVector3& camera_origin, bool needs_update, U32 last_update) +{ +	if(!needs_update && getVisible() >= last_update) +	{ +		return; //no need to update +	} + +	const LLVector4a& center = getPositionGroup(); +	 +	LLVector4a origin; +	origin.load3(camera_origin.mV); + +	LLVector4a lookAt; +	lookAt.setSub(center, origin); +	F32 squared_dist = lookAt.dot3(lookAt).getF32(); + +	F32 rad = getBinRadius(); +	mSceneContrib = rad * rad / squared_dist; + +	setVisible(); +} + +//------------------------------------------------------------------- +//LLVOCachePartition +//------------------------------------------------------------------- +LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp) +{ +	mRegionp = regionp; +	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE; +	mVisitedTime = 0; + +	new LLviewerOctreeGroup(mOctree); +} + +void LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry) +{ +	llassert(entry->hasVOCacheEntry()); + +	mOctree->insert(entry); +} +	 +void LLVOCachePartition::removeEntry(LLViewerOctreeEntry* entry) +{ +	entry->getVOCacheEntry()->setGroup(NULL); + +	llassert(!entry->getGroup()); +} +	 +class LLVOCacheOctreeCull : public LLViewerOctreeCull +{ +public: +	LLVOCacheOctreeCull(LLCamera* camera, LLViewerRegion* regionp, const LLVector3& shift) : LLViewerOctreeCull(camera), mRegionp(regionp)  +	{ +		mLocalShift = shift; +	} + +	virtual S32 frustumCheck(const LLviewerOctreeGroup* group) +	{ +		//S32 res = AABBInRegionFrustumGroupBounds(group); +		 +		S32 res = AABBInRegionFrustumNoFarClipGroupBounds(group); +		if (res != 0) +		{ +			res = llmin(res, AABBRegionSphereIntersectGroupExtents(group, mLocalShift)); +		} +		return res; +	} + +	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group) +	{ +		//S32 res = AABBInRegionFrustumObjectBounds(group); + +		S32 res = AABBInRegionFrustumNoFarClipObjectBounds(group); +		if (res != 0) +		{ +			res = llmin(res, AABBRegionSphereIntersectObjectExtents(group, mLocalShift)); +		} +		return res; +	} + +	virtual void processGroup(LLviewerOctreeGroup* base_group) +	{ +		mRegionp->addVisibleGroup(base_group); +	} + +private: +	LLViewerRegion* mRegionp; +	LLVector3       mLocalShift; //shift vector from agent space to local region space. +}; + +S32 LLVOCachePartition::cull(LLCamera &camera) +{ +	if(!LLViewerRegion::sVOCacheCullingEnabled) +	{ +		return 0; +	} + +	if(mVisitedTime == LLViewerOctreeEntryData::getCurrentFrame()) +	{ +		return 0; //already visited. +	} +	mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame(); + +	((LLviewerOctreeGroup*)mOctree->getListener(0))->rebound(); + +	//localize the camera +	LLVector3 region_agent = mRegionp->getOriginAgent(); +	camera.calcRegionFrustumPlanes(region_agent); + +	LLVOCacheOctreeCull culler(&camera, mRegionp, region_agent); +	culler.traverse(mOctree); + +	return 0; +} +  //-------------------------------------------------------------------  //LLVOCache  //------------------------------------------------------------------- @@ -625,11 +899,10 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca  				{  					for (S32 i = 0; i < num_entries; i++)  					{ -						LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file); +						LLPointer<LLVOCacheEntry> entry = new LLVOCacheEntry(&apr_file);  						if (!entry->getLocalID())  						{  							llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; -							delete entry ;  							success = false ;  							break ;  						} diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 14e3b4c793..c631e12739 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -31,34 +31,95 @@  #include "lldatapacker.h"  #include "lldlinked.h"  #include "lldir.h" - +#include "llvieweroctree.h"  //---------------------------------------------------------------------------  // Cache entries  class LLVOCacheEntry; +class LLCamera; -class LLVOCacheEntry +class LLVOCacheEntry : public LLViewerOctreeEntryData  {  public: +	enum +	{ +		INACTIVE = 0x00000000,     //not visible +		IN_QUEUE = 0x00000001,     //in visible queue, object to be created +		WAITING  = 0x00000002,     //object creation request sent +		ACTIVE   = 0x00000004      //object created, and in rendering pipeline. +	}; + +	enum +	{ +		ADD_TO_CACHE_TREE = 0x00010000, //has parent +	}; + +	struct CompareVOCacheEntry +	{ +		bool operator()(const LLVOCacheEntry* const& lhs, const LLVOCacheEntry* const& rhs) +		{ +			F32 lpa = lhs->getSceneContribution(); +			F32 rpa = rhs->getSceneContribution(); + +			//larger pixel area first +			if(lpa > rpa)		 +			{ +				return true; +			} +			else if(lpa < rpa) +			{ +				return false; +			} +			else +			{ +				return lhs < rhs; +			}			 +		} +	}; +protected: +	~LLVOCacheEntry(); +public:  	LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp);  	LLVOCacheEntry(LLAPRFile* apr_file); -	LLVOCacheEntry(); -	~LLVOCacheEntry(); - +	LLVOCacheEntry();	 + +	void setState(U32 state); +	void clearState(U32 state) {mState &= ~state;} +	void addState(U32 state)   {mState |= state;} +	bool isState(U32 state)    {return (mState & 0xffff) == state;} +	bool hasState(U32 state)   {return mState & state;} +	U32  getState() const      {return (mState & 0xffff);} +	U32  getFullState() const  {return mState;} +	  	U32 getLocalID() const			{ return mLocalID; }  	U32 getCRC() const				{ return mCRC; }  	S32 getHitCount() const			{ return mHitCount; }  	S32 getCRCChangeCount() const	{ return mCRCChangeCount; } +	S32 getMinVisFrameRange()const;	 + +	void calcSceneContribution(const LLVector3& camera_origin, bool needs_update, U32 last_update); +	void setSceneContribution(F32 scene_contrib) {mSceneContrib = scene_contrib;} +	F32 getSceneContribution() const             { return mSceneContrib;}  	void dump() const;  	BOOL writeToFile(LLAPRFile* apr_file) const; -	void assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp);  	LLDataPackerBinaryBuffer *getDP(U32 crc); +	LLDataPackerBinaryBuffer *getDP();  	void recordHit();  	void recordDupe() { mDupeCount++; } +	 +	void copyTo(LLVOCacheEntry* new_entry); //copy variables  +	/*virtual*/ void setOctreeEntry(LLViewerOctreeEntry* entry); + +	void addChild(LLVOCacheEntry* entry); +	LLVOCacheEntry* getChild(S32 i) {return mChildrenList[i];} +	S32  getNumOfChildren()         {return mChildrenList.size();} +	void clearChildrenList()        {mChildrenList.clear();}  public: -	typedef std::map<U32, LLVOCacheEntry*>	vocache_entry_map_t; +	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	   vocache_entry_map_t; +	typedef std::set<LLVOCacheEntry*>                      vocache_entry_set_t; +	typedef std::set<LLVOCacheEntry*, CompareVOCacheEntry> vocache_entry_priority_list_t;	  protected:  	U32							mLocalID; @@ -68,6 +129,25 @@ protected:  	S32							mCRCChangeCount;  	LLDataPackerBinaryBuffer	mDP;  	U8							*mBuffer; + +	F32                         mSceneContrib; //projected scene contributuion of this object. +	S32                         mVisFrameRange; +	S32                         mRepeatedVisCounter; //number of repeatedly visible within a short time. +	U32                         mState; //high 16 bits reserved for special use. +	std::vector<LLVOCacheEntry*> mChildrenList; //children entries in a linked set. +}; + +class LLVOCachePartition : public LLViewerOctreePartition +{ +public: +	LLVOCachePartition(LLViewerRegion* regionp); + +	void addEntry(LLViewerOctreeEntry* entry); +	void removeEntry(LLViewerOctreeEntry* entry); +	/*virtual*/ S32 cull(LLCamera &camera); + +private: +	U32 mVisitedTime;  };  // diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 4dca87652d..d378ed2577 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -603,8 +603,8 @@ U32 LLVOGrass::getPartitionType() const  	return LLViewerRegion::PARTITION_GRASS;  } -LLGrassPartition::LLGrassPartition() -: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB) +LLGrassPartition::LLGrassPartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB, regionp)  {  	mDrawableType = LLPipeline::RENDER_TYPE_GRASS;  	mPartitionType = LLViewerRegion::PARTITION_GRASS; @@ -624,9 +624,9 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count  	LLViewerCamera* camera = LLViewerCamera::getInstance();  	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  	{ -		LLDrawable* drawablep = *i; +		LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); -		if (drawablep->isDead()) +		if (!drawablep || drawablep->isDead())  		{  			continue;  		} @@ -738,8 +738,10 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group)  			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(),   				//facep->getTexture(),  				buffer, fullbright);  -			info->mExtents[0] = group->mObjectExtents[0]; -			info->mExtents[1] = group->mObjectExtents[1]; + +			const LLVector4a* exts = group->getObjectExtents(); +			info->mExtents[0] = exts[0]; +			info->mExtents[1] = exts[1];  			info->mVSize = vsize;  			draw_vec.push_back(info);  			//for alpha sorting diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index fa34a6f1f5..29c78f85f2 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -489,8 +489,8 @@ U32 LLVOPartGroup::getPartitionType() const  	return LLViewerRegion::PARTITION_PARTICLE;   } -LLParticlePartition::LLParticlePartition() -: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB) +LLParticlePartition::LLParticlePartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB, regionp)  {  	mRenderPass = LLRenderPass::PASS_ALPHA;  	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES; @@ -499,8 +499,8 @@ LLParticlePartition::LLParticlePartition()  	mLODPeriod = 1;  } -LLHUDParticlePartition::LLHUDParticlePartition() : -	LLParticlePartition() +LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) : +	LLParticlePartition(regionp)  {  	mDrawableType = LLPipeline::RENDER_TYPE_HUD_PARTICLES;  	mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE; @@ -510,7 +510,7 @@ static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VBO("Particle VBO");  void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)  { -	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) +	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))  	{  		return;  	} @@ -558,9 +558,9 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co  	LLViewerCamera* camera = LLViewerCamera::getInstance();  	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  	{ -		LLDrawable* drawablep = *i; +		LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); -		if (drawablep->isDead()) +		if (!drawablep || drawablep->isDead())  		{  			continue;  		} @@ -699,8 +699,10 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)  			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(),   				//facep->getTexture(),  				buffer, fullbright);  -			info->mExtents[0] = group->mObjectExtents[0]; -			info->mExtents[1] = group->mObjectExtents[1]; + +			const LLVector4a* exts = group->getObjectExtents(); +			info->mExtents[0] = exts[0]; +			info->mExtents[1] = exts[1];  			info->mVSize = vsize;  			draw_vec.push_back(info);  			//for alpha sorting diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index cb905d02da..d5b3f2fd14 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -1058,8 +1058,8 @@ U32 LLVOSurfacePatch::getPartitionType() const  	return LLViewerRegion::PARTITION_TERRAIN;   } -LLTerrainPartition::LLTerrainPartition() -: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB) +LLTerrainPartition::LLTerrainPartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB, regionp)  {  	mOcclusionEnabled = FALSE;  	mInfiniteFarClip = TRUE; diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 6687ce432f..fe1ef10f7f 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -1290,8 +1290,8 @@ U32 LLVOTree::getPartitionType() const  	return LLViewerRegion::PARTITION_TREE;   } -LLTreePartition::LLTreePartition() -: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB) +LLTreePartition::LLTreePartition(LLViewerRegion* regionp) +: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB, regionp)  {  	mDrawableType = LLPipeline::RENDER_TYPE_TREE;  	mPartitionType = LLViewerRegion::PARTITION_TREE; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 78ccbd90c9..2056aed0ad 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3933,8 +3933,8 @@ U32 LLVOVolume::getPartitionType() const  	return LLViewerRegion::PARTITION_VOLUME;  } -LLVolumePartition::LLVolumePartition() -: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB) +LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp)  {  	mLODPeriod = 32;  	mDepthMask = FALSE; @@ -3944,8 +3944,8 @@ LLVolumePartition::LLVolumePartition()  	mBufferUsage = GL_DYNAMIC_DRAW_ARB;  } -LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep) -: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK) +LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep, LLViewerRegion* regionp) +: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp)  {  	mDepthMask = FALSE;  	mLODPeriod = 32; @@ -4167,9 +4167,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	group->mLastUpdateViewAngle = group->mViewAngle; -	if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY)) +	if (!group->hasState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY))  	{ -		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) +		if (group->hasState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)  		{  			rebuildMesh(group);  		} @@ -4207,7 +4207,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	group->mSurfaceArea = 0;  	//cache object box size since it might be used for determining visibility -	group->mObjectBoxSize = group->mObjectBounds[1].getLength3().getF32(); +	const LLVector4a* bounds = group->getObjectBounds(); +	group->mObjectBoxSize = bounds[1].getLength3().getF32();  	group->clearDrawMap(); @@ -4234,9 +4235,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  		//get all the faces into a list  		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)  		{ -			LLDrawable* drawablep = *drawable_iter; +			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); -			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) +			if (!drawablep || drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )  			{  				continue;  			} @@ -4640,8 +4641,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  		//drawables have been rebuilt, clear rebuild status  		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)  		{ -			LLDrawable* drawablep = *drawable_iter; -			drawablep->clearState(LLDrawable::REBUILD_ALL); +			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); +			if(drawablep) +			{ +				drawablep->clearState(LLDrawable::REBUILD_ALL); +			}  		}  	} @@ -4667,7 +4671,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  {  	llassert(group); -	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) +	if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))  	{  		LLFastTimer ftm(FTM_REBUILD_VOLUME_VB);  		LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers @@ -4680,9 +4684,9 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)  		{ -			LLDrawable* drawablep = *drawable_iter; +			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); -			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) +			if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )  			{  				LLVOVolume* vobj = drawablep->getVOVolume();  				vobj->preRebuild(); @@ -4748,7 +4752,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  			llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ;   			for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)  			{ -				LLDrawable* drawablep = *drawable_iter; +				LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); +				if(!drawablep) +				{ +					continue; +				}  				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)  				{  					LLFace* face = drawablep->getFace(i); @@ -5221,9 +5229,9 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun  	for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)  	{ -		LLDrawable* drawablep = *drawable_iter; +		LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); -		if (drawablep->isDead()) +		if (!drawablep || drawablep->isDead())  		{  			continue;  		} @@ -5261,7 +5269,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun  	group->mBufferUsage = usage;  } -LLHUDPartition::LLHUDPartition() +LLHUDPartition::LLHUDPartition(LLViewerRegion* regionp) : LLBridgePartition(regionp)  {  	mPartitionType = LLViewerRegion::PARTITION_HUD;  	mDrawableType = LLPipeline::RENDER_TYPE_HUD; diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index e8a1c3d1d6..50e7ed7bb5 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -298,15 +298,15 @@ U32 LLVOVoidWater::getPartitionType() const  	return LLViewerRegion::PARTITION_VOIDWATER;  } -LLWaterPartition::LLWaterPartition() -: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB) +LLWaterPartition::LLWaterPartition(LLViewerRegion* regionp) +: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB, regionp)  {  	mInfiniteFarClip = TRUE;  	mDrawableType = LLPipeline::RENDER_TYPE_WATER;  	mPartitionType = LLViewerRegion::PARTITION_WATER;  } -LLVoidWaterPartition::LLVoidWaterPartition() +LLVoidWaterPartition::LLVoidWaterPartition(LLViewerRegion* regionp) : LLWaterPartition(regionp)  {  	mOcclusionEnabled = FALSE;  	mDrawableType = LLPipeline::RENDER_TYPE_VOIDWATER; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 126dc59929..06e2302b0b 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -55,7 +55,7 @@  #include "message.h"  #include "pipeline.h"  #include "llappviewer.h"		// for do_disconnect() - +#include "llscenemonitor.h"  #include <deque>  #include <queue>  #include <map> @@ -110,6 +110,7 @@ LLWorld::LLWorld() :  	gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);  	mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); +	LLViewerRegion::sVOCacheCullingEnabled = (BOOL)gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");  } @@ -133,6 +134,11 @@ void LLWorld::destroyClass()  	{  		mEdgeWaterObjects[i] = NULL;  	} + +	//make all visible drawbles invisible. +	LLDrawable::incrementVisible(); + +	LLSceneMonitor::getInstance()->destroyClass();  } @@ -599,7 +605,8 @@ void LLWorld::updateVisibilities()  		if (part)  		{  			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); -			if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1])) +			const LLVector4a* bounds = group->getBounds(); +			if (LLViewerCamera::getInstance()->AABBInFrustum(bounds[0], bounds[1]))  			{  				mCulledRegionList.erase(curiter);  				mVisibleRegionList.push_back(regionp); @@ -622,7 +629,8 @@ void LLWorld::updateVisibilities()  		if (part)  		{  			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); -			if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1])) +			const LLVector4a* bounds = group->getBounds(); +			if (LLViewerCamera::getInstance()->AABBInFrustum(bounds[0], bounds[1]))  			{  				regionp->calculateCameraDistance();  				regionp->getLand().updatePatchVisibilities(gAgent); @@ -644,8 +652,8 @@ void LLWorld::updateVisibilities()  void LLWorld::updateRegions(F32 max_update_time)  {  	LLTimer update_timer; -	BOOL did_one = FALSE; -	 +	BOOL did_one = FALSE;	 +  	// Perform idle time updates for the regions (and associated surfaces)  	for (region_list_t::iterator iter = mRegionList.begin();  		 iter != mRegionList.end(); ++iter) @@ -660,6 +668,13 @@ void LLWorld::updateRegions(F32 max_update_time)  			did_one = TRUE;  		}  	} + +	mNumOfActiveCachedObjects = 0; +	for (region_list_t::iterator iter = mRegionList.begin(); +		 iter != mRegionList.end(); ++iter) +	{ +		mNumOfActiveCachedObjects += (*iter)->getNumOfActiveCachedObjects(); +	}  }  void LLWorld::updateParticles() diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index f350009d10..8187142b2b 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -144,6 +144,7 @@ public:  	U64 getSpaceTimeUSec() const;  	void getInfo(LLSD& info); +	U32  getNumOfActiveCachedObjects() const {return mNumOfActiveCachedObjects;}  public:  	typedef std::list<LLViewerRegion*> region_list_t; @@ -181,7 +182,7 @@ private:  	S32 mLastPacketsIn;  	S32 mLastPacketsOut;  	S32 mLastPacketsLost; - +	U32 mNumOfActiveCachedObjects;  	U64 mSpaceTimeUSec;  	BOOL mClassicCloudsEnabled; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b5a81c9fcd..8d3075d1e1 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -86,6 +86,7 @@  #include "llviewerregion.h" // for audio debugging.  #include "llviewerwindow.h" // For getSpinAxis  #include "llvoavatarself.h" +#include "llvocache.h"  #include "llvoground.h"  #include "llvosky.h"  #include "llvotree.h" @@ -111,6 +112,7 @@  #include "llfloaterpathfindingconsole.h"  #include "llfloaterpathfindingcharacters.h"  #include "llpathfindingpathtool.h" +#include "llscenemonitor.h"  #ifdef _DEBUG  // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -1410,18 +1412,18 @@ S32 LLPipeline::setLightingDetail(S32 level)  	return mLightingDetail;  } -class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable> +class LLOctreeDirtyTexture : public OctreeTraveler  {  public:  	const std::set<LLViewerFetchedTexture*>& mTextures;  	LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { } -	virtual void visit(const LLOctreeNode<LLDrawable>* node) +	virtual void visit(const OctreeNode* node)  	{  		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); -		if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty()) +		if (!group->hasState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty())  		{  			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)  			{ @@ -1610,11 +1612,9 @@ void LLPipeline::addPool(LLDrawPool *new_poolp)  void LLPipeline::allocDrawable(LLViewerObject *vobj)  { -	LLDrawable *drawable = new LLDrawable(); +	LLDrawable *drawable = new LLDrawable(vobj);  	vobj->mDrawable = drawable; -	drawable->mVObjp     = vobj; -	  	//encompass completely sheared objects by taking   	//the most extreme point possible (<1,1,0.5>)  	drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length()); @@ -2038,7 +2038,7 @@ void check_references(LLSpatialGroup* group, LLDrawable* drawable)  {  	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  	{ -		if (drawable == *i) +		if (drawable == (LLDrawable*)(*i)->getDrawable())  		{  			llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;  		} @@ -2060,8 +2060,11 @@ void check_references(LLSpatialGroup* group, LLFace* face)  {  	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  	{ -		LLDrawable* drawable = *i; -		check_references(drawable, face); +		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); +		if(drawable) +		{ +			check_references(drawable, face); +		}  	}			  } @@ -2385,6 +2388,13 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl  				}  			}  		} + +		//scan the VO Cache tree +		LLVOCachePartition* vo_part = region->getVOCachePartition(); +		if(vo_part) +		{ +			vo_part->cull(camera); +		}  	}  	if (bound_shader) @@ -2452,14 +2462,15 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)  		return;  	} +	const LLVector4a* bounds = group->getBounds();  	if (sMinRenderSize > 0.f &&  -			llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) +			llmax(llmax(bounds[1][0], bounds[1][1]), bounds[1][2]) < sMinRenderSize)  	{  		return;  	}  	assertInitialized(); -	 +		  	if (!group->mSpatialPartition->mRenderByGroup)  	{ //render by drawable  		sCull->pushDrawableGroup(group); @@ -3041,14 +3052,14 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)  		if (priority)  		{ -			if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) +			if (!group->hasState(LLSpatialGroup::IN_BUILD_Q1))  			{  				llassert_always(!mGroupQ1Locked);  				mGroupQ1.push_back(group);  				group->setState(LLSpatialGroup::IN_BUILD_Q1); -				if (group->isState(LLSpatialGroup::IN_BUILD_Q2)) +				if (group->hasState(LLSpatialGroup::IN_BUILD_Q2))  				{  					LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);  					if (iter != mGroupQ2.end()) @@ -3059,7 +3070,7 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)  				}  			}  		} -		else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) +		else if (!group->hasState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))  		{  			llassert_always(!mGroupQ2Locked);  			mGroupQ2.push_back(group); @@ -3134,7 +3145,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)  			group->setVisible();  			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  			{ -				markVisible(*i, camera); +				markVisible((LLDrawable*)(*i)->getDrawable(), camera);  			}  			if (!sDelayVBUpdate) @@ -3212,7 +3223,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)  		}  	} -	postSort(camera);	 +	postSort(camera); + +	LLSceneMonitor::getInstance()->fetchQueryResult();  }  void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) @@ -3221,8 +3234,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)  	{  		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)  		{ -			LLDrawable* drawablep = *i; -			stateSort(drawablep, camera); +			stateSort((LLDrawable*)(*i)->getDrawable(), camera);  		}  		if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) @@ -3341,7 +3353,10 @@ void forAllDrawables(LLCullResult::sg_iterator begin,  	{  		for (LLSpatialGroup::element_iter j = (*i)->getDataBegin(); j != (*i)->getDataEnd(); ++j)  		{ -			func(*j);	 +			if((*j)->hasDrawable()) +			{ +				func((LLDrawable*)(*j)->getDrawable());	 +			}  		}  	}  } @@ -3569,7 +3584,7 @@ void LLPipeline::postSort(LLCamera& camera)  			continue;  		} -		if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY)) +		if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY))  		{ //no way this group is going to be drawable without a rebuild  			group->rebuildGeom();  		} diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 386d912a2a..8fe955aed8 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1989,6 +1989,16 @@                 function="Advanced.ToggleConsole"                 parameter="scene view" />              </menu_item_check> +            <menu_item_check +                 label="Scene Loading Monitor" +                 name="Scene Loading Monitor"> +              <menu_item_check.on_check +               function="Advanced.CheckConsole" +               parameter="scene monitor" /> +              <menu_item_check.on_click +               function="Advanced.ToggleConsole" +               parameter="scene monitor" /> +            </menu_item_check>              <menu_item_call                enabled="false"                visible="false" | 
