phoenix-firestorm/indra/newview/lldrawpool.cpp

1399 lines
30 KiB
C++

/**
* @file lldrawpool.cpp
* @brief LLDrawPool class implementation
*
* Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
* $License$
*/
#include "llviewerprecompiledheaders.h"
#include "lldrawpool.h"
#include "llfasttimer.h"
#include "llviewercontrol.h"
#include "llagparray.h"
#include "lldrawable.h"
#include "lldrawpoolalpha.h"
#include "lldrawpoolavatar.h"
#include "lldrawpoolbump.h"
#include "lldrawpoolclouds.h"
#include "lldrawpoolground.h"
#include "lldrawpoolsimple.h"
#include "lldrawpoolsky.h"
#include "lldrawpoolstars.h"
#include "lldrawpooltree.h"
#include "lldrawpooltreenew.h"
#include "lldrawpoolterrain.h"
#include "lldrawpoolwater.h"
#include "lldrawpoolhud.h"
#include "llface.h"
#include "llviewerobjectlist.h" // For debug listing.
#include "llvotreenew.h"
#include "pipeline.h"
#include "llagparray.inl"
U32 LLDrawPool::sDataSizes[LLDrawPool::DATA_MAX_TYPES] =
{
12, // DATA_VERTICES
8, // DATA_TEX_COORDS0
8, // DATA_TEX_COORDS1
8, // DATA_TEX_COORDS2
8, // DATA_TEX_COORDS3
12, // DATA_NORMALS
4, // DATA_VERTEX_WEIGHTS,
16, // DATA_CLOTHING_WEIGHTS
12, // DATA_BINORMALS
4, // DATA_COLORS
};
S32 LLDrawPool::sNumDrawPools = 0;
LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0)
{
LLDrawPool *poolp = NULL;
switch (type)
{
case POOL_SIMPLE:
poolp = new LLDrawPoolSimple(tex0);
break;
case POOL_ALPHA:
poolp = new LLDrawPoolAlpha();
break;
case POOL_AVATAR:
poolp = new LLDrawPoolAvatar();
break;
case POOL_TREE:
poolp = new LLDrawPoolTree(tex0);
break;
case POOL_TREE_NEW:
poolp = new LLDrawPoolTreeNew(tex0);
break;
case POOL_TERRAIN:
poolp = new LLDrawPoolTerrain(tex0);
break;
case POOL_SKY:
poolp = new LLDrawPoolSky();
break;
case POOL_STARS:
poolp = new LLDrawPoolStars();
break;
case POOL_CLOUDS:
poolp = new LLDrawPoolClouds();
break;
case POOL_WATER:
poolp = new LLDrawPoolWater();
break;
case POOL_GROUND:
poolp = new LLDrawPoolGround();
break;
case POOL_BUMP:
poolp = new LLDrawPoolBump(tex0);
break;
case POOL_HUD:
poolp = new LLDrawPoolHUD();
break;
default:
llerrs << "Unknown draw pool type!" << llendl;
return NULL;
}
llassert(poolp->mType == type);
return poolp;
}
LLDrawPool::LLDrawPool(const U32 type, const U32 data_mask_il, const U32 data_mask_nil)
{
llassert(data_mask_il & DATA_VERTICES_MASK);
S32 i;
mType = type;
sNumDrawPools++;
mId = sNumDrawPools;
mDataMaskIL = data_mask_il;
mDataMaskNIL = data_mask_nil;
U32 cur_mask = 0x01;
U32 cur_offset = 0;
for (i = 0; i < DATA_MAX_TYPES; i++)
{
mDataOffsets[i] = cur_offset;
if (cur_mask & mDataMaskIL)
{
cur_offset += sDataSizes[i];
}
cur_mask <<= 1;
}
mStride = cur_offset;
mCleanupUnused = FALSE;
mIndicesDrawn = 0;
mRebuildFreq = 128 + rand() % 5;
mRebuildTime = 0;
mGeneration = 1;
mSkippedVertices = 0;
resetDrawOrders();
resetVertexData(0);
if (gGLManager.mHasATIVAO && !gGLManager.mIsRadeon9700)
{
// ATI 8500 doesn't like indices > 15 bit.
mMaxVertices = DEFAULT_MAX_VERTICES/2;
}
else
{
mMaxVertices = DEFAULT_MAX_VERTICES;
}
// JC: This must happen last, as setUseAGP reads many of the
// above variables.
mUseAGP = FALSE;
setUseAGP(gPipeline.usingAGP());
for (i=0; i<NUM_BUCKETS; i++)
{
mFreeListGeomHead[i] = -1;
mFreeListIndHead[i] = -1;
}
mVertexShaderLevel = 0;
}
void LLDrawPool::destroy()
{
if (!mReferences.empty())
{
llinfos << mReferences.size() << " references left on deletion of draw pool!" << llendl;
}
}
LLDrawPool::~LLDrawPool()
{
destroy();
llassert( gPipeline.findPool( getType(), getTexture() ) == NULL );
}
BOOL LLDrawPool::setUseAGP(BOOL use_agp)
{
BOOL ok = TRUE;
S32 vertex_count = mMemory.count() / mStride;
if (vertex_count > mMaxVertices && use_agp)
{
#ifdef DEBUG_AGP
llwarns << "Allocating " << vertex_count << " vertices in pool type " << getType() << ", disabling AGP!" << llendl
#endif
use_agp = FALSE;
ok = FALSE;
}
if (mUseAGP != use_agp)
{
mUseAGP = use_agp;
BOOL ok = TRUE;
ok &= mMemory.setUseAGP(use_agp);
if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK)
{
ok &= mWeights.setUseAGP(use_agp);
}
if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK)
{
ok &= mClothingWeights.setUseAGP(use_agp);
}
if (!ok)
{
// Disable AGP if any one of these doesn't have AGP, we don't want to try
// mixing AGP and non-agp arrays in a single pool.
#ifdef DEBUG_AGP
llinfos << "Aborting using AGP because set failed on a mem block!" << llendl;
#endif
setUseAGP(FALSE);
ok = FALSE;
}
}
return ok;
}
void LLDrawPool::flushAGP()
{
mMemory.flushAGP();
if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK)
{
mWeights.flushAGP();
}
if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK)
{
mClothingWeights.flushAGP();
}
}
void LLDrawPool::syncAGP()
{
if (!getVertexCount())
{
return;
}
setUseAGP(gPipeline.usingAGP());
BOOL all_agp_on = TRUE;
mMemory.sync();
all_agp_on &= mMemory.isAGP();
if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK)
{
mWeights.sync();
all_agp_on &= mWeights.isAGP();
}
if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK)
{
mClothingWeights.sync();
all_agp_on &= mClothingWeights.isAGP();
}
// Since sometimes AGP allocation is done during syncs, we need
// to make sure that if AGP allocation fails, we fallback to non-agp.
if (mUseAGP && !all_agp_on)
{
#ifdef DEBUG_AGP
llinfos << "setUseAGP false because of AGP sync failure!" << llendl;
#endif
setUseAGP(FALSE);
}
}
void LLDrawPool::dirtyTexture(const LLViewerImage *imagep)
{
}
BOOL LLDrawPool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data)
{
return TRUE;
}
// static
S32 LLDrawPool::drawLoop(face_array_t& face_list, const U32* index_array)
{
S32 res = 0;
if (!face_list.empty())
{
for (std::vector<LLFace*>::iterator iter = face_list.begin();
iter != face_list.end(); iter++)
{
LLFace *facep = *iter;
if (facep->mSkipRender)
{
continue;
}
facep->enableLights();
res += facep->renderIndexed(index_array);
}
}
return res;
}
// static
S32 LLDrawPool::drawLoopSetTex(face_array_t& face_list, const U32* index_array, S32 stage)
{
S32 res = 0;
if (!face_list.empty())
{
for (std::vector<LLFace*>::iterator iter = face_list.begin();
iter != face_list.end(); iter++)
{
LLFace *facep = *iter;
if (facep->mSkipRender)
{
continue;
}
facep->bindTexture(stage);
facep->enableLights();
res += facep->renderIndexed(index_array);
}
}
return res;
}
void LLDrawPool::drawLoop()
{
const U32* index_array = getRawIndices();
if (!mDrawFace.empty())
{
mIndicesDrawn += drawLoop(mDrawFace, index_array);
}
}
BOOL LLDrawPool::getVertexStrider(LLStrider<LLVector3> &vertices, const U32 index)
{
llassert(mDataMaskIL & LLDrawPool::DATA_VERTICES_MASK);
vertices = (LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_VERTICES] + index * mStride);
vertices.setStride(mStride);
return TRUE;
}
BOOL LLDrawPool::getTexCoordStrider(LLStrider<LLVector2> &tex_coords, const U32 index, const U32 pass)
{
llassert(mDataMaskIL & (LLDrawPool::DATA_TEX_COORDS0_MASK << pass));
tex_coords = (LLVector2*)(mMemory.getMem() + mDataOffsets[DATA_TEX_COORDS0 + pass] + index * mStride);
tex_coords.setStride(mStride);
return TRUE;
}
BOOL LLDrawPool::getVertexWeightStrider(LLStrider<F32> &vertex_weights, const U32 index)
{
llassert(mDataMaskNIL & LLDrawPool::DATA_VERTEX_WEIGHTS_MASK);
vertex_weights = &mWeights[index];
vertex_weights.setStride( 0 );
return TRUE;
}
BOOL LLDrawPool::getClothingWeightStrider(LLStrider<LLVector4> &clothing_weights, const U32 index)
{
llassert(mDataMaskNIL & LLDrawPool::DATA_CLOTHING_WEIGHTS_MASK);
clothing_weights= &mClothingWeights[index];
clothing_weights.setStride( 0 );
return TRUE;
}
BOOL LLDrawPool::getNormalStrider(LLStrider<LLVector3> &normals, const U32 index)
{
llassert((mDataMaskIL) & LLDrawPool::DATA_NORMALS_MASK);
normals = (LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_NORMALS] + index * mStride);
normals.setStride( mStride );
return TRUE;
}
BOOL LLDrawPool::getBinormalStrider(LLStrider<LLVector3> &binormals, const U32 index)
{
llassert((mDataMaskIL) & LLDrawPool::DATA_BINORMALS_MASK);
binormals = (LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_BINORMALS] + index * mStride);
binormals.setStride( mStride );
return TRUE;
}
BOOL LLDrawPool::getColorStrider(LLStrider<LLColor4U> &colors, const U32 index)
{
llassert((mDataMaskIL) & LLDrawPool::DATA_COLORS_MASK);
colors = (LLColor4U*)(mMemory.getMem() + mDataOffsets[DATA_COLORS] + index * mStride);
colors.setStride( mStride );
return TRUE;
}
//virtual
void LLDrawPool::beginRenderPass( S32 pass )
{
}
//virtual
void LLDrawPool::endRenderPass( S32 pass )
{
glDisableClientState ( GL_TEXTURE_COORD_ARRAY );
glDisableClientState ( GL_COLOR_ARRAY );
glDisableClientState ( GL_NORMAL_ARRAY );
}
void LLDrawPool::renderFaceSelected(LLFace *facep,
LLImageGL *image,
const LLColor4 &color,
const S32 index_offset, const S32 index_count)
{
}
void LLDrawPool::renderVisibility()
{
if (mDrawFace.empty())
{
return;
}
// SJB: Note: This may be broken now. If you need it, fix it :)
glLineWidth(1.0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(-0.4f,-0.3f,0);
float table[7][3] = {
{ 1,0,0 },
{ 0,1,0 },
{ 1,1,0 },
{ 0,0,1 },
{ 1,0,1 },
{ 0,1,1 },
{ 1,1,1 }
};
glColor4f(0,0,0,0.5);
glBegin(GL_POLYGON);
glVertex3f(-0.5f,-0.5f,1.0f);
glVertex3f(+0.5f,-0.5f,1.0f);
glVertex3f(+0.5f,+0.5f,1.0f);
glVertex3f(-0.5f,+0.5f,1.0f);
glVertex3f(-0.5f,-0.5f,1.0f);
glEnd();
for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
{
LLFace *face = *iter;
S32 geom_count = face->getGeomCount();
for (S32 j=0;j<geom_count;j++)
{
LLVector3 p1;
LLVector3 p2;
intptr_t p = ((intptr_t)face*13) % 7;
F32 r = table[p][0];
F32 g = table[p][1];
F32 b = table[p][2];
//p1.mV[1] = y;
//p2.mV[1] = y;
p1.mV[2] = 1.0;
p2.mV[2] = 1.0;
glColor4f(r,g,b,0.5f);
glBegin(GL_LINE_STRIP);
glVertex3fv(p1.mV);
glVertex3fv(p2.mV);
glEnd();
}
}
glColor4f(1,1,1,1);
glBegin(GL_LINE_STRIP);
glVertex3f(-0.5f,-0.5f,1.0f);
glVertex3f(+0.5f,-0.5f,1.0f);
glVertex3f(+0.5f,+0.5f,1.0f);
glVertex3f(-0.5f,+0.5f,1.0f);
glVertex3f(-0.5f,-0.5f,1.0f);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void LLDrawPool::enqueue(LLFace* facep)
{
if (facep->isState(LLFace::BACKLIST))
{
mMoveFace.put(facep);
}
else
{
#if ENABLE_FACE_LINKING
facep->mSkipRender = FALSE;
facep->mNextFace = NULL;
if (mDrawFace.size() > 0)
{
LLFace* last_face = mDrawFace[mDrawFace.size()-1];
if (match(last_face, facep))
{
last_face->link(facep);
}
}
#endif
mDrawFace.put(facep);
}
}
void LLDrawPool::bindGLVertexPointer()
{
mMemory.bindGLVertexPointer(getStride(DATA_VERTICES), mDataOffsets[DATA_VERTICES]);
}
void LLDrawPool::bindGLTexCoordPointer(const U32 pass)
{
mMemory.bindGLTexCoordPointer(getStride(DATA_TEX_COORDS0+pass), mDataOffsets[DATA_TEX_COORDS0+pass]);
}
void LLDrawPool::bindGLNormalPointer()
{
mMemory.bindGLNormalPointer(getStride(DATA_NORMALS), mDataOffsets[DATA_NORMALS]);
}
void LLDrawPool::bindGLBinormalPointer(S32 index)
{
mMemory.bindGLBinormalPointer(index, getStride(DATA_BINORMALS), mDataOffsets[DATA_BINORMALS]);
}
void LLDrawPool::bindGLColorPointer()
{
mMemory.bindGLColorPointer(getStride(DATA_COLORS), mDataOffsets[DATA_COLORS]);
}
void LLDrawPool::bindGLVertexWeightPointer(S32 index)
{
mWeights.bindGLVertexWeightPointer(index, 0, 0);
}
void LLDrawPool::bindGLVertexClothingWeightPointer(S32 index)
{
mClothingWeights.bindGLVertexClothingWeightPointer(index, 0, 0);
}
U32* LLDrawPool::getIndices(S32 index)
{
return &mIndices[index];
}
const LLVector3& LLDrawPool::getVertex(const S32 index)
{
llassert(mDataMaskIL & DATA_VERTICES_MASK);
llassert(index < mMemory.count());
llassert(mMemory.getMem());
return *(LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_VERTICES] + index * mStride);
}
const LLVector2& LLDrawPool::getTexCoord(const S32 index, const U32 pass)
{
llassert(mDataMaskIL & (LLDrawPool::DATA_TEX_COORDS0_MASK << pass));
llassert(index < mMemory.count());
return *(LLVector2*)(mMemory.getMem() + mDataOffsets[DATA_TEX_COORDS0 + pass] + index * mStride);
}
const LLVector3& LLDrawPool::getNormal(const S32 index)
{
llassert(mDataMaskIL & DATA_NORMALS_MASK);
llassert(index < mMemory.count());
return *(LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_NORMALS] + index * mStride);
}
const LLVector3& LLDrawPool::getBinormal(const S32 index)
{
llassert(mDataMaskIL & DATA_BINORMALS_MASK);
llassert(index < mMemory.count());
return *(LLVector3*)(mMemory.getMem() + mDataOffsets[DATA_BINORMALS] + index * mStride);
}
const LLColor4U& LLDrawPool::getColor(const S32 index)
{
llassert(mDataMaskIL & DATA_COLORS_MASK);
llassert(index < mMemory.count());
return *(LLColor4U*)(mMemory.getMem() + mDataOffsets[DATA_COLORS] + index * mStride);
}
const F32& LLDrawPool::getVertexWeight(const S32 index)
{
llassert(mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK);
llassert(index < mWeights.count());
llassert(mWeights.getMem());
return mWeights[index];
}
const LLVector4& LLDrawPool::getClothingWeight(const S32 index)
{
llassert(mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK);
llassert(index < mClothingWeights.count());
llassert(mClothingWeights.getMem());
return mClothingWeights[index];
}
//////////////////////////////////////////////////////////////////////////////
#define USE_FREE_LIST 0
#define DEBUG_FREELIST 0
struct tFreeListNode
{
U32 count;
S32 next;
};
#if DEBUG_FREELIST
static void check_list(U8 *pool, S32 stride, S32 head, S32 max)
{
int count = 0;
while (head >= 0)
{
tFreeListNode *node = (tFreeListNode *)(pool + head*stride);
count++;
if ((count > max) || ((node->count>>20) != 0xabc) || ((node->count&0xfffff) < 2))
llerrs << "Bad Ind List" << llendl;
head = node->next;
}
}
#define CHECK_LIST(x) check_list##x
#else
#define CHECK_LIST(x)
#endif
// DEBUG!
void LLDrawPool::CheckIntegrity()
{
#if DEBUG_FREELIST
int bucket;
for (bucket=0; bucket<NUM_BUCKETS; bucket++)
{
CHECK_LIST(((U8 *)mMemory.getMem(), mStride, mFreeListGeomHead[bucket], mMemory.count() / mStride));
CHECK_LIST(((U8 *)mIndices.getMem(), 4, mFreeListIndHead[bucket], mIndices.count()));
}
#endif
}
int LLDrawPool::freeListBucket(U32 count)
{
int bucket;
// llassert(NUM_BUCKETS == 8)
if (count & ~511) // >= 512
bucket = 7;
else if (count & 256) // 256-511
bucket = 6;
else if (count & 128)
bucket = 5;
else if (count & 64)
bucket = 4;
else if (count & 32)
bucket = 3;
else if (count & 16)
bucket = 2;
else if (count & 8) // 8-15
bucket = 1;
else // 0-7
bucket = 0;
return bucket;
}
void remove_node(int nodeidx, int pidx, U8 *membase, int stride, int *head)
{
LLDrawPool::FreeListNode *node = (LLDrawPool::FreeListNode *)(membase + nodeidx*stride);
if (pidx >= 0)
{
LLDrawPool::FreeListNode *pnode = (LLDrawPool::FreeListNode *)(membase + pidx*stride);
pnode->next = node->next;
}
else
{
*head = node->next;
}
}
void LLDrawPool::freeListAddGeom(S32 index, U32 count)
{
#if USE_FREE_LIST
int i;
U8 *membase = (U8*)mMemory.getMem();
// See if next block or previous block is free, if so combine them
for (i=0; i<NUM_BUCKETS; i++)
{
int pidx = -1;
int nodeidx = mFreeListGeomHead[i];
while(nodeidx >= 0)
{
int change = 0;
FreeListNode *node = (FreeListNode *)(membase + nodeidx*mStride);
int nodecount = node->count & 0xffff;
// Check for prev block
if (nodeidx + nodecount == index)
{
remove_node(nodeidx, pidx, membase, mStride, &mFreeListGeomHead[i]);
// Combine nodes
index = nodeidx;
count += nodecount;
i = 0; // start over ; i = NUM_BUCKETS // done
change = 1;
//break;
}
// Check for next block
if (nodeidx == index + count)
{
remove_node(nodeidx, pidx, membase, mStride, &mFreeListGeomHead[i]);
// Combine nodes
count += nodecount;
i = 0; // start over ; i = NUM_BUCKETS // done
change = 1;
//break;
}
if (change)
break;
pidx = nodeidx;
nodeidx = node->next;
}
}
// Add (extended) block to free list
if (count >= 2) // need 2 words to store free list (theoreticly mStride could = 4)
{
CheckIntegrity();
if ((index + count)*mStride >= mMemory.count())
{
mMemory.shrinkTo(index*mStride);
}
else
{
int bucket = freeListBucket(count);
FreeListNode *node = (FreeListNode *)(membase + index*mStride);
node->count = count | (0xabc<<20);
node->next = mFreeListGeomHead[bucket];
mFreeListGeomHead[bucket] = index;
}
CheckIntegrity();
}
#endif
}
void LLDrawPool::freeListAddInd(S32 index, U32 count)
{
#if USE_FREE_LIST
int i;
const U32 *membase = mIndices.getMem();
// See if next block or previous block is free, if so combine them
for (i=0; i<NUM_BUCKETS; i++)
{
int pidx = -1;
int nodeidx = mFreeListIndHead[i];
while(nodeidx >= 0)
{
int change = 0;
FreeListNode *node = (FreeListNode *)(membase + nodeidx);
int nodecount = node->count & 0xffff;
// Check for prev block
if (nodeidx + nodecount == index)
{
remove_node(nodeidx, pidx, (U8*)membase, 4, &mFreeListIndHead[i]);
// Combine nodes
index = nodeidx;
count += nodecount;
i = 0; // start over ; i = NUM_BUCKETS // done
change = 1;
//break;
}
// Check for next block
if (nodeidx == index + count)
{
remove_node(nodeidx, pidx, (U8*)membase, 4, &mFreeListIndHead[i]);
// Combine nodes
count += nodecount;
i = 0; // start over ; i = NUM_BUCKETS // done
change = 1;
//break;
}
if (change)
break;
pidx = nodeidx;
nodeidx = node->next;
}
}
// Add (extended) block to free list
if (count >= 2) // need 2 words to store free list
{
CheckIntegrity();
if (index + count >= mIndices.count())
{
mIndices.shrinkTo(index);
}
else
{
int bucket = freeListBucket(count);
FreeListNode *node = (FreeListNode *)(membase + index);
node->count = count | (0xabc<<20);
node->next = mFreeListIndHead[bucket];
mFreeListIndHead[bucket] = index;
}
CheckIntegrity();
}
#endif
}
S32 LLDrawPool::freeListFindGeom(U32 count)
{
#if USE_FREE_LIST
int i, nodeidx, pidx;
int firstbucket = freeListBucket(count);
U8 *membase = (U8*)mMemory.getMem();
for (i=firstbucket; i<NUM_BUCKETS; i++)
{
pidx = -1;
nodeidx = mFreeListGeomHead[i];
CHECK_LIST(((U8 *)mMemory.getMem(), mStride, mFreeListGeomHead[i], mMemory.count() / mStride));
while(nodeidx >= 0)
{
FreeListNode *node = (FreeListNode *)(membase + nodeidx*mStride);
int nodecount = node->count & 0xffff;
llassert((node->count>>20) == 0xabc);
if (nodecount >= count)
{
remove_node(nodeidx, pidx, membase, mStride, &mFreeListGeomHead[i]);
#if 1
if (nodecount > count)
{
int leftover = nodecount - count;
freeListAddGeom(nodeidx + count, leftover);
}
#endif
return nodeidx;
}
pidx = nodeidx;
nodeidx = node->next;
}
}
#endif // USE_FREE_LIST
return -1;
}
S32 LLDrawPool::freeListFindInd(U32 count)
{
#if USE_FREE_LIST
int i, nodeidx, pidx;
int firstbucket = freeListBucket(count);
U32 *membase = (U32 *)mIndices.getMem();
for (i=firstbucket; i<NUM_BUCKETS; i++)
{
pidx = -1;
nodeidx = mFreeListIndHead[i];
CHECK_LIST(((U8 *)mIndices.getMem(), 4, mFreeListIndHead[i], mIndices.count()));
while(nodeidx >= 0)
{
FreeListNode *node = (FreeListNode *)(membase + nodeidx);
int nodecount = node->count & 0xffff;
llassert((node->count>>20) == 0xabc);
if (nodecount >= count)
{
remove_node(nodeidx, pidx, (U8*)membase, 4, &mFreeListIndHead[i]);
#if 1
if (nodecount > count)
{
int leftover = nodecount - count;
freeListAddInd(nodeidx + count, leftover);
}
#endif
return nodeidx;
}
pidx = nodeidx;
nodeidx = node->next;
}
}
#endif // USE_FREE_LIST
return -1;
}
//////////////////////////////////////////////////////////////////////////////
S32 LLDrawPool::reserveGeom(const U32 geom_count)
{
LLFastTimer t(LLFastTimer::FTM_GEO_RESERVE);
S32 index;
index = freeListFindGeom(geom_count);
if (index < 0)
{
index = mMemory.count() / mStride;
if (!geom_count)
{
llwarns << "Attempting to reserve zero bytes!" << llendl;
return index;
}
S32 bytes = geom_count * mStride;
if ((index + (S32)geom_count) > (S32)mMaxVertices)
{
//
// Various drivers have issues with the number of indices being greater than a certain number.
// if you're using AGP. Disable AGP if we've got more vertices than in the pool.
//
#ifdef DEBUG_AGP
llinfos << "setUseAGP false because of large vertex count in reserveGeom" << llendl;
#endif
setUseAGP(FALSE);
}
mMemory.reserve_block(bytes);
if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK)
{
mWeights.reserve_block(geom_count);
}
if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK)
{
mClothingWeights.reserve_block(geom_count);
}
}
CHECK_LIST(((U8 *)mMemory.getMem(), mStride, mFreeListGeomHead[0], mMemory.count() / mStride));
return index;
}
S32 LLDrawPool::reserveInd(U32 indCount)
{
S32 index;
index = freeListFindInd(indCount);
if (index < 0)
{
index = mIndices.count();
if (indCount)
{
mIndices.reserve_block(indCount);
}
}
for (U32 i=0;i<indCount;i++)
{
mIndices[index+i]=0;
}
CHECK_LIST(((U8 *)mIndices.getMem(), 4, mFreeListIndHead[0], mIndices.count()));
return index;
}
S32 LLDrawPool::unReserveGeom(const S32 index, const U32 count)
{
if (index < 0 || count == 0)
return -1;
freeListAddGeom(index, count);
#if 0
int i;
S32 bytes,words;
U32 *memp;
// Fill mem with bad data (for testing only)
bytes = count * mStride;
bytes -= sizeof(FreeListNode);
memp = (U32*)(mMemory.getMem() + index * mStride);
memp += sizeof(FreeListNode)>>2;
words = bytes >> 2;
for (i=0; i<words; i++)
*memp++ = 0xffffffff;
words = count; // (sizeof each array is a word)
if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK)
{
memp = (U32*)(&mWeights[index]);
for (i=0; i<words; i++)
*memp++ = 0xffffffff;
}
if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK)
{
memp = (U32*)(&mClothingWeights[index]);
for (i=0; i<count; i++)
*memp++ = 0xffffffff;
}
#endif
return -1;
}
S32 LLDrawPool::unReserveInd(const S32 index, const U32 count)
{
if (index < 0 || count == 0)
return -1;
freeListAddInd(index, count);
#if 0
int i;
U32 *memp = &mIndices[index];
for (i=0; i<count; i++)
*memp++ = 0xffffffff;
#endif
return -1;
}
//////////////////////////////////////////////////////////////////////////////
const U32 LLDrawPool::getIndexCount() const
{
return mIndices.count();
}
const U32 LLDrawPool::getVertexCount() const
{
return mMemory.count() / mStride;
}
const U32 LLDrawPool::getTexCoordCount(U32 pass) const
{
return mMemory.count() / mStride;
}
const U32 LLDrawPool::getNormalCount() const
{
return mMemory.count() / mStride;
}
const U32 LLDrawPool::getBinormalCount() const
{
return mMemory.count() / mStride;
}
const U32 LLDrawPool::getColorCount() const
{
return mMemory.count() / mStride;
}
const U32 LLDrawPool::getVertexWeightCount() const
{
return mWeights.count();
}
// virtual
BOOL LLDrawPool::addFace(LLFace *facep)
{
addFaceReference(facep);
return TRUE;
}
// virtual
BOOL LLDrawPool::removeFace(LLFace *facep)
{
removeFaceReference(facep);
vector_replace_with_last(mDrawFace, facep);
facep->unReserve();
return TRUE;
}
// Not absolutely sure if we should be resetting all of the chained pools as well - djs
void LLDrawPool::resetDrawOrders()
{
mDrawFace.resize(0);
}
void LLDrawPool::resetIndices(S32 indices_count)
{
mIndices.reset(indices_count);
for (S32 i=0; i<NUM_BUCKETS; i++)
mFreeListIndHead[i] = -1;
}
void LLDrawPool::resetVertexData(S32 reserve_count)
{
mMemory.reset(reserve_count*mStride);
for (S32 i=0; i<NUM_BUCKETS; i++)
{
mFreeListGeomHead[i] = -1;
}
if (mDataMaskNIL & DATA_VERTEX_WEIGHTS_MASK)
{
mWeights.reset(reserve_count);
}
if (mDataMaskNIL & DATA_CLOTHING_WEIGHTS_MASK)
{
mClothingWeights.reset(reserve_count);
}
}
void LLDrawPool::resetAll()
{
resetDrawOrders();
resetVertexData(0);
mGeneration++;
}
S32 LLDrawPool::rebuild()
{
mRebuildTime++;
BOOL needs_rebuild = FALSE;
S32 rebuild_cost = 0;
if (mUseAGP)
{
if (getVertexCount() > 0.75f*DEFAULT_MAX_VERTICES)
{
if (mRebuildTime > 8)
{
needs_rebuild = TRUE;
}
#ifdef DEBUG_AGP
llwarns << "More than " << DEFAULT_MAX_VERTICES << " in pool type " << (S32)mType << " at rebuild!" << llendl;
#endif
}
}
// rebuild de-allocates 'stale' objects, so we still need to do a rebuild periodically
if (mRebuildFreq > 0 && mRebuildTime >= mRebuildFreq)
{
needs_rebuild = TRUE;
}
if (needs_rebuild)
{
mGeneration++;
if (mReferences.empty())
{
resetIndices(0);
resetVertexData(0);
}
else
{
for (std::vector<LLFace*>::iterator iter = mReferences.begin();
iter != mReferences.end(); iter++)
{
LLFace *facep = *iter;
if (facep->hasGeometry() && !facep->isState(LLFace::BACKLIST | LLFace::SHARED_GEOM))
{
facep->backup();
}
}
S32 tot_verts = 0;
S32 tot_indices = 0;
for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
{
LLFace *facep = *iter;
if (facep->isState(LLFace::BACKLIST))
{
tot_verts += facep->getGeomCount();
tot_indices += facep->getIndicesCount();
}
}
for (std::vector<LLFace*>::iterator iter = mMoveFace.begin();
iter != mMoveFace.end(); iter++)
{
LLFace *facep = *iter;
if (facep->isState(LLFace::BACKLIST))
{
tot_verts += facep->getGeomCount();
tot_indices += facep->getIndicesCount();
}
}
resetIndices(tot_indices);
flushAGP();
resetVertexData(tot_verts);
for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
{
LLFace *facep = *iter;
llassert(facep->getPool() == this);
facep->restore();
}
}
mRebuildTime = 0;
setDirty();
}
if (!mMoveFace.empty())
{
for (std::vector<LLFace*>::iterator iter = mMoveFace.begin();
iter != mMoveFace.end(); iter++)
{
LLFace *facep = *iter;
facep->restore();
enqueue(facep);
}
setDirty();
mMoveFace.reset();
rebuild_cost++;
}
return rebuild_cost;
}
LLViewerImage *LLDrawPool::getTexture()
{
return NULL;
}
LLViewerImage *LLDrawPool::getDebugTexture()
{
return NULL;
}
void LLDrawPool::removeFaceReference(LLFace *facep)
{
if (facep->getReferenceIndex() != -1)
{
if (facep->getReferenceIndex() != (S32)mReferences.size())
{
LLFace *back = mReferences.back();
mReferences[facep->getReferenceIndex()] = back;
back->setReferenceIndex(facep->getReferenceIndex());
}
mReferences.pop_back();
}
facep->setReferenceIndex(-1);
}
void LLDrawPool::addFaceReference(LLFace *facep)
{
if (-1 == facep->getReferenceIndex())
{
facep->setReferenceIndex(mReferences.size());
mReferences.push_back(facep);
}
}
U32 LLDrawPool::getTrianglesDrawn() const
{
return mIndicesDrawn / 3;
}
void LLDrawPool::resetTrianglesDrawn()
{
mIndicesDrawn = 0;
}
void LLDrawPool::addIndicesDrawn(const U32 indices)
{
mIndicesDrawn += indices;
}
BOOL LLDrawPool::verify() const
{
BOOL ok = TRUE;
// Verify all indices in the pool are in the right range
const U32 *indicesp = getRawIndices();
for (U32 i = 0; i < getIndexCount(); i++)
{
if (indicesp[i] > getVertexCount())
{
ok = FALSE;
llinfos << "Bad index in tree pool!" << llendl;
}
}
for (std::vector<LLFace*>::const_iterator iter = mDrawFace.begin();
iter != mDrawFace.end(); iter++)
{
const LLFace* facep = *iter;
if (facep->getPool() != this)
{
llinfos << "Face in wrong pool!" << llendl;
facep->printDebugInfo();
ok = FALSE;
}
else if (!facep->verify())
{
ok = FALSE;
}
}
return ok;
}
void LLDrawPool::printDebugInfo() const
{
llinfos << "Pool " << this << " Type: " << getType() << llendl;
llinfos << "--------------------" << llendl;
llinfos << "Vertex count: " << getVertexCount() << llendl;
llinfos << "Normal count: " << getNormalCount() << llendl;
llinfos << "Indices count: " << getIndexCount() << llendl;
llinfos << llendl;
}
S32 LLDrawPool::getMemUsage(const BOOL print)
{
S32 mem_usage = 0;
mem_usage += sizeof(this);
// Usage beyond the pipeline allocated data (color and mMemory)
mem_usage += mIndices.getMax() * sizeof(U32);
mem_usage += mDrawFace.capacity() * sizeof(LLFace *);
mem_usage += mMoveFace.capacity() * sizeof(LLFace *);
mem_usage += mReferences.capacity() * sizeof(LLFace *);
mem_usage += mMemory.getSysMemUsage();
mem_usage += mWeights.getSysMemUsage();
mem_usage += mClothingWeights.getSysMemUsage();
return mem_usage;
}
LLColor3 LLDrawPool::getDebugColor() const
{
return LLColor3(0.f, 0.f, 0.f);
}
void LLDrawPool::setDirty()
{
mMemory.setDirty();
mWeights.setDirty();
mClothingWeights.setDirty();
}
BOOL LLDrawPool::LLOverrideFaceColor::sOverrideFaceColor = FALSE;
void LLDrawPool::LLOverrideFaceColor::setColor(const LLColor4& color)
{
if (mPool->mVertexShaderLevel > 0 && mPool->getMaterialAttribIndex() > 0)
{
glVertexAttrib4fvARB(mPool->getMaterialAttribIndex(), color.mV);
}
else
{
glColor4fv(color.mV);
}
}
void LLDrawPool::LLOverrideFaceColor::setColor(const LLColor4U& color)
{
if (mPool->mVertexShaderLevel > 0 && mPool->getMaterialAttribIndex() > 0)
{
glVertexAttrib4ubvARB(mPool->getMaterialAttribIndex(), color.mV);
}
else
{
glColor4ubv(color.mV);
}
}
void LLDrawPool::LLOverrideFaceColor::setColor(F32 r, F32 g, F32 b, F32 a)
{
if (mPool->mVertexShaderLevel > 0 && mPool->getMaterialAttribIndex() > 0)
{
glVertexAttrib4fARB(mPool->getMaterialAttribIndex(), r,g,b,a);
}
else
{
glColor4f(r,g,b,a);
}
}
// virtual
void LLDrawPool::enableShade()
{ }
// virtual
void LLDrawPool::disableShade()
{ }
// virtual
void LLDrawPool::setShade(F32 shade)
{ }