diff options
Diffstat (limited to 'indra/newview/lldrawpool.cpp')
-rw-r--r-- | indra/newview/lldrawpool.cpp | 1402 |
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) +{ } |