summaryrefslogtreecommitdiff
path: root/indra/newview/lldrawpool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/lldrawpool.cpp')
-rw-r--r--indra/newview/lldrawpool.cpp1402
1 files changed, 1402 insertions, 0 deletions
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
new file mode 100644
index 0000000000..0ef9eed7a3
--- /dev/null
+++ b/indra/newview/lldrawpool.cpp
@@ -0,0 +1,1402 @@
+/**
+ * @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 "lldrawpoolmedia.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_MEDIA:
+ poolp = new LLDrawPoolMedia(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)
+{ }