FIRE-34600 - Go for atomics on the particle counts

If we're even chasing the right bug this should fix it.
Tested visiting every single repro site for most recent beta no crashes
but I've never seen this crash normally either :-(
master
Beq 2024-10-07 00:54:07 +01:00
parent 01cee5b676
commit 7d5a15c924
2 changed files with 83 additions and 29 deletions

View File

@ -47,8 +47,8 @@ const F32 PART_SIM_BOX_SIDE = 16.f;
//static
S32 LLViewerPartSim::sMaxParticleCount = 0;
S32 LLViewerPartSim::sParticleCount = 0;
S32 LLViewerPartSim::sParticleCount2 = 0;
std::atomic<S32> LLViewerPartSim::sParticleCount{0}; // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
std::atomic<S32> LLViewerPartSim::sParticleCount2{0}; // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
// This controls how greedy individual particle burst sources are allowed to be, and adapts according to how near the particle-count limit we are.
F32 LLViewerPartSim::sParticleAdaptiveRate = 0.0625f;
F32 LLViewerPartSim::sParticleBurstRate = 0.5f;
@ -82,7 +82,7 @@ LLViewerPart::LLViewerPart() :
mPartSourcep = NULL;
mParent = NULL;
mChild = NULL;
++LLViewerPartSim::sParticleCount2 ;
LLViewerPartSim::incParticleCount2( 1 ); // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
}
LLViewerPart::~LLViewerPart()
@ -107,7 +107,7 @@ LLViewerPart::~LLViewerPart()
mPartSourcep = NULL;
--LLViewerPartSim::sParticleCount2 ;
LLViewerPartSim::decParticleCount2( 1 ); // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
}
void LLViewerPart::init(LLPointer<LLViewerPartSource> sourcep, LLViewerTexture *imagep, LLVPCallback cb)
@ -205,7 +205,7 @@ LLViewerPartGroup::~LLViewerPartGroup()
}
mParticles.clear();
LLViewerPartSim::decPartCount(count);
LLViewerPartSim::decParticleCount(count); // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
}
void LLViewerPartGroup::cleanup()
@ -268,7 +268,7 @@ bool LLViewerPartGroup::addPart(LLViewerPart* part, F32 desired_size)
mParticles.push_back(part);
part->mSkipOffset=mSkippedTime;
LLViewerPartSim::incPartCount(1);
LLViewerPartSim::incParticleCount(1); // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
return true;
}
@ -432,7 +432,7 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt)
{
gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL);
}
LLViewerPartSim::decPartCount(removed);
LLViewerPartSim::decParticleCount(removed); // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
}
// Kill the viewer object if this particle group is empty
@ -478,14 +478,22 @@ void LLViewerPartGroup::removeParticlesByID(const U32 source_id)
//static
void LLViewerPartSim::checkParticleCount(U32 size)
{
if(LLViewerPartSim::sParticleCount2 != LLViewerPartSim::sParticleCount)
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// if(LLViewerPartSim::sParticleCount2 != LLViewerPartSim::sParticleCount)
S32 count = LLViewerPartSim::getParticleCount();
S32 count2 = LLViewerPartSim::getParticleCount2();
if( count != count2 )
// <FS:Beq/>
{
LL_ERRS() << "sParticleCount: " << LLViewerPartSim::sParticleCount << " ; sParticleCount2: " << LLViewerPartSim::sParticleCount2 << LL_ENDL ;
LL_ERRS() << "sParticleCount: " << count << " ; sParticleCount2: " << count2 << LL_ENDL ; //<FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
}
if(size > (U32)LLViewerPartSim::sParticleCount2)
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// if(size > (U32)LLViewerPartSim::sParticleCount2)
if( size > static_cast<U32>(count2) )
// <FS:Beq/>
{
LL_ERRS() << "curren particle size: " << LLViewerPartSim::sParticleCount2 << " array size: " << size << LL_ENDL ;
LL_ERRS() << "current particle size: " << count2 << " array size: " << size << LL_ENDL ; // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
}
}
@ -531,14 +539,18 @@ void LLViewerPartSim::destroyClass()
//static
bool LLViewerPartSim::shouldAddPart()
{
if (sParticleCount >= MAX_PART_COUNT)
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// if (sParticleCount < MAX_PART_COUNT)
auto count = LLViewerPartSim::getParticleCount();
if ( count >= MAX_PART_COUNT)
// <FS:Beq/>
{
return false;
}
if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
if ( count > PART_THROTTLE_THRESHOLD*sMaxParticleCount) // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
{
F32 frac = (F32)sParticleCount/(F32)sMaxParticleCount;
F32 frac = (F32)count/(F32)sMaxParticleCount; // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
frac -= PART_THROTTLE_THRESHOLD;
frac *= PART_THROTTLE_RESCALE;
if (ll_frand() < frac)
@ -560,7 +572,7 @@ bool LLViewerPartSim::shouldAddPart()
void LLViewerPartSim::addPart(LLViewerPart* part)
{
if (sParticleCount < MAX_PART_COUNT)
if (LLViewerPartSim::getParticleCount() < MAX_PART_COUNT)
{
put(part);
}
@ -794,14 +806,19 @@ void LLViewerPartSim::updateSimulation()
}
if (LLDrawable::getCurrentFrame()%16==0)
{
if (sParticleCount > sMaxParticleCount * 0.875f
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// if (sParticleCount > sMaxParticleCount * 0.875f
// && sParticleAdaptiveRate < 2.0f)
auto count = LLViewerPartSim::getParticleCount();
if ( count > sMaxParticleCount * 0.875f
&& sParticleAdaptiveRate < 2.0f)
// <FS:Beq/>
{
sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT;
}
else
{
if (sParticleCount < sMaxParticleCount * 0.5f
if ( count < sMaxParticleCount * 0.5f // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
&& sParticleAdaptiveRate > 0.03125f)
{
sParticleAdaptiveRate *= PART_ADAPT_RATE_MULT_RECIP;
@ -818,15 +835,25 @@ void LLViewerPartSim::updatePartBurstRate()
{
if (!(LLDrawable::getCurrentFrame() & 0xf))
{
if (sParticleCount >= MAX_PART_COUNT) //set rate to zero
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// if (sParticleCount >= MAX_PART_COUNT) //set rate to zero
auto count = LLViewerPartSim::getParticleCount();
if (count >= MAX_PART_COUNT) //set rate to zero
// <FS:Beq/>
{
sParticleBurstRate = 0.0f ;
}
else if(sParticleCount > 0)
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// else if(sParticleCount > 0)
else if (count > 0)
// <FS:Beq/>
{
if(sParticleBurstRate > 0.0000001f)
{
F32 total_particles = sParticleCount / sParticleBurstRate ; //estimated
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// F32 total_particles = sParticleCount / sParticleBurstRate ; //estimated
F32 total_particles = count / sParticleBurstRate ; //estimated
// <FS:Beq/>
F32 new_rate = llclamp(0.9f * sMaxParticleCount / total_particles, 0.0f, 1.0f) ;
F32 delta_rate_threshold = llmin(0.1f * llmax(new_rate, sParticleBurstRate), 0.1f) ;
F32 delta_rate = llclamp(new_rate - sParticleBurstRate, -1.0f * delta_rate_threshold, delta_rate_threshold) ;

View File

@ -155,14 +155,25 @@ public:
static bool shouldAddPart(); // Just decides whether this particle should be added or not (for particle count capping)
F32 maxRate() // Return maximum particle generation rate
{
if (sParticleCount >= MAX_PART_COUNT)
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// if (sParticleCount >= MAX_PART_COUNT)
// {
// return 1.f;
// }
// if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
// {
// return (((F32)sParticleCount/(F32)sMaxParticleCount)-PART_THROTTLE_THRESHOLD)*PART_THROTTLE_RESCALE;
// }
const auto count = getParticleCount();
if ( count >= MAX_PART_COUNT)
{
return 1.f;
}
if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
if ( count > PART_THROTTLE_THRESHOLD*sMaxParticleCount)
{
return (((F32)sParticleCount/(F32)sMaxParticleCount)-PART_THROTTLE_THRESHOLD)*PART_THROTTLE_RESCALE;
return (((F32)count/(F32)sMaxParticleCount)-PART_THROTTLE_THRESHOLD)*PART_THROTTLE_RESCALE;
}
// </FS:Beq>
return 0.f;
}
F32 getRefRate() { return sParticleAdaptiveRate; }
@ -177,12 +188,28 @@ public:
friend class LLViewerPartGroup;
bool aboveParticleLimit() const { return sParticleCount > sMaxParticleCount; }
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// bool aboveParticleLimit() const { return sParticleCount > sMaxParticleCount; }
bool aboveParticleLimit() const { return getParticleCount() > sMaxParticleCount; }
// </FS:Beq>
static void setMaxPartCount(const S32 max_parts) { sMaxParticleCount = max_parts; }
static S32 getMaxPartCount() { return sMaxParticleCount; }
static void incPartCount(const S32 count) { sParticleCount += count; }
static void decPartCount(const S32 count) { sParticleCount -= count; }
// <FS:Beq> FIRE-34600 - bugsplat AVX2 particle count mismatch
// static void incPartCount(const S32 count) { sParticleCount += count; }
// static void decPartCount(const S32 count) { sParticleCount -= count; }
static void incParticleCount(const S32 count, std::memory_order order = std::memory_order_seq_cst )
{ sParticleCount.fetch_add( count , std::memory_order_seq_cst ); }
static void decParticleCount(const S32 count, std::memory_order order = std::memory_order_seq_cst )
{ sParticleCount.fetch_sub( count , std::memory_order_seq_cst ); }
static void incParticleCount2(const S32 count, std::memory_order order = std::memory_order_seq_cst )
{ sParticleCount2.fetch_add( count , std::memory_order_seq_cst ); }
static void decParticleCount2(const S32 count, std::memory_order order = std::memory_order_seq_cst )
{ sParticleCount2.fetch_sub( count , std::memory_order_seq_cst ); }
static inline S32 getParticleCount(std::memory_order order = std::memory_order_seq_cst) { return sParticleCount.load(order); }
static inline S32 getParticleCount2(std::memory_order order = std::memory_order_seq_cst) { return sParticleCount2.load(order); }
// </FS:Beq>
U32 mID;
@ -195,7 +222,7 @@ protected:
LLFrameTimer mSimulationTimer;
static S32 sMaxParticleCount;
static S32 sParticleCount;
static std::atomic<S32> sParticleCount; // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
static F32 sParticleAdaptiveRate;
static F32 sParticleBurstRate;
@ -207,7 +234,7 @@ protected:
//debug use only
public:
static S32 sParticleCount2;
static std::atomic<S32> sParticleCount2; // <FS:Beq/> FIRE-34600 - bugsplat AVX2 particle count mismatch
static void checkParticleCount(U32 size = 0) ;
};