[sldev] Particles / VWR-418

Nicholaz Beresford nicholaz at blueflash.cc
Fri May 25 17:46:29 PDT 2007


I just completed my version of the particles adjustment.   There may be 
other/better solutions, but this is the best I can come up with at the 
moment.

I did look again, but could not find any buggish problems (like 
rendering particles outside draw distance etc.), the only problem I can 
see was that with high concurrency and high draw distance emitters were 
fighting each other with entirely equal rights.

The attached patch has a previously found memory/object leak in region 
changes fixed and uses some sort of prioritizing without requiring the 
particles to be sorted.   Details are inside the source with extensive 
comments.

If someone wants to run it, I can provide a Windows test version.

Feedback would be welcome


Nick
-------------- next part --------------
--- linden-orig/indra/newview/llviewerpartsim.h	2007-05-26 01:48:21.531250000 +0200
+++ linden/indra/newview/llviewerpartsim.h	2007-05-26 01:48:23.765625000 +0200
@@ -138,6 +138,8 @@
 	void cleanupRegion(LLViewerRegion *regionp);
 
 	BOOL shouldAddPart(); // Just decides whether this particle should be added or not (for particle count capping)
+	F32 getPartFillRatio() { return (F32)sParticleCount / (F32)sMaxParticleCount; }
+
 	void addPart(LLViewerPart* part);
 	void cleanMutedParticles(const LLUUID& task_id);
 
--- linden-orig/indra/newview/llviewerpartsim.cpp	2007-05-23 11:56:00.000000000 +0200
+++ linden/indra/newview/llviewerpartsim.cpp	2007-05-26 02:14:39.281250000 +0200
@@ -521,6 +521,7 @@
 		llwarns << "LLViewerPartSim::put - Particle didn't go into its box!" << llendl;
 		llinfos << groupp->getCenterAgent() << llendl;
 		llinfos << part->mPosAgent << llendl;
+		delete groupp; // potential memory leak fixed (loss of groupp) [Nicholaz Beresford]
 		return NULL;
 	}
 	return groupp;
@@ -668,6 +669,14 @@
 			}
 		}
 	}
+
+
+	// DEBUG [Nicholas Beresford]
+	//
+	dump_sim_info(sParticleCount, mViewerPartSources.size()); 
+	//
+	// ~DEBUG 
+
 	//llinfos << "Particles: " << sParticleCount << llendl;
 }
 
@@ -693,7 +702,11 @@
 
 		if ((*iter)->getRegion() == regionp)
 		{
+			// sequence: remember the pointer, delete from list, delete object
+			LLViewerPartGroup *groupp= (*iter);	
 			i = mViewerPartGroups.erase(iter);			
+			delete groupp;		// need to delete object associated with pointer not just 
+								// erase pointer from pointer-list [Nicholaz Beresford]
 		}
 	}
 }
--- linden-orig/indra/newview/llviewerpartsource.h	2007-05-23 11:56:00.000000000 +0200
+++ linden/indra/newview/llviewerpartsource.h	2007-05-26 02:05:04.515625000 +0200
@@ -110,6 +110,7 @@
 	static LLViewerPartSourceScript *unpackPSS(LLViewerObject *source_objp, LLViewerPartSourceScript *pssp, const S32 block_num);
 	static LLViewerPartSourceScript *unpackPSS(LLViewerObject *source_objp, LLViewerPartSourceScript *pssp, LLDataPacker &dp);
 
+	F32 throttlePartSource(void);
 	LLViewerImage *getImage() const				{ return mImagep; }
 	void setImage(LLViewerImage *imagep);
 	LLPartSysData				mPartSysData;
--- linden-orig/indra/newview/llviewerpartsource.cpp	2007-05-23 11:56:00.000000000 +0200
+++ linden/indra/newview/llviewerpartsource.cpp	2007-05-26 02:14:07.609375000 +0200
@@ -80,8 +80,7 @@
 	mImagep = gImageList.getImage(id);
 	mImagep->bind();
 	mImagep->setClamp(TRUE, TRUE);
-}
-
+}	
 
 void LLViewerPartSourceScript::setDead()
 {
@@ -96,7 +95,7 @@
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
 	F32 old_update_time = mLastUpdateTime;
 	mLastUpdateTime += dt;
-	
+
 	F32 dt_update = mLastUpdateTime - mLastPartTime;
 
 	// Update this for objects which have the follow flag set...
@@ -148,6 +147,13 @@
 	}
 
 
+	// EXPERIMENTAL: throttle particle generation [Nicholaz Beresford]
+	//
+	F32 quota = throttlePartSource();
+	//
+	// ~EXPERIMENTAL
+
+
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PARTICLES))
 	{
 		if (mSourceObjectp.notNull())
@@ -202,7 +208,30 @@
 				continue;
 			}
 
+
+			// EXPERIMENTAL: throttle particle generation [Nicholaz Beresford]
+			//
+			// (NOTE: just multiplying the filter with the loop's mPartSysData.mBurstPartCount
+			// won't work because often these values are fairly small (just a count of 1-3)
+			// and don't lend themselves to multiplying with 20% or so.  
+			// 
+			// Therefore a statistical method works better: whenever a particle is needed,
+			// it is generated when a random number meets the percentage threshold (which
+			// over time ensures generation of the desired quota of particles)
+
+			if (ll_frand() > quota) {			// let quota percentage of the particles pass
+				continue;						// skip this particle, try our luck with the next iteration
+			}
+
+
+			// hooray ... a new particle
 			LLPointer<LLViewerPart> part = new LLViewerPart();
+			if (part.isNull()) {
+				break; // oops, out of memory
+			}
+			//
+			// ~EXPERIMENTAL
+
 
 			part->init(this, mImagep, NULL);
 			part->mFlags = mPartSysData.mPartData.mFlags;
@@ -309,6 +338,68 @@
 	}
 }
 
+
+// EXPERIMENTAL [Nicholas Beresford]
+//
+// throttle particle source 
+F32 LLViewerPartSourceScript::throttlePartSource()
+{
+	// Generate less of the intended particles the further away the emitter is,
+	// Current particle usage defines what is considered "far" (between draw_dist*4 and draw_dist/4 in this example)
+	F32 draw_dist = gAgent.mDrawDistance,
+		dist_cam = 1,	// distance from camera 
+		usage = gWorldPointer->mPartSim.getPartFillRatio(),
+		view_limit_low = draw_dist / 4,
+		view_limit_high = draw_dist * 4,
+		view_limit;
+	
+
+	// vary view limit depending on usage.  view_limit determines the quota an emitter 
+	// may generate: 100% generation a 0-meters distance, 0% generation at a distance of 
+	// view_limit-meters  and proportional quotas in between (based on distance)
+	// (with a view_limit of draw_dist*4 the most distant visible source could generate
+	// at a quota of 75%)
+	view_limit = view_limit_low + (1.f - usage) * (view_limit_high - view_limit_low); 
+
+
+	// get distance from camera
+	// (we could also do: LLVector3 dist= (mPosAgent - gCamera->getOrigin()).magVec())
+	LLViewerObject* srcobjp= mSourceObjectp;
+	if (srcobjp && srcobjp->mDrawable.notNull()) {
+		dist_cam =  srcobjp->mDrawable->mDistanceWRTCamera;
+	}
+
+
+	// generate quota of allowance (from 110% to zero)
+	//
+	// (normally this would start from 1.f (100%) but this gives 
+	// nearer particles extra leeway, i.e. make the filter not cut
+	// in from the first meter)
+	F32 pass_quota = 1.1f - dist_cam / view_limit;					
+
+
+
+	// here we could further tweak the allowance based on 
+	// emission, size of particles, cloud size, camera direction 
+	// (direction may be a real winner, anyone in for some vector geometry??)
+
+	//	S32 parts_per_second = (S32)((1.f/psd.mBurstRate)*(S32)psd.mBurstPartCount);  // particle generation rate
+	//	F32 active_parts_max = parts_per_second * pd.mMaxAge;	// max. theoretical number of parts after swinging in
+
+	// yada yada yada
+
+
+	// return 0-100% pass through rate for the filter
+	pass_quota = llclamp(pass_quota, 0.f, 1.f);
+
+	return pass_quota;
+}
+//
+// ~EXPERIMENTAL
+
+
+
+
 // static
 LLViewerPartSourceScript *LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLViewerPartSourceScript *pssp, const S32 block_num)
 {
@@ -322,6 +413,7 @@
 		LLViewerPartSourceScript *new_pssp = new LLViewerPartSourceScript(source_objp);
 		if (!new_pssp->mPartSysData.unpackBlock(block_num))
 		{
+			delete new_pssp; // potential memory leak fixed (loss of new_pssp) [Nicholaz Beresford]
 			return NULL;
 		}
 		if (new_pssp->mPartSysData.mTargetUUID.notNull())
@@ -360,6 +452,7 @@
 		LLViewerPartSourceScript *new_pssp = new LLViewerPartSourceScript(source_objp);
 		if (!new_pssp->mPartSysData.unpack(dp))
 		{
+			delete new_pssp; // potential memory leak fixed (loss of new_pssp) [Nicholaz Beresford]
 			return NULL;
 		}
 		if (new_pssp->mPartSysData.mTargetUUID.notNull())


More information about the SLDev mailing list