New patch to fix the particle corruption and flashing. Try to group particles into on adjacent VBO to avoid slowdowns.
parent
40a6e62a68
commit
b37c6e7cf0
|
|
@ -0,0 +1,66 @@
|
|||
U32 sFreeIndex[LL_MAX_PARTICLE_COUNT/32] = {0};
|
||||
U32 sIndexGeneration = 1;
|
||||
U32 sTotalParticles = 0;
|
||||
|
||||
U32 bitMasks[ 32 ] = { 0xFFFFFFFF, 0x80000000, 0xC0000000, 0xE0000000,
|
||||
0xF0000000, 0xF8000000, 0xFC000000, 0xFE000000,
|
||||
0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000,
|
||||
0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000,
|
||||
0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000,
|
||||
0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
|
||||
0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
|
||||
0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE };
|
||||
|
||||
bool findAvailableVBSlots( S32 &idxStart, S32 &idxEnd, U32 amount )
|
||||
{
|
||||
idxStart = idxEnd = -1;
|
||||
|
||||
if( amount + sTotalParticles > LL_MAX_PARTICLE_COUNT )
|
||||
amount = LL_MAX_PARTICLE_COUNT - sTotalParticles;
|
||||
|
||||
U32 u32Count = amount/32;
|
||||
U32 bitsLeft = amount - (u32Count*32);
|
||||
if( bitsLeft )
|
||||
++u32Count;
|
||||
U32 maskLast = bitMasks[ bitsLeft ];
|
||||
|
||||
int i = 0;
|
||||
int maxI = LL_MAX_PARTICLE_COUNT/32-u32Count;
|
||||
do
|
||||
{
|
||||
while( sFreeIndex[i] != 0xFFFFFFFF && i <= maxI )
|
||||
++i;
|
||||
|
||||
if( i > maxI )
|
||||
continue;
|
||||
|
||||
int j = i;
|
||||
while( sFreeIndex[j] == 0xFFFFFFFF && j <= LL_MAX_PARTICLE_COUNT/32 && (j-i) != u32Count )
|
||||
++j;
|
||||
|
||||
if( j > LL_MAX_PARTICLE_COUNT/32 || (i-j) != u32Count || (sFreeIndex[j-1] & maskLast) != maskLast )
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
int k = 0;
|
||||
idxStart = i*32;
|
||||
idxEnd = i + amount;
|
||||
while( k != amount )
|
||||
{
|
||||
for( int l = 0; k != amount && l < 32; ++l )
|
||||
{
|
||||
U32 mask = 1 << l;
|
||||
sFreeIndex[ i ] &= ~mask;
|
||||
++k;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
sTotalParticles += amount;
|
||||
return true;
|
||||
|
||||
} while( i <= maxI);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -166,6 +166,8 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
|
|||
mBoundingSphereRadius = 0.0f ;
|
||||
|
||||
mHasMedia = FALSE ;
|
||||
|
||||
mParticleGeneration = 0; // <FS:ND/> Default = no particle
|
||||
}
|
||||
|
||||
void LLFace::destroy()
|
||||
|
|
@ -183,9 +185,14 @@ void LLFace::destroy()
|
|||
}
|
||||
}
|
||||
|
||||
if (isState(LLFace::PARTICLE))
|
||||
// <FS:ND> Make sure we released any allocated VB index if this was a particle
|
||||
// if (isState(LLFace::PARTICLE))
|
||||
if (isState(LLFace::PARTICLE) || mParticleGeneration )
|
||||
// </FS:ND>
|
||||
{
|
||||
LLVOPartGroup::freeVBSlot(getGeomIndex()/4);
|
||||
LLVOPartGroup::freeVBSlot(getGeomIndex()/4,mParticleGeneration);
|
||||
mParticleGeneration = 0;
|
||||
|
||||
clearState(LLFace::PARTICLE);
|
||||
}
|
||||
|
||||
|
|
@ -414,8 +421,16 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align)
|
|||
llassert(verify());
|
||||
}
|
||||
|
||||
void LLFace::setGeomIndex(U16 idx)
|
||||
// <FS:ND> Pass another flag to mark this index as from LLVOPartGroup, in that case it needs to be freed with LLVOPartGroup::LLVOPartGroup
|
||||
// void LLFace::setGeomIndex(U16 idx)
|
||||
void LLFace::setGeomIndex(U16 idx, U32 aParticleGeneration )
|
||||
// </FS:ND>
|
||||
{
|
||||
if( mParticleGeneration && mGeomIndex != idx )
|
||||
LLVOPartGroup::freeVBSlot(getGeomIndex()/4,mParticleGeneration);
|
||||
|
||||
mParticleGeneration = aParticleGeneration;
|
||||
|
||||
if (mGeomIndex != idx)
|
||||
{
|
||||
mGeomIndex = idx;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,11 @@ public:
|
|||
BOOL verify(const U32* indices_array = NULL) const;
|
||||
void printDebugInfo() const;
|
||||
|
||||
void setGeomIndex(U16 idx);
|
||||
// <FS:ND> Pass another flag to mark this index as from LLVOPartGroup, in that case it needs to be freed with LLVOPartGroup::LLVOPartGroup
|
||||
// void setGeomIndex(U16 idx);
|
||||
void setGeomIndex(U16 idx, U32 aParticleGeneration = 0);
|
||||
// </FS:ND>
|
||||
|
||||
void setIndicesIndex(S32 idx);
|
||||
void setDrawInfo(LLDrawInfo* draw_info);
|
||||
|
||||
|
|
@ -359,6 +363,9 @@ public:
|
|||
lhs->getTexture() < rhs->getTexture();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
U32 mParticleGeneration;
|
||||
};
|
||||
|
||||
#endif // LL_LLFACE_H
|
||||
|
|
|
|||
|
|
@ -284,16 +284,36 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt)
|
|||
LLViewerCamera* camera = LLViewerCamera::getInstance();
|
||||
LLViewerRegion *regionp = getRegion();
|
||||
S32 end = (S32) mParticles.size();
|
||||
for (S32 i = 0 ; i < (S32)mParticles.size();)
|
||||
|
||||
// <FS:ND> Instead of walking the current particles back to front, we first make a copy, then sort by adress and refill mParticles as needed.
|
||||
mParticlesTemp.swap( mParticles );
|
||||
mParticles.erase( mParticles.begin(), mParticles.end() );
|
||||
std::sort( mParticlesTemp.begin(), mParticlesTemp.end() );
|
||||
|
||||
// for (S32 i = 0 ; i < (S32)mParticles.size(); )
|
||||
for (S32 i = 0 ; i < (S32)mParticlesTemp.size(); ++i )
|
||||
// </FS:ND>
|
||||
{
|
||||
LLVector3 a(0.f, 0.f, 0.f);
|
||||
LLViewerPart* part = mParticles[i] ;
|
||||
// LLVector3 a(0.f, 0.f, 0.f); // <FS:ND/> Unused
|
||||
LLViewerPart* part = mParticlesTemp[i] ;
|
||||
|
||||
dt = lastdt + mSkippedTime - part->mSkipOffset;
|
||||
part->mSkipOffset = 0.f;
|
||||
|
||||
// Update current time
|
||||
const F32 cur_time = part->mLastUpdateTime + dt;
|
||||
|
||||
// <FS:ND> Bail out as soon as possible to avoid all the complicated work down.
|
||||
if( cur_time > part->mMaxAge || LLViewerPart::LL_PART_DEAD_MASK == part->mFlags )
|
||||
{
|
||||
if (part->mVPCallback)
|
||||
(*part->mVPCallback)(*part, dt);
|
||||
|
||||
delete part ;
|
||||
continue;
|
||||
}
|
||||
// </FS:ND>
|
||||
|
||||
const F32 frac = cur_time / part->mMaxAge;
|
||||
|
||||
// "Drift" the object based on the source object
|
||||
|
|
@ -397,26 +417,34 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt)
|
|||
part->mLastUpdateTime = cur_time;
|
||||
|
||||
|
||||
// <FS:ND> We did that above
|
||||
// Kill dead particles (either flagged dead, or too old)
|
||||
if ((part->mLastUpdateTime > part->mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part->mFlags))
|
||||
{
|
||||
mParticles[i] = mParticles.back() ;
|
||||
mParticles.pop_back() ;
|
||||
delete part ;
|
||||
}
|
||||
else
|
||||
// if ((part->mLastUpdateTime > part->mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part->mFlags))
|
||||
// {
|
||||
// mParticles[i] = mParticles.back() ;
|
||||
// mParticles.pop_back() ;
|
||||
// delete part ;
|
||||
// }
|
||||
// else
|
||||
// </FS:ND>
|
||||
{
|
||||
F32 desired_size = calc_desired_size(camera, part->mPosAgent, part->mScale);
|
||||
if (!posInGroup(part->mPosAgent, desired_size))
|
||||
{
|
||||
// Transfer particles between groups
|
||||
LLViewerPartSim::getInstance()->put(part) ;
|
||||
mParticles[i] = mParticles.back() ;
|
||||
mParticles.pop_back() ;
|
||||
|
||||
// <FS:ND> No need for any transfer, just to not add to mParticles.
|
||||
// mParticles[i] = mParticles.back() ;
|
||||
// mParticles.pop_back() ;
|
||||
// </FS:ND>
|
||||
}
|
||||
else
|
||||
{
|
||||
i++ ;
|
||||
// <FS:ND> Keep current particle in this group.
|
||||
// i++ ;
|
||||
mParticles.push_back( part );
|
||||
// </FS:ND>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -892,3 +920,76 @@ void LLViewerPartSim::clearParticlesByOwnerID(const LLUUID& task_id)
|
|||
}
|
||||
}
|
||||
|
||||
// <FS:ND> Object pool for LLViewerPart
|
||||
U8 *sParts;
|
||||
U8 *sPartsEnd;
|
||||
U32 sFree[ LL_MAX_PARTICLE_COUNT/32 ];
|
||||
U32 sPartSize;
|
||||
|
||||
S32 findFreeIndex()
|
||||
{
|
||||
for( int i = 0; i < LL_MAX_PARTICLE_COUNT/32; ++i )
|
||||
{
|
||||
if( sFree[i] )
|
||||
{
|
||||
U32 val = sFree[i];
|
||||
U32 mask = 1;
|
||||
int j(0);
|
||||
for( j = 0; j < 32; ++j )
|
||||
{
|
||||
if( mask & val )
|
||||
{
|
||||
mask = ~mask;
|
||||
break;
|
||||
}
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
sFree[ i ] = val & mask;
|
||||
return i*32+j;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void* LLViewerPart::operator new(size_t size)
|
||||
{
|
||||
if( !sParts )
|
||||
{
|
||||
sPartSize = sizeof( LLViewerPart );
|
||||
sPartSize += 0xF;
|
||||
sPartSize &= ~0xF;
|
||||
sParts = reinterpret_cast<U8*>( ll_aligned_malloc<16>( sPartSize * LL_MAX_PARTICLE_COUNT ) );
|
||||
for( int i = 0; i < LL_MAX_PARTICLE_COUNT/32; ++i )
|
||||
sFree[ i ] = 0xFFFFFFFF;
|
||||
|
||||
sPartsEnd = sParts + sPartSize * LL_MAX_PARTICLE_COUNT;
|
||||
}
|
||||
|
||||
S32 i = findFreeIndex();
|
||||
if( i < 0 )
|
||||
return new char[ size ];
|
||||
|
||||
return reinterpret_cast< void* >( sParts + sPartSize*i );
|
||||
}
|
||||
|
||||
void LLViewerPart::operator delete(void* ptr)
|
||||
{
|
||||
if( ptr < sParts || ptr >= sPartsEnd )
|
||||
{
|
||||
delete [] (char*)ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
U32 diff = static_cast<U32>( reinterpret_cast<U8*>(ptr) - sParts );
|
||||
diff /= sPartSize;
|
||||
|
||||
U32 i = (diff & ~0x0000001F) / 32;
|
||||
U32 j = diff & 0x0000001F;
|
||||
|
||||
U32 mask = 1 << j;
|
||||
|
||||
sFree[ i ] |= mask;
|
||||
}
|
||||
// </FS:ND>
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ public:
|
|||
|
||||
|
||||
static U32 sNextPartID;
|
||||
// <FS:ND> Object pool for LLViewerPart
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* ptr);
|
||||
// </FS:ND>
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -108,6 +112,7 @@ public:
|
|||
|
||||
typedef std::vector<LLViewerPart*> part_list_t;
|
||||
part_list_t mParticles;
|
||||
part_list_t mParticlesTemp; // <FS:ND/> Temporary list for iteration in updateParticles
|
||||
|
||||
const LLVector3 &getCenterAgent() const { return mCenterAgent; }
|
||||
S32 getCount() const { return (S32) mParticles.size(); }
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ extern U64MicrosecondsImplicit gFrameTime;
|
|||
LLPointer<LLVertexBuffer> LLVOPartGroup::sVB = NULL;
|
||||
S32 LLVOPartGroup::sVBSlotCursor = 0;
|
||||
|
||||
#include "fsvopartgroup.cpp"
|
||||
|
||||
void LLVOPartGroup::initClass()
|
||||
{
|
||||
|
||||
|
|
@ -59,6 +61,11 @@ void LLVOPartGroup::initClass()
|
|||
//static
|
||||
void LLVOPartGroup::restoreGL()
|
||||
{
|
||||
sIndexGeneration += 2;
|
||||
|
||||
for( int i = 0; i < LL_MAX_PARTICLE_COUNT/32; ++i )
|
||||
sFreeIndex[i] = 0xFFFFFFFF;
|
||||
|
||||
|
||||
//TODO: optimize out binormal mask here. Specular and normal coords as well.
|
||||
sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, GL_STREAM_DRAW_ARB);
|
||||
|
|
@ -118,12 +125,39 @@ void LLVOPartGroup::destroyGL()
|
|||
//static
|
||||
S32 LLVOPartGroup::findAvailableVBSlot()
|
||||
{
|
||||
if (sVBSlotCursor >= LL_MAX_PARTICLE_COUNT)
|
||||
{ //no more available slots
|
||||
return -1;
|
||||
for( int i = 0; i < LL_MAX_PARTICLE_COUNT/32; ++i )
|
||||
{
|
||||
if( sFreeIndex[i] != 0 )
|
||||
{
|
||||
U32 val = sFreeIndex[i];
|
||||
U32 mask = 1;
|
||||
int j(0);
|
||||
for( j = 0; j < 32; ++j )
|
||||
{
|
||||
if( mask & val )
|
||||
{
|
||||
mask = ~mask;
|
||||
break;
|
||||
}
|
||||
|
||||
mask <<= 1;
|
||||
}
|
||||
|
||||
sFreeIndex[ i ] = val & mask;
|
||||
++sTotalParticles;
|
||||
|
||||
return i*32+j;
|
||||
}
|
||||
}
|
||||
|
||||
return sVBSlotCursor++;
|
||||
return -1;
|
||||
|
||||
// if (sVBSlotCursor >= LL_MAX_PARTICLE_COUNT)
|
||||
// { //no more available slots
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
// return sVBSlotCursor++;
|
||||
}
|
||||
|
||||
bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
|
||||
|
|
@ -142,7 +176,8 @@ bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
|
|||
}
|
||||
|
||||
//static
|
||||
void LLVOPartGroup::freeVBSlot(S32 idx)
|
||||
// void LLVOPartGroup::freeVBSlot(S32 idx)
|
||||
void LLVOPartGroup::freeVBSlot(S32 idx, U32 generation )
|
||||
{
|
||||
/*llassert(idx < LL_MAX_PARTICLE_COUNT && idx >= 0);
|
||||
//llassert(sVBSlotCursor > sVBSlotFree);
|
||||
|
|
@ -153,6 +188,21 @@ void LLVOPartGroup::freeVBSlot(S32 idx)
|
|||
sVBSlotCursor--;
|
||||
*sVBSlotCursor = idx;
|
||||
}*/
|
||||
|
||||
if( idx < 0 || idx >= LL_MAX_PARTICLE_COUNT )
|
||||
return;
|
||||
|
||||
--sTotalParticles;
|
||||
|
||||
if( sIndexGeneration != generation )
|
||||
return;
|
||||
|
||||
U32 i = (idx & ~0x0000001F) / 32;
|
||||
U32 j = idx & 0x0000001F;
|
||||
|
||||
U32 mask = 1 << j;
|
||||
|
||||
sFreeIndex[ i ] |= mask;
|
||||
}
|
||||
|
||||
LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
|
||||
|
|
@ -859,6 +909,14 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
|
|||
|
||||
LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];
|
||||
|
||||
// <FS:ND> Free all vb slots. Then try to allocate an adjacent block of slots for all faces
|
||||
for( std::vector<LLFace*>::iterator itr = mFaceList.begin(); itr != mFaceList.end(); ++itr )
|
||||
(*itr)->setGeomIndex( 0 );
|
||||
|
||||
S32 idxStart, idxEnd;
|
||||
bool bValidRange = findAvailableVBSlots( idxStart, idxEnd, mFaceList.size() );
|
||||
// </FS:ND>
|
||||
|
||||
for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
|
||||
{
|
||||
LLFace* facep = *i;
|
||||
|
|
@ -866,10 +924,26 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
|
|||
|
||||
//if (!facep->isState(LLFace::PARTICLE))
|
||||
{ //set the indices of this face
|
||||
S32 idx = LLVOPartGroup::findAvailableVBSlot();
|
||||
|
||||
// <FS:ND> Can we use a index from our preallocated list?
|
||||
// S32 idx = LLVOPartGroup::findAvailableVBSlot();
|
||||
S32 idx(-1);
|
||||
if( bValidRange )
|
||||
{
|
||||
if( idxStart < idxEnd )
|
||||
idx = idxStart++;
|
||||
}
|
||||
else
|
||||
idx = LLVOPartGroup::findAvailableVBSlot();
|
||||
// <FS:ND>
|
||||
|
||||
if (idx >= 0)
|
||||
{
|
||||
facep->setGeomIndex(idx*4);
|
||||
// <FS:ND> Face needs to release the index when it gets destroyed.
|
||||
// facep->setGeomIndex(idx*4);
|
||||
facep->setGeomIndex(idx*4, sIndexGeneration);
|
||||
// <FS:ND>
|
||||
|
||||
facep->setIndicesIndex(idx*6);
|
||||
facep->setVertexBuffer(LLVOPartGroup::sVB);
|
||||
facep->setPoolType(LLDrawPool::POOL_ALPHA);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ public:
|
|||
static void restoreGL();
|
||||
static void destroyGL();
|
||||
static S32 findAvailableVBSlot();
|
||||
static void freeVBSlot(S32 idx);
|
||||
|
||||
// static void freeVBSlot(S32 idx);
|
||||
static void freeVBSlot(S32 idx, U32 generation);
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue