/** * @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 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::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::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 &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 &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 &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 &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 &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 &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 &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::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { LLFace *face = *iter; S32 geom_count = face->getGeomCount(); for (S32 j=0;jisState(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= 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= 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= 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= 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= 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>2; words = bytes >> 2; for (i=0; iunReserve(); 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 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::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::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::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::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::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::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) { }