davep avatar davep committed 44c6da7

MAINT-616 Different VBO Pooling scheme -- populate VBO pool with buffers that are likely to be requested, but never reuse a previously used buffer.

Comments (0)

Files changed (4)

indra/llrender/llvertexbuffer.cpp

 #include "llglslshader.h"
 #include "llmemory.h"
 
-#define LL_VBO_POOLING 0
+#define LL_VBO_POOLING 1
 
 //Next Highest Power Of Two
 //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
 
 
 const U32 LL_VBO_BLOCK_SIZE = 2048;
+const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
 
 U32 vbo_block_size(U32 size)
 { //what block size will fit size?
 	return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
 }
 
+const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
 
 
 //============================================================================
 
 };
 
+LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
+: mUsage(vboUsage), mType(vboType)
+{
+	mMissCount.resize(LL_VBO_POOL_SEED_COUNT);
+	std::fill(mMissCount.begin(), mMissCount.end(), 0);
+}
 
-volatile U8* LLVBOPool::allocate(U32& name, U32 size)
+
+volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
 	llassert(vbo_block_size(size) == size);
 	
 	if (mFreeList.size() <= i)
 	{
 		mFreeList.resize(i+1);
+		mMissCount.resize(i+1);
 	}
 
-	if (mFreeList[i].empty())
+	if (mFreeList[i].empty() || for_seed)
 	{
 		//make a new buffer
 		glGenBuffersARB(1, &name);
 		glBindBufferARB(mType, name);
 
+		if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
+		{ //record this miss
+			mMissCount[i]++;	
+		}
+
 		if (mType == GL_ARRAY_BUFFER_ARB)
 		{
 			LLVertexBuffer::sAllocatedBytes += size;
 		}
 
 		glBindBufferARB(mType, 0);
+
+		if (for_seed)
+		{ //put into pool for future use
+			llassert(mFreeList.size() > i);
+
+			Record rec;
+			rec.mGLName = name;
+			rec.mClientData = ret;
+	
+			if (mType == GL_ARRAY_BUFFER_ARB)
+			{
+				sBytesPooled += size;
+			}
+			else
+			{
+				sIndexBytesPooled += size;
+			}
+			mFreeList[i].push_back(rec);
+		}
 	}
 	else
 	{
 {
 	llassert(vbo_block_size(size) == size);
 
-#if LL_VBO_POOLING
+#if 0 && LL_VBO_POOLING
 
 	U32 i = vbo_block_index(size);
 
 #endif
 }
 
+void LLVBOPool::seedPool()
+{
+	U32 dummy_name = 0;
+
+	if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
+	{
+		mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
+	}
+
+	for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++)
+	{
+		if (mMissCount[i] > mFreeList[i].size())
+		{ 
+			U32 size = i*LL_VBO_BLOCK_SIZE;
+		
+			S32 count = mMissCount[i] - mFreeList[i].size();
+			for (U32 j = 0; j < count; ++j)
+			{
+				allocate(dummy_name, size, true);
+			}
+		}
+	}
+}
+
+
 void LLVBOPool::cleanup()
 {
 	U32 size = 1;
 
 		size *= 2;
 	}
+
+	//reset miss counts
+	std::fill(mMissCount.begin(), mMissCount.end(), 0);
 }
 
 
 
 
 //static
+void LLVertexBuffer::seedPools()
+{
+	sStreamVBOPool.seedPool();
+	sDynamicVBOPool.seedPool();
+	sStreamIBOPool.seedPool();
+	sDynamicIBOPool.seedPool();
+}
+
+//static
 void LLVertexBuffer::setupClientArrays(U32 data_mask)
 {
 	if (sLastMask != data_mask)

indra/llrender/llvertexbuffer.h

 	static U32 sBytesPooled;
 	static U32 sIndexBytesPooled;
 	
-	LLVBOPool(U32 vboUsage, U32 vboType)
-		: mUsage(vboUsage)
-		, mType(vboType)
-	{}
-
+	LLVBOPool(U32 vboUsage, U32 vboType);
+		
 	const U32 mUsage;
 	const U32 mType;
 
 	//size MUST be a power of 2
-	volatile U8* allocate(U32& name, U32 size);
+	volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
 	
 	//size MUST be the size provided to allocate that returned the given name
 	void release(U32 name, volatile U8* buffer, U32 size);
 	
+	//batch allocate buffers to be provided to the application on demand
+	void seedPool();
+
 	//destroy all records in mFreeList
 	void cleanup();
 
 
 	typedef std::list<Record> record_list_t;
 	std::vector<record_list_t> mFreeList;
+	std::vector<U32> mMissCount;
+
 };
 
 class LLGLFence
 	static bool sUseVAO;
 	static bool	sPreferStreamDraw;
 
+	static void seedPools();
+
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);

indra/newview/llvovolume.cpp

 {
 	LLViewerObject::idleUpdate(agent, world, time);
 
-	static LLFastTimer::DeclareTimer ftm("Volume");
+	static LLFastTimer::DeclareTimer ftm("Volume Idle");
 	LLFastTimer t(ftm);
 
 	if (mDead || mDrawable.isNull())
 	return true;
 }
 
+static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face");
+
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
+	LLFastTimer t(FTM_REGISTER_FACE);
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 
 	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
 
 }
 
-static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume VB");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_FACE_LIST("Build Face List");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info");
 
 static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
 {
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
+	
+
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
 	{
 		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
 		{
-			LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
-		
 			rebuildMesh(group);
 		}
 		return;
 	}
 
+	LLFastTimer ftm(FTM_REBUILD_VOLUME_VB);
+
 	group->mBuilt = 1.f;
 	
-	LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
-
 	LLVOAvatar* pAvatarVO = NULL;
 
 	LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
 
 	bool emissive = false;
 
-	//get all the faces into a list
-	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
-	{
-		LLDrawable* drawablep = *drawable_iter;
+	{
+		LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST);
+
+		//get all the faces into a list
+		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+		{
+			LLDrawable* drawablep = *drawable_iter;
 		
-		if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
-		{
-			continue;
-		}
-	
-		if (drawablep->isAnimating())
-		{ //fall back to stream draw for animating verts
-			useage = GL_STREAM_DRAW_ARB;
-		}
-
-		LLVOVolume* vobj = drawablep->getVOVolume();
-
-		if (!vobj)
-		{
-			continue;
-		}
-
-		if (vobj->isMesh() &&
-			(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
-		{
-			continue;
-		}
-
-		LLVolume* volume = vobj->getVolume();
-		if (volume)
-		{
-			const LLVector3& scale = vobj->getScale();
-			group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
-		}
-
-		llassert_always(vobj);
-		vobj->updateTextureVirtualSize(true);
-		vobj->preRebuild();
-
-		drawablep->clearState(LLDrawable::HAS_ALPHA);
-
-		bool rigged = vobj->isAttachment() && 
-					vobj->isMesh() && 
-					gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
-
-		bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
-
-		bool is_rigged = false;
-
-		//for each face
-		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
-		{
-			LLFace* facep = drawablep->getFace(i);
-			if (!facep)
+			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
 			{
 				continue;
 			}
-
-			//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
-			// batch, it will recover its vertex buffer reference from the spatial group
-			facep->setVertexBuffer(NULL);
+	
+			if (drawablep->isAnimating())
+			{ //fall back to stream draw for animating verts
+				useage = GL_STREAM_DRAW_ARB;
+			}
+
+			LLVOVolume* vobj = drawablep->getVOVolume();
+
+			if (!vobj)
+			{
+				continue;
+			}
+
+			if (vobj->isMesh() &&
+				(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
+			{
+				continue;
+			}
+
+			LLVolume* volume = vobj->getVolume();
+			if (volume)
+			{
+				const LLVector3& scale = vobj->getScale();
+				group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
+			}
+
+			llassert_always(vobj);
+			vobj->updateTextureVirtualSize(true);
+			vobj->preRebuild();
+
+			drawablep->clearState(LLDrawable::HAS_ALPHA);
+
+			bool rigged = vobj->isAttachment() && 
+						vobj->isMesh() && 
+						gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
+
+			bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+
+			bool is_rigged = false;
+
+			//for each face
+			for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+			{
+				LLFace* facep = drawablep->getFace(i);
+				if (!facep)
+				{
+					continue;
+				}
+
+				//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
+				// batch, it will recover its vertex buffer reference from the spatial group
+				facep->setVertexBuffer(NULL);
 			
-			//sum up face verts and indices
-			drawablep->updateFaceSize(i);
+				//sum up face verts and indices
+				drawablep->updateFaceSize(i);
 			
 			
 
-			if (rigged) 
-			{
-				if (!facep->isState(LLFace::RIGGED))
-				{ //completely reset vertex buffer
-					facep->clearVertexBuffer();
-				}
+				if (rigged) 
+				{
+					if (!facep->isState(LLFace::RIGGED))
+					{ //completely reset vertex buffer
+						facep->clearVertexBuffer();
+					}
 		
-				facep->setState(LLFace::RIGGED);
-				is_rigged = true;
+					facep->setState(LLFace::RIGGED);
+					is_rigged = true;
 				
-				//get drawpool of avatar with rigged face
-				LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+					//get drawpool of avatar with rigged face
+					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
 				
-				//Determine if we've received skininfo that contains an
-				//alternate bind matrix - if it does then apply the translational component
-				//to the joints of the avatar.
-				bool pelvisGotSet = false;
-
-				if ( pAvatarVO )
-				{
-					LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
-					const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+					//Determine if we've received skininfo that contains an
+					//alternate bind matrix - if it does then apply the translational component
+					//to the joints of the avatar.
+					bool pelvisGotSet = false;
+
+					if ( pAvatarVO )
+					{
+						LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+						const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
 					
-					if ( pSkinData )
-					{
-						const int bindCnt = pSkinData->mAlternateBindMatrix.size();								
-						if ( bindCnt > 0 )
-						{					
-							const int jointCnt = pSkinData->mJointNames.size();
-							const F32 pelvisZOffset = pSkinData->mPelvisOffset;
-							bool fullRig = (jointCnt>=20) ? true : false;
-							if ( fullRig )
-							{
-								for ( int i=0; i<jointCnt; ++i )
+						if ( pSkinData )
+						{
+							const int bindCnt = pSkinData->mAlternateBindMatrix.size();								
+							if ( bindCnt > 0 )
+							{					
+								const int jointCnt = pSkinData->mJointNames.size();
+								const F32 pelvisZOffset = pSkinData->mPelvisOffset;
+								bool fullRig = (jointCnt>=20) ? true : false;
+								if ( fullRig )
 								{
-									std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
-									//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
-									LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
-									if ( pJoint && pJoint->getId() != currentId )
-									{   									
-										pJoint->setId( currentId );
-										const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									
-										//Set the joint position
-										pJoint->storeCurrentXform( jointPos );																																
-										//If joint is a pelvis then handle old/new pelvis to foot values
-										if ( lookingForJoint == "mPelvis" )
-										{	
+									for ( int i=0; i<jointCnt; ++i )
+									{
+										std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
+										//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
+										LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
+										if ( pJoint && pJoint->getId() != currentId )
+										{   									
+											pJoint->setId( currentId );
+											const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									
+											//Set the joint position
 											pJoint->storeCurrentXform( jointPos );																																
-											if ( !pAvatarVO->hasPelvisOffset() )
-											{										
-												pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
-												//Trigger to rebuild viewer AV
-												pelvisGotSet = true;											
+											//If joint is a pelvis then handle old/new pelvis to foot values
+											if ( lookingForJoint == "mPelvis" )
+											{	
+												pJoint->storeCurrentXform( jointPos );																																
+												if ( !pAvatarVO->hasPelvisOffset() )
+												{										
+													pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
+													//Trigger to rebuild viewer AV
+													pelvisGotSet = true;											
+												}										
 											}										
-										}										
+										}
 									}
-								}
-							}							
+								}							
+							}
 						}
 					}
-				}
-				//If we've set the pelvis to a new position we need to also rebuild some information that the
-				//viewer does at launch (e.g. body size etc.)
-				if ( pelvisGotSet )
-				{
-					pAvatarVO->postPelvisSetRecalc();
-				}
-
-				if (pool)
-				{
-					const LLTextureEntry* te = facep->getTextureEntry();
-
-					//remove face from old pool if it exists
-					LLDrawPool* old_pool = facep->getPool();
-					if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+					//If we've set the pelvis to a new position we need to also rebuild some information that the
+					//viewer does at launch (e.g. body size etc.)
+					if ( pelvisGotSet )
 					{
-						((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+						pAvatarVO->postPelvisSetRecalc();
 					}
 
-					//add face to new pool
-					LLViewerTexture* tex = facep->getTexture();
-					U32 type = gPipeline.getPoolTypeFromTE(te, tex);
-
-					if (type == LLDrawPool::POOL_ALPHA)
+					if (pool)
 					{
-						if (te->getColor().mV[3] > 0.f)
+						const LLTextureEntry* te = facep->getTextureEntry();
+
+						//remove face from old pool if it exists
+						LLDrawPool* old_pool = facep->getPool();
+						if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+						{
+							((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+						}
+
+						//add face to new pool
+						LLViewerTexture* tex = facep->getTexture();
+						U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+						if (type == LLDrawPool::POOL_ALPHA)
+						{
+							if (te->getColor().mV[3] > 0.f)
+							{
+								if (te->getFullbright())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+								}
+							}
+						}
+						else if (te->getShiny())
 						{
 							if (te->getFullbright())
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
 							}
 							else
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+								if (LLPipeline::sRenderDeferred)
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+								}
+							}
+						}
+						else
+						{
+							if (te->getFullbright())
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+							}
+							else
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+							}
+						}
+
+						if (te->getGlow())
+						{
+							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+						}
+
+						if (LLPipeline::sRenderDeferred)
+						{
+							if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+							{
+								if (te->getBumpmap())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+								}
 							}
 						}
 					}
-					else if (te->getShiny())
+
+					continue;
+				}
+				else
+				{
+					if (facep->isState(LLFace::RIGGED))
+					{ //face is not rigged but used to be, remove from rigged face pool
+						LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+						if (pool)
+						{
+							pool->removeRiggedFace(facep);
+						}
+						facep->clearState(LLFace::RIGGED);
+					}
+				}
+
+
+				if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
+				{
+					facep->clearVertexBuffer();
+					continue;
+				}
+
+				cur_total += facep->getGeomCount();
+
+				if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
+				{
+					const LLTextureEntry* te = facep->getTextureEntry();
+					LLViewerTexture* tex = facep->getTexture();
+
+					if (te->getGlow() >= 1.f/255.f)
 					{
-						if (te->getFullbright())
+						emissive = true;
+					}
+
+					if (facep->isState(LLFace::TEXTURE_ANIM))
+					{
+						if (!vobj->mTexAnimMode)
 						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
+							facep->clearState(LLFace::TEXTURE_ANIM);
 						}
-						else
+					}
+
+					BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
+					U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+					if (type != LLDrawPool::POOL_ALPHA && force_simple)
+					{
+						type = LLDrawPool::POOL_SIMPLE;
+					}
+					facep->setPoolType(type);
+
+					if (vobj->isHUDAttachment())
+					{
+						facep->setState(LLFace::FULLBRIGHT);
+					}
+
+					if (vobj->mTextureAnimp && vobj->mTexAnimMode)
+					{
+						if (vobj->mTextureAnimp->mFace <= -1)
 						{
-							if (LLPipeline::sRenderDeferred)
+							S32 face;
+							for (face = 0; face < vobj->getNumTEs(); face++)
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+								LLFace * facep = drawablep->getFace(face);
+								if (facep)
+								{
+									facep->setState(LLFace::TEXTURE_ANIM);
+								}
 							}
 						}
-					}
-					else
-					{
-						if (te->getFullbright())
+						else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
 						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
-						}
-						else
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-						}
-					}
-
-					if (te->getGlow())
-					{
-						pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
-					}
-
-					if (LLPipeline::sRenderDeferred)
-					{
-						if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
-						{
-							if (te->getBumpmap())
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
-							}
-						}
-					}
-				}
-
-				continue;
-			}
-			else
-			{
-				if (facep->isState(LLFace::RIGGED))
-				{ //face is not rigged but used to be, remove from rigged face pool
-					LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
-					if (pool)
-					{
-						pool->removeRiggedFace(facep);
-					}
-					facep->clearState(LLFace::RIGGED);
-				}
-			}
-
-
-			if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
-			{
-				facep->clearVertexBuffer();
-				continue;
-			}
-
-			cur_total += facep->getGeomCount();
-
-			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
-			{
-				const LLTextureEntry* te = facep->getTextureEntry();
-				LLViewerTexture* tex = facep->getTexture();
-
-				if (te->getGlow() >= 1.f/255.f)
-				{
-					emissive = true;
-				}
-
-				if (facep->isState(LLFace::TEXTURE_ANIM))
-				{
-					if (!vobj->mTexAnimMode)
-					{
-						facep->clearState(LLFace::TEXTURE_ANIM);
-					}
-				}
-
-				BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
-				U32 type = gPipeline.getPoolTypeFromTE(te, tex);
-				if (type != LLDrawPool::POOL_ALPHA && force_simple)
-				{
-					type = LLDrawPool::POOL_SIMPLE;
-				}
-				facep->setPoolType(type);
-
-				if (vobj->isHUDAttachment())
-				{
-					facep->setState(LLFace::FULLBRIGHT);
-				}
-
-				if (vobj->mTextureAnimp && vobj->mTexAnimMode)
-				{
-					if (vobj->mTextureAnimp->mFace <= -1)
-					{
-						S32 face;
-						for (face = 0; face < vobj->getNumTEs(); face++)
-						{
-							LLFace * facep = drawablep->getFace(face);
+							LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace);
 							if (facep)
 							{
 								facep->setState(LLFace::TEXTURE_ANIM);
 							}
 						}
 					}
-					else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
+
+					if (type == LLDrawPool::POOL_ALPHA)
 					{
-						LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace);
-						if (facep)
-						{
-							facep->setState(LLFace::TEXTURE_ANIM);
-						}
-					}
-				}
-
-				if (type == LLDrawPool::POOL_ALPHA)
-				{
-					if (facep->canRenderAsMask())
-					{ //can be treated as alpha mask
-						simple_faces.push_back(facep);
-					}
-					else
-					{
-						if (te->getColor().mV[3] > 0.f)
-						{ //only treat as alpha in the pipeline if < 100% transparent
-							drawablep->setState(LLDrawable::HAS_ALPHA);
-						}
-						alpha_faces.push_back(facep);
-					}
-				}
-				else
-				{
-					if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
-					{
-						facep->mLastUpdateTime = gFrameTimeSeconds;
-					}
-
-					if (gPipeline.canUseWindLightShadersOnObjects()
-						&& LLPipeline::sRenderBump)
-					{
-						if (te->getBumpmap())
-						{ //needs normal + binormal
-							bump_faces.push_back(facep);
-						}
-						else if (te->getShiny() || !te->getFullbright())
-						{ //needs normal
+						if (facep->canRenderAsMask())
+						{ //can be treated as alpha mask
 							simple_faces.push_back(facep);
 						}
-						else 
-						{ //doesn't need normal
-							facep->setState(LLFace::FULLBRIGHT);
-							fullbright_faces.push_back(facep);
+						else
+						{
+							if (te->getColor().mV[3] > 0.f)
+							{ //only treat as alpha in the pipeline if < 100% transparent
+								drawablep->setState(LLDrawable::HAS_ALPHA);
+							}
+							alpha_faces.push_back(facep);
 						}
 					}
 					else
 					{
-						if (te->getBumpmap() && LLPipeline::sRenderBump)
-						{ //needs normal + binormal
-							bump_faces.push_back(facep);
+						if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
+						{
+							facep->mLastUpdateTime = gFrameTimeSeconds;
 						}
-						else if ((te->getShiny() && LLPipeline::sRenderBump) ||
-							!(te->getFullbright() || bake_sunlight))
-						{ //needs normal
-							simple_faces.push_back(facep);
+
+						if (gPipeline.canUseWindLightShadersOnObjects()
+							&& LLPipeline::sRenderBump)
+						{
+							if (te->getBumpmap())
+							{ //needs normal + binormal
+								bump_faces.push_back(facep);
+							}
+							else if (te->getShiny() || !te->getFullbright())
+							{ //needs normal
+								simple_faces.push_back(facep);
+							}
+							else 
+							{ //doesn't need normal
+								facep->setState(LLFace::FULLBRIGHT);
+								fullbright_faces.push_back(facep);
+							}
 						}
-						else 
-						{ //doesn't need normal
-							facep->setState(LLFace::FULLBRIGHT);
-							fullbright_faces.push_back(facep);
+						else
+						{
+							if (te->getBumpmap() && LLPipeline::sRenderBump)
+							{ //needs normal + binormal
+								bump_faces.push_back(facep);
+							}
+							else if ((te->getShiny() && LLPipeline::sRenderBump) ||
+								!(te->getFullbright() || bake_sunlight))
+							{ //needs normal
+								simple_faces.push_back(facep);
+							}
+							else 
+							{ //doesn't need normal
+								facep->setState(LLFace::FULLBRIGHT);
+								fullbright_faces.push_back(facep);
+							}
 						}
 					}
 				}
+				else
+				{	//face has no renderable geometry
+					facep->clearVertexBuffer();
+				}		
+			}
+
+			if (is_rigged)
+			{
+				drawablep->setState(LLDrawable::RIGGED);
 			}
 			else
-			{	//face has no renderable geometry
-				facep->clearVertexBuffer();
-			}		
-		}
-
-		if (is_rigged)
-		{
-			drawablep->setState(LLDrawable::RIGGED);
-		}
-		else
-		{
-			drawablep->clearState(LLDrawable::RIGGED);
+			{
+				drawablep->clearState(LLDrawable::RIGGED);
+			}
 		}
 	}
 
 	}
 }
 
-static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
-static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild");
 
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
 	llassert(group);
 	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
 	{
-		LLFastTimer tm(FTM_VOLUME_GEOM);
+		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
+
 		S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
 
 		group->mBuilt = 1.f;
 
 		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 		{
-			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
 			LLDrawable* drawablep = *drawable_iter;
 
 			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
 	}
 };
 
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FIND_VB("Find VB");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB");
+
+
+
+
+
 void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
 {
+	LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO);
+
 	U32 buffer_usage = group->mBufferUsage;
 	
 #if LL_DARWIN
 	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
 	max_vertices = llmin(max_vertices, (U32) 65535);
 
-	if (!distance_sort)
-	{
-		//sort faces by things that break batches
-		std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
-	}
-	else
-	{
-		//sort faces by distance
-		std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
+	{
+		LLFastTimer t(FTM_GEN_DRAW_INFO_SORT);
+		if (!distance_sort)
+		{
+			//sort faces by things that break batches
+			std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
+		}
+		else
+		{
+			//sort faces by distance
+			std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
+		}
 	}
 				
 	bool hud_group = group->isHUDGroup() ;
 		
 		std::vector<LLViewerTexture*> texture_list;
 
-		if (batch_textures)
 		{
-			U8 cur_tex = 0;
-			facep->setTextureIndex(cur_tex);
-			texture_list.push_back(tex);
-
-			//if (can_batch_texture(facep))
+			LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE);
+			if (batch_textures)
 			{
-				while (i != faces.end())
+				U8 cur_tex = 0;
+				facep->setTextureIndex(cur_tex);
+				texture_list.push_back(tex);
+
+				//if (can_batch_texture(facep))
+				{
+					while (i != faces.end())
+					{
+						facep = *i;
+						if (facep->getTexture() != tex)
+						{
+							if (distance_sort)
+							{ //textures might be out of order, see if texture exists in current batch
+								bool found = false;
+								for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
+								{
+									if (facep->getTexture() == texture_list[tex_idx])
+									{
+										cur_tex = tex_idx;
+										found = true;
+										break;
+									}
+								}
+
+								if (!found)
+								{
+									cur_tex = texture_list.size();
+								}
+							}
+							else
+							{
+								cur_tex++;
+							}
+
+							if (!can_batch_texture(facep))
+							{ //face is bump mapped or has an animated texture matrix -- can't 
+								//batch more than 1 texture at a time
+								break;
+							}
+
+							if (cur_tex >= texture_index_channels)
+							{ //cut batches when index channels are depleted
+								break;
+							}
+
+							tex = facep->getTexture();
+
+							texture_list.push_back(tex);
+						}
+
+						if (geom_count + facep->getGeomCount() > max_vertices)
+						{ //cut batches on geom count too big
+							break;
+						}
+
+						++i;
+						index_count += facep->getIndicesCount();
+						geom_count += facep->getGeomCount();
+
+						facep->setTextureIndex(cur_tex);
+					}
+				}
+
+				tex = texture_list[0];
+			}
+			else
+			{
+				while (i != faces.end() && 
+					(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
 				{
 					facep = *i;
-					if (facep->getTexture() != tex)
-					{
-						if (distance_sort)
-						{ //textures might be out of order, see if texture exists in current batch
-							bool found = false;
-							for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
-							{
-								if (facep->getTexture() == texture_list[tex_idx])
-								{
-									cur_tex = tex_idx;
-									found = true;
-									break;
-								}
-							}
-
-							if (!found)
-							{
-								cur_tex = texture_list.size();
-							}
-						}
-						else
-						{
-							cur_tex++;
-						}
-
-						if (!can_batch_texture(facep))
-						{ //face is bump mapped or has an animated texture matrix -- can't 
-							//batch more than 1 texture at a time
-							break;
-						}
-
-						if (cur_tex >= texture_index_channels)
-						{ //cut batches when index channels are depleted
-							break;
-						}
-
-						tex = facep->getTexture();
-
-						texture_list.push_back(tex);
-					}
+			
+
+					//face has no texture index
+					facep->mDrawInfo = NULL;
+					facep->setTextureIndex(255);
 
 					if (geom_count + facep->getGeomCount() > max_vertices)
 					{ //cut batches on geom count too big
 					++i;
 					index_count += facep->getIndicesCount();
 					geom_count += facep->getGeomCount();
-
-					facep->setTextureIndex(cur_tex);
 				}
 			}
-
-			tex = texture_list[0];
 		}
-		else
-		{
-			while (i != faces.end() && 
-				(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
-			{
-				facep = *i;
-			
-
-				//face has no texture index
-				facep->mDrawInfo = NULL;
-				facep->setTextureIndex(255);
-
-				if (geom_count + facep->getGeomCount() > max_vertices)
-				{ //cut batches on geom count too big
-					break;
-				}
-
-				++i;
-				index_count += facep->getIndicesCount();
-				geom_count += facep->getGeomCount();
-			}
-		}
-	
+
 		//create/delete/resize vertex buffer if needed
 		LLVertexBuffer* buffer = NULL;
 
+		if (group->mBufferUsage != GL_DYNAMIC_DRAW_ARB)
 		{ //try to find a buffer to reuse
+			LLFastTimer t(FTM_GEN_DRAW_INFO_FIND_VB);
 			LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter);
 		
 			if (found_iter != group->mBufferMap[mask].end())
 				}
 			}
 		}
-						
-		if (!buffer || !buffer->isWriteable())
-		{ //create new buffer if needed
-			buffer = createVertexBuffer(mask, buffer_usage);
-			buffer->allocateBuffer(geom_count, index_count, TRUE);
-		}
-		else 
-		{ //resize pre-existing buffer
-			if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage ||
-				buffer->getTypeMask() != mask)
-			{
+					
+		{
+			LLFastTimer t(FTM_GEN_DRAW_INFO_ALLOCATE);
+	
+			if (!buffer || !buffer->isWriteable())
+			{ //create new buffer if needed
 				buffer = createVertexBuffer(mask, buffer_usage);
 				buffer->allocateBuffer(geom_count, index_count, TRUE);
 			}
-			else
-			{
-				buffer->resizeBuffer(geom_count, index_count);
+			else 
+			{ //resize pre-existing buffer
+				LLFastTimer t(FTM_GEN_DRAW_INFO_RESIZE_VB);
+				if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage ||
+					buffer->getTypeMask() != mask)
+				{
+					buffer = createVertexBuffer(mask, buffer_usage);
+					buffer->allocateBuffer(geom_count, index_count, TRUE);
+				}
+				else
+				{
+					buffer->resizeBuffer(geom_count, index_count);
+				}
 			}
 		}
 

indra/newview/pipeline.cpp

 	return update_complete;
 }
 
+static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool");
+
 void LLPipeline::updateGL()
 {
 	while (!LLGLUpdate::sGLQ.empty())
 		glu->mInQ = FALSE;
 		LLGLUpdate::sGLQ.pop_front();
 	}
+
+	{ //seed VBO Pools
+		LLFastTimer t(FTM_SEED_VBO_POOLS);
+		LLVertexBuffer::seedPools();
+	}
 }
 
 void LLPipeline::rebuildPriorityGroups()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.