diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 117ccdea336393f9f059f890710e7478389f5a8a..cfe765a1cbdf99cd923139984bd6743617a6d074 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -90,6 +90,7 @@ const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000;
 
 BOOL LLViewerRegion::sVOCacheCullingEnabled = FALSE;
 S32  LLViewerRegion::sLastCameraUpdated = 0;
+S32  LLViewerRegion::sNewObjectCreationThrottle = 0;
 
 typedef std::map<std::string, std::string> CapabilityMap;
 
@@ -372,7 +373,9 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mCapabilitiesReceived(false),
 	mBitsReceived(0.f),
 	mPacketsReceived(0.f),
-	mDead(FALSE)
+	mDead(FALSE),
+	mLastVisitedEntry(NULL),
+	mInvisibilityCheckHistory(-1)
 {
 	mWidth = region_width_meters;
 	mImpl->mOriginGlobal = from_region_handle(handle); 
@@ -968,6 +971,11 @@ void LLViewerRegion::addVisibleGroup(LLviewerOctreeGroup* group)
 	mImpl->mVisibleGroups.insert(group);
 }
 
+U32 LLViewerRegion::getNumOfVisibleGroups() const
+{
+	return mImpl ? mImpl->mVisibleGroups.size() : 0;
+}
+
 void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
 {
 	if(!sVOCacheCullingEnabled)
@@ -1139,7 +1147,7 @@ F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 	return 2.0f * max_time - update_timer.getElapsedTimeF32();
 }
 
-F32 LLViewerRegion::createVisibleObjects(F32 max_time, S32 throttle)
+F32 LLViewerRegion::createVisibleObjects(F32 max_time)
 {
 	if(mDead)
 	{
@@ -1150,6 +1158,7 @@ F32 LLViewerRegion::createVisibleObjects(F32 max_time, S32 throttle)
 		return max_time;
 	}
 
+	S32 throttle = sNewObjectCreationThrottle;
 	LLTimer update_timer;	
 	for(LLVOCacheEntry::vocache_entry_priority_list_t::iterator iter = mImpl->mWaitingList.begin();
 		iter != mImpl->mWaitingList.end(); ++iter)
@@ -1170,9 +1179,7 @@ F32 LLViewerRegion::createVisibleObjects(F32 max_time, S32 throttle)
 }
 
 BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
-{
-	static LLCachedControl<S32> new_object_creation_throttle(gSavedSettings,"NewObjectCreationThrottle");
-
+{	
 	LLTimer update_timer;
 
 	// did_update returns TRUE if we did at least one significant update
@@ -1191,44 +1198,28 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 	if(mImpl->mCacheMap.empty())
 	{
 		return did_update;
-	}
-
-	max_update_time -= update_timer.getElapsedTimeF32();	
+	}	
 	
 	//reset all occluders
 	mImpl->mVOCachePartition->resetOccluders();
 
-	//update the throttling number
-	static S32 throttle = new_object_creation_throttle;
-	if(LLStartUp::getStartupState() < STATE_STARTED || gTeleportDisplay)
-	{
-		throttle = -1; //cancel the throttling
+	max_update_time -= update_timer.getElapsedTimeF32();	
 
+	if(sNewObjectCreationThrottle < 0 && (LLStartUp::getStartupState() < STATE_STARTED || gTeleportDisplay))
+	{
 		//apply octree cullings here to pick up visible objects because rendering pipeline stops view culling at this moment
 		mImpl->mVOCachePartition->cull(*LLViewerCamera::getInstance(), false);
 	}	
-	else if(throttle < 0) //just recoved from the login/teleport screen
-	{
-		if(new_object_creation_throttle > 0)
-		{
-			throttle = 4096; //a big number
-		}
-	}
-	else
-	{
-		throttle = llmax((S32)new_object_creation_throttle, (S32)(throttle >> 1));
-	}
-
-	if(max_update_time < 0.f && throttle > 0 && throttle < new_object_creation_throttle * 2)
+	else if(max_update_time < 0.f)
 	{
 		return did_update;
 	}
 
 	//kill invisible objects
-	max_update_time = killInvisibleObjects(max_update_time, throttle);	
+	max_update_time = killInvisibleObjects(max_update_time);	
 	
 	max_update_time = updateVisibleEntries(max_update_time);
-	createVisibleObjects(max_update_time, throttle);
+	createVisibleObjects(max_update_time);
 
 	mImpl->mWaitingList.clear();
 	mImpl->mVisibleGroups.clear();
@@ -1236,7 +1227,35 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 	return did_update;
 }
 
-F32 LLViewerRegion::killInvisibleObjects(F32 max_time, S32 throttle)
+//update the throttling number for new object creation
+void LLViewerRegion::calcNewObjectCreationThrottle()
+{
+	static LLCachedControl<S32> new_object_creation_throttle(gSavedSettings,"NewObjectCreationThrottle");
+
+	sNewObjectCreationThrottle = new_object_creation_throttle;
+	if(LLStartUp::getStartupState() < STATE_STARTED || gTeleportDisplay)
+	{
+		sNewObjectCreationThrottle = -1; //cancel the throttling		
+	}	
+	else if(sNewObjectCreationThrottle < 0) //just recoved from the login/teleport screen
+	{
+		if(new_object_creation_throttle > 0)
+		{
+			sNewObjectCreationThrottle = 4096; //a big number
+		}
+	}
+	else
+	{
+		sNewObjectCreationThrottle = llmax((S32)new_object_creation_throttle, (S32)(sNewObjectCreationThrottle >> 1));
+	}
+}
+
+BOOL LLViewerRegion::isViewerCameraStatic()
+{
+	return sLastCameraUpdated < LLViewerOctreeEntryData::getCurrentFrame();
+}
+
+F32 LLViewerRegion::killInvisibleObjects(F32 max_time)
 {
 #if 1
 	if(!sVOCacheCullingEnabled)
@@ -1248,12 +1267,16 @@ F32 LLViewerRegion::killInvisibleObjects(F32 max_time, S32 throttle)
 		return max_time;
 	}
 
-	static LLVOCacheEntry* last_visited_entry = NULL;
-
-	const size_t MAX_UPDATE = throttle < 0 ? mImpl->mActiveSet.size() : 64; 
+	size_t max_update = sNewObjectCreationThrottle < 0 ? mImpl->mActiveSet.size() : 64; 
+	if(!mInvisibilityCheckHistory && isViewerCameraStatic())
+	{
+		//history is clean, reduce number of checking
+		max_update = llmax(max_update / 2, (size_t)8);
+	}
+	
 	std::vector<LLDrawable*> delete_list;
-	S32 update_counter = llmin(MAX_UPDATE, mImpl->mActiveSet.size());
-	LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.upper_bound(last_visited_entry);	
+	S32 update_counter = llmin(max_update, mImpl->mActiveSet.size());
+	LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.upper_bound(mLastVisitedEntry);	
 	
 	for(; update_counter > 0; --update_counter, ++iter)
 	{	
@@ -1262,7 +1285,7 @@ F32 LLViewerRegion::killInvisibleObjects(F32 max_time, S32 throttle)
 			iter = mImpl->mActiveSet.begin();
 		}
 
-		if(!(*iter)->isRecentlyVisible() && (*iter)->mLastCameraUpdated != sLastCameraUpdated)
+		if(!(*iter)->isRecentlyVisible() && (*iter)->mLastCameraUpdated < sLastCameraUpdated)
 		{
 			killObject((*iter), delete_list);
 		}
@@ -1270,18 +1293,23 @@ F32 LLViewerRegion::killInvisibleObjects(F32 max_time, S32 throttle)
 
 	if(iter == mImpl->mActiveSet.end())
 	{
-		last_visited_entry = NULL;
+		mLastVisitedEntry = NULL;
 	}
 	else
 	{
-		last_visited_entry = *iter;
+		mLastVisitedEntry = *iter;
 	}
 
-	for(S32 i = 0; i < delete_list.size(); i++)
+	mInvisibilityCheckHistory <<= 2;
+	if(!delete_list.empty())
 	{
-		gObjectList.killObject(delete_list[i]->getVObj());
+		mInvisibilityCheckHistory |= 1;
+		for(S32 i = 0; i < delete_list.size(); i++)
+		{
+			gObjectList.killObject(delete_list[i]->getVObj());
+		}
+		delete_list.clear();
 	}
-	delete_list.clear();
 #endif
 	return max_time;
 }
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index a8e0b7bba9c87d9ac018288aca80c30e63c88e1d..9d2a333b1bd773444050c1bd94471cb33e4dbc43 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -220,6 +220,10 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	// can process the message.
 	static void processRegionInfo(LLMessageSystem* msg, void**);
 
+	//check if the viewer camera is static
+	static BOOL isViewerCameraStatic();
+	static void calcNewObjectCreationThrottle();
+
 	void setCacheID(const LLUUID& id);
 
 	F32	getWidth() const						{ return mWidth; }
@@ -345,6 +349,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
     virtual std::string getDescription() const;
 	std::string getHttpUrl() const { return mHttpUrl ;}
 
+	U32 getNumOfVisibleGroups() const;
 	U32 getNumOfActiveCachedObjects() const;
 	LLSpatialPartition* getSpatialPartition(U32 type);
 	LLVOCachePartition* getVOCachePartition();
@@ -359,7 +364,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	LLViewerRegionImpl * getRegionImplNC() { return mImpl; }
 
 	void removeFromCreatedList(U32 local_id);
-	void addToCreatedList(U32 local_id);
+	void addToCreatedList(U32 local_id);	
 
 private:
 	void addToVOCacheTree(LLVOCacheEntry* entry);
@@ -369,8 +374,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	void replaceVisibleCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry);
 	void killCacheEntry(LLVOCacheEntry* entry); //physically delete the cache entry	
 
-	F32 killInvisibleObjects(F32 max_time, S32 throttle);
-	F32 createVisibleObjects(F32 max_time, S32 throttle);
+	F32 killInvisibleObjects(F32 max_time);
+	F32 createVisibleObjects(F32 max_time);
 	F32 updateVisibleEntries(F32 max_time); //update visible entries
 
 	void addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type);
@@ -411,6 +416,10 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 
 	static BOOL sVOCacheCullingEnabled; //vo cache culling enabled or not.
 	static S32  sLastCameraUpdated;
+
+private:
+	static S32  sNewObjectCreationThrottle;
+
 private:
 	LLViewerRegionImpl * mImpl;
 	LLFrameTimer         mRegionTimer;
@@ -445,6 +454,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	F32		mCameraDistanceSquared;	// updated once per frame
 	U8		mCentralBakeVersion;
 	
+	LLVOCacheEntry* mLastVisitedEntry;
+	U32				mInvisibilityCheckHistory;	
+
 	// Information for Homestead / CR-53
 	S32 mClassID;
 	S32 mCPURatio;
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 82485d7fdcf6870267128658a7e17706f28b5773..7dfa131ebf3b469770d2920721be620feb66cb45 100755
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -34,6 +34,7 @@
 #include "llviewerregion.h"
 #include "pipeline.h"
 
+BOOL LLVOCachePartition::sNeedsOcclusionCheck = FALSE;
 LLTrace::MemStatHandle	LLVOCachePartition::sMemStat("LLVOCachePartition");
 
 BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
@@ -467,8 +468,14 @@ LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
 {
 	mLODPeriod = 16;
 	mRegionp = regionp;
-	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;
-	
+	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;	
+	mDirty = FALSE;
+
+	for(S32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+	{
+		mCulledTime[i] = 0;
+		mCullHistory[i] = -1;
+	}
 	new LLOcclusionCullingGroup(mOctree, this);
 }
 
@@ -477,6 +484,7 @@ void LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry)
 	llassert(entry->hasVOCacheEntry());
 
 	mOctree->insert(entry);
+	mDirty = TRUE;
 }
 	
 void LLVOCachePartition::removeEntry(LLViewerOctreeEntry* entry)
@@ -595,7 +603,19 @@ S32 LLVOCachePartition::cull(LLCamera &camera, bool do_occlusion)
 		return 0;
 	}
 
+	if(mCulledTime[LLViewerCamera::sCurCameraID] == LLViewerOctreeEntryData::getCurrentFrame())
+	{
+		return 0; //already culled
+	}
+	mCulledTime[LLViewerCamera::sCurCameraID] = LLViewerOctreeEntryData::getCurrentFrame();
+
+	if(!mDirty && !mCullHistory[LLViewerCamera::sCurCameraID] && LLViewerRegion::isViewerCameraStatic())
+	{
+		return 0; //nothing changed, skip culling
+	}
+
 	((LLviewerOctreeGroup*)mOctree->getListener(0))->rebound();
+	mCullHistory[LLViewerCamera::sCurCameraID] <<= 2;
 
 	//localize the camera
 	LLVector3 region_agent = mRegionp->getOriginAgent();
@@ -604,7 +624,16 @@ S32 LLVOCachePartition::cull(LLCamera &camera, bool do_occlusion)
 	LLVOCacheOctreeCull culler(&camera, mRegionp, region_agent, do_occlusion && use_object_cache_occlusion, this);
 	culler.traverse(mOctree);
 
-	return 0;
+	if(mRegionp->getNumOfVisibleGroups() > 0)
+	{
+		mCullHistory[LLViewerCamera::sCurCameraID] |= 1;
+	}
+
+	if(!sNeedsOcclusionCheck)
+	{
+		sNeedsOcclusionCheck = !mOccludedGroups.empty();
+	}
+	return 1;
 }
 
 void LLVOCachePartition::addOccluders(LLviewerOctreeGroup* gp)
@@ -646,6 +675,8 @@ void LLVOCachePartition::resetOccluders()
 		group->clearOcclusionState(LLOcclusionCullingGroup::ACTIVE_OCCLUSION);
 	}	
 	mOccludedGroups.clear();
+	mDirty = FALSE;
+	sNeedsOcclusionCheck = FALSE;
 }
 
 //-------------------------------------------------------------------
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 04463088fa5069e87f412144ddbc50f2bdfb5378..c448b97b80671c4758a45098a8c298afa635fdd7 100755
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -168,7 +168,13 @@ class LLVOCachePartition : public LLViewerOctreePartition, public LLTrace::MemTr
 public:	
 	void processOccluders(LLCamera* camera);
 
+public:
+	static BOOL sNeedsOcclusionCheck;
+
 private:
+	BOOL  mDirty;
+	U32   mCullHistory[LLViewerCamera::NUM_CAMERAS];
+	U32   mCulledTime[LLViewerCamera::NUM_CAMERAS];
 	std::set<LLOcclusionCullingGroup*> mOccludedGroups;
 };
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index bfc5077c9079c033700ef6f890f6dbc6497f3701..df5e3d835c5c1156557ffe9711d3287422348c06 100755
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -668,8 +668,9 @@ void LLWorld::updateRegions(F32 max_update_time)
 	
 	if(LLViewerCamera::getInstance()->isChanged())
 	{
-		LLViewerRegion::sLastCameraUpdated = LLViewerOctreeEntryData::getCurrentFrame();
+		LLViewerRegion::sLastCameraUpdated = LLViewerOctreeEntryData::getCurrentFrame() + 1;
 	}
+	LLViewerRegion::calcNewObjectCreationThrottle();
 
 	// Perform idle time updates for the regions (and associated surfaces)
 	for (region_list_t::iterator iter = mRegionList.begin();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 1abaaa49ac04792b5e0494c4ad0f2a67b6f9d79e..87c3bf7bdf32d1152f5cfa5d8f9719be85a39d18 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2724,7 +2724,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT
 
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
-	if (LLPipeline::sUseOcclusion > 1)
+	if (LLPipeline::sUseOcclusion > 1 && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
 	{
 		LLVertexBuffer::unbind();