/indra/newview/llspatialpartition.cpp
C++ | 2720 lines | 2118 code | 432 blank | 170 comment | 317 complexity | 905d06b0391037b1a5379e498573db63 MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /**
- * @file llspatialpartition.cpp
- * @brief LLSpatialGroup class implementation and supporting functions
- *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llspatialpartition.h"
- #include "llappviewer.h"
- #include "lltexturecache.h"
- #include "lltexturefetch.h"
- #include "llimageworker.h"
- #include "llviewerwindow.h"
- #include "llviewerobjectlist.h"
- #include "llvovolume.h"
- #include "llvolume.h"
- #include "llvolumeoctree.h"
- #include "llviewercamera.h"
- #include "llface.h"
- #include "llfloatertools.h"
- #include "llviewercontrol.h"
- #include "llviewerregion.h"
- #include "llcamera.h"
- #include "pipeline.h"
- #include "llmeshrepository.h"
- #include "llrender.h"
- #include "lloctree.h"
- #include "llphysicsshapebuilderutil.h"
- #include "llvoavatar.h"
- #include "llvolumemgr.h"
- #include "lltextureatlas.h"
- #include "llglslshader.h"
- #include "llviewershadermgr.h"
- static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
- static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
- const F32 SG_OCCLUSION_FUDGE = 0.25f;
- #define SG_DISCARD_TOLERANCE 0.01f
- #if LL_OCTREE_PARANOIA_CHECK
- #define assert_octree_valid(x) x->validate()
- #define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates()
- #else
- #define assert_octree_valid(x)
- #define assert_states_valid(x)
- #endif
- static U32 sZombieGroups = 0;
- U32 LLSpatialGroup::sNodeCount = 0;
- #define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
- std::set<GLuint> LLSpatialGroup::sPendingQueries;
- U32 gOctreeMaxCapacity;
- BOOL LLSpatialGroup::sNoDelete = FALSE;
- static F32 sLastMaxTexPriority = 1.f;
- static F32 sCurMaxTexPriority = 1.f;
- class LLOcclusionQueryPool : public LLGLNamePool
- {
- protected:
- virtual GLuint allocateName()
- {
- GLuint name;
- glGenQueriesARB(1, &name);
- return name;
- }
- virtual void releaseName(GLuint name)
- {
- #if LL_TRACK_PENDING_OCCLUSION_QUERIES
- LLSpatialGroup::sPendingQueries.erase(name);
- #endif
- glDeleteQueriesARB(1, &name);
- }
- };
- static LLOcclusionQueryPool sQueryPool;
- //static counter for frame to switch LOD on
- void sg_assert(BOOL expr)
- {
- #if LL_OCTREE_PARANOIA_CHECK
- if (!expr)
- {
- llerrs << "Octree invalid!" << llendl;
- }
- #endif
- }
- S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
- {
- return AABBSphereIntersectR2(min, max, origin, rad*rad);
- }
- S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
- {
- F32 d = 0.f;
- F32 t;
-
- if ((min-origin).magVecSquared() < r &&
- (max-origin).magVecSquared() < r)
- {
- return 2;
- }
- for (U32 i = 0; i < 3; i++)
- {
- if (origin.mV[i] < min.mV[i])
- {
- t = min.mV[i] - origin.mV[i];
- d += t*t;
- }
- else if (origin.mV[i] > max.mV[i])
- {
- t = origin.mV[i] - max.mV[i];
- d += t*t;
- }
- if (d > r)
- {
- return 0;
- }
- }
- return 1;
- }
- S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
- {
- return AABBSphereIntersectR2(min, max, origin, rad*rad);
- }
- S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
- {
- F32 d = 0.f;
- F32 t;
-
- LLVector4a origina;
- origina.load3(origin.mV);
- LLVector4a v;
- v.setSub(min, origina);
-
- if (v.dot3(v) < r)
- {
- v.setSub(max, origina);
- if (v.dot3(v) < r)
- {
- return 2;
- }
- }
- for (U32 i = 0; i < 3; i++)
- {
- if (origin.mV[i] < min[i])
- {
- t = min[i] - origin.mV[i];
- d += t*t;
- }
- else if (origin.mV[i] > max[i])
- {
- t = origin.mV[i] - max[i];
- d += t*t;
- }
- if (d > r)
- {
- return 0;
- }
- }
- return 1;
- }
- typedef enum
- {
- b000 = 0x00,
- b001 = 0x01,
- b010 = 0x02,
- b011 = 0x03,
- b100 = 0x04,
- b101 = 0x05,
- b110 = 0x06,
- b111 = 0x07,
- } eLoveTheBits;
- //contact Runitai Linden for a copy of the SL object used to write this table
- //basically, you give the table a bitmask of the look-at vector to a node and it
- //gives you a triangle fan index array
- static U16 sOcclusionIndices[] =
- {
- //000
- b111, b110, b010, b011, b001, b101, b100, b110,
- //001
- b011, b010, b000, b001, b101, b111, b110, b010,
- //010
- b101, b100, b110, b111, b011, b001, b000, b100,
- //011
- b001, b000, b100, b101, b111, b011, b010, b000,
- //100
- b110, b000, b010, b011, b111, b101, b100, b000,
- //101
- b010, b100, b000, b001, b011, b111, b110, b100,
- //110
- b100, b010, b110, b111, b101, b001, b000, b010,
- //111
- b000, b110, b100, b101, b001, b011, b010, b110,
- };
- U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
- {
- LLVector4a origin;
- origin.load3(camera->getOrigin().mV);
- S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
-
- return cypher*8;
- }
- U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
- {
- LLVector4a origin;
- origin.load3(camera->getOrigin().mV);
- S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
-
- return (U8*) (sOcclusionIndices+cypher*8);
- }
- static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
- void LLSpatialGroup::buildOcclusion()
- {
- if (mOcclusionVerts.isNull())
- {
- mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX,
- LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
- mOcclusionVerts->allocateBuffer(8, 64, true);
-
- LLStrider<U16> idx;
- mOcclusionVerts->getIndexStrider(idx);
- for (U32 i = 0; i < 64; i++)
- {
- *idx++ = sOcclusionIndices[i];
- }
- }
- LLVector4a fudge;
- fudge.splat(SG_OCCLUSION_FUDGE);
- LLVector4a r;
- r.setAdd(mBounds[1], fudge);
- LLStrider<LLVector3> pos;
-
- {
- LLFastTimer t(FTM_BUILD_OCCLUSION);
- mOcclusionVerts->getVertexStrider(pos);
- }
- {
- LLVector4a* v = (LLVector4a*) pos.get();
- const LLVector4a& c = mBounds[0];
- const LLVector4a& s = r;
-
- static const LLVector4a octant[] =
- {
- LLVector4a(-1.f, -1.f, -1.f),
- LLVector4a(-1.f, -1.f, 1.f),
- LLVector4a(-1.f, 1.f, -1.f),
- LLVector4a(-1.f, 1.f, 1.f),
- LLVector4a(1.f, -1.f, -1.f),
- LLVector4a(1.f, -1.f, 1.f),
- LLVector4a(1.f, 1.f, -1.f),
- LLVector4a(1.f, 1.f, 1.f),
- };
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
-
- for (S32 i = 0; i < 8; ++i)
- {
- LLVector4a p;
- p.setMul(s, octant[i]);
- p.add(c);
- v[i] = p;
- }
- }
-
- {
- mOcclusionVerts->flush();
- LLVertexBuffer::unbind();
- }
- clearState(LLSpatialGroup::OCCLUSION_DIRTY);
- }
- BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
- //returns:
- // 0 if sphere and AABB are not intersecting
- // 1 if they are
- // 2 if AABB is entirely inside sphere
- S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
- {
- S32 ret = 2;
- LLVector3 min = center - size;
- LLVector3 max = center + size;
- for (U32 i = 0; i < 3; i++)
- {
- if (min.mV[i] > pos.mV[i] + rad ||
- max.mV[i] < pos.mV[i] - rad)
- { //totally outside
- return 0;
- }
-
- if (min.mV[i] < pos.mV[i] - rad ||
- max.mV[i] > pos.mV[i] + rad)
- { //intersecting
- ret = 1;
- }
- }
- return ret;
- }
- LLSpatialGroup::~LLSpatialGroup()
- {
- /*if (sNoDelete)
- {
- llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
- }*/
- if (gDebugGL)
- {
- gPipeline.checkReferences(this);
- }
- if (isState(DEAD))
- {
- sZombieGroups--;
- }
-
- sNodeCount--;
- if (gGLManager.mHasOcclusionQuery)
- {
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
- {
- if (mOcclusionQuery[i])
- {
- sQueryPool.release(mOcclusionQuery[i]);
- }
- }
- }
- mOcclusionVerts = NULL;
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- clearDrawMap();
- clearAtlasList() ;
- }
- BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
- {
- S8 type = atlasp->getComponents() - 1 ;
- for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
- {
- if(atlasp == *iter)
- {
- return TRUE ;
- }
- }
- return FALSE ;
- }
- void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level)
- {
- if(!hasAtlas(atlasp))
- {
- mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
- atlasp->addSpatialGroup(this) ;
- }
-
- --recursive_level;
- if(recursive_level)//levels propagating up.
- {
- LLSpatialGroup* parent = getParent() ;
- if(parent)
- {
- parent->addAtlas(atlasp, recursive_level) ;
- }
- }
- }
- void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level)
- {
- mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
- if(remove_group)
- {
- atlasp->removeSpatialGroup(this) ;
- }
- --recursive_level;
- if(recursive_level)//levels propagating up.
- {
- LLSpatialGroup* parent = getParent() ;
- if(parent)
- {
- parent->removeAtlas(atlasp, recursive_level) ;
- }
- }
- }
- void LLSpatialGroup::clearAtlasList()
- {
- std::list<LLTextureAtlas*>::iterator iter ;
- for(S8 i = 0 ; i < 4 ; i++)
- {
- if(mAtlasList[i].size() > 0)
- {
- for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
- {
- ((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;
- }
- mAtlasList[i].clear() ;
- }
- }
- }
- LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
- {
- S8 type = ncomponents - 1 ;
- if(mAtlasList[type].size() > 0)
- {
- for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
- {
- if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
- {
- return *iter ;
- }
- }
- }
- --recursive_level;
- if(recursive_level)
- {
- LLSpatialGroup* parent = getParent() ;
- if(parent)
- {
- return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
- }
- }
- return NULL ;
- }
- void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp)
- {
- mCurUpdatingSlotp = slotp;
- //if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
- //{
- // addAtlas(mCurUpdatingSlotp->getAtlas()) ;
- //}
- }
- LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level)
- {
- if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
- {
- return mCurUpdatingSlotp ;
- }
- //--recursive_level ;
- //if(recursive_level)
- //{
- // LLSpatialGroup* parent = getParent() ;
- // if(parent)
- // {
- // return parent->getCurUpdatingSlot(imagep, recursive_level) ;
- // }
- //}
- return NULL ;
- }
- void LLSpatialGroup::clearDrawMap()
- {
- mDrawMap.clear();
- }
- BOOL LLSpatialGroup::isHUDGroup()
- {
- return mSpatialPartition && mSpatialPartition->isHUDPartition() ;
- }
- BOOL LLSpatialGroup::isRecentlyVisible() const
- {
- return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ;
- }
- BOOL LLSpatialGroup::isVisible() const
- {
- return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
- }
- void LLSpatialGroup::setVisible()
- {
- mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
- }
- void LLSpatialGroup::validate()
- {
- #if LL_OCTREE_PARANOIA_CHECK
- sg_assert(!isState(DIRTY));
- sg_assert(!isDead());
- LLVector4a myMin;
- myMin.setSub(mBounds[0], mBounds[1]);
- LLVector4a myMax;
- myMax.setAdd(mBounds[0], mBounds[1]);
- validateDrawMap();
- for (element_iter i = getData().begin(); i != getData().end(); ++i)
- {
- LLDrawable* drawable = *i;
- sg_assert(drawable->getSpatialGroup() == this);
- if (drawable->getSpatialBridge())
- {
- sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
- }
- /*if (drawable->isSpatialBridge())
- {
- LLSpatialPartition* part = drawable->asPartition();
- if (!part)
- {
- llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl;
- }
- LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
- group->validate();
- }*/
- }
- for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
- group->validate();
-
- //ensure all children are enclosed in this node
- LLVector4a center = group->mBounds[0];
- LLVector4a size = group->mBounds[1];
-
- LLVector4a min;
- min.setSub(center, size);
- LLVector4a max;
- max.setAdd(center, size);
-
- for (U32 j = 0; j < 3; j++)
- {
- sg_assert(min[j] >= myMin[j]-0.02f);
- sg_assert(max[j] <= myMax[j]+0.02f);
- }
- }
- #endif
- }
- void LLSpatialGroup::checkStates()
- {
- #if LL_OCTREE_PARANOIA_CHECK
- //LLOctreeStateCheck checker;
- //checker.traverse(mOctreeNode);
- #endif
- }
- void LLSpatialGroup::validateDrawMap()
- {
- #if LL_OCTREE_PARANOIA_CHECK
- for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
- {
- LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
- for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
- {
- LLDrawInfo& params = **j;
-
- params.validate();
- }
- }
- #endif
- }
- BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- drawablep->updateSpatialExtents();
- OctreeNode* parent = mOctreeNode->getOctParent();
-
- if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&
- (mOctreeNode->contains(drawablep) ||
- (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
- parent && parent->getElementCount() >= gOctreeMaxCapacity)))
- {
- unbound();
- setState(OBJECT_DIRTY);
- //setState(GEOM_DIRTY);
- return TRUE;
- }
-
- return FALSE;
- }
- BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- if (!from_octree)
- {
- mOctreeNode->insert(drawablep);
- }
- else
- {
- drawablep->setSpatialGroup(this);
- setState(OBJECT_DIRTY | GEOM_DIRTY);
- setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
- gPipeline.markRebuild(this, TRUE);
- if (drawablep->isSpatialBridge())
- {
- mBridgeList.push_back((LLSpatialBridge*) drawablep);
- }
- if (drawablep->getRadius() > 1.f)
- {
- setState(IMAGE_DIRTY);
- }
- }
- return TRUE;
- }
- void LLSpatialGroup::rebuildGeom()
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- if (!isDead())
- {
- mSpatialPartition->rebuildGeom(this);
- }
- }
- void LLSpatialGroup::rebuildMesh()
- {
- if (!isDead())
- {
- mSpatialPartition->rebuildMesh(this);
- }
- }
- static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
- void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
- {
- if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
- {
- return;
- }
- if (group->changeLOD())
- {
- group->mLastUpdateDistance = group->mDistance;
- group->mLastUpdateViewAngle = group->mViewAngle;
- }
-
- LLFastTimer ftm(FTM_REBUILD_VBO);
- group->clearDrawMap();
-
- //get geometry count
- U32 index_count = 0;
- U32 vertex_count = 0;
-
- addGeometryCount(group, vertex_count, index_count);
- if (vertex_count > 0 && index_count > 0)
- { //create vertex buffer containing volume geometry for this node
- group->mBuilt = 1.f;
- if (group->mVertexBuffer.isNull() || (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
- {
- group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
- group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true);
- stop_glerror();
- }
- else
- {
- group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
- stop_glerror();
- }
-
- getGeometry(group);
- }
- else
- {
- group->mVertexBuffer = NULL;
- group->mBufferMap.clear();
- }
- group->mLastUpdateTime = gFrameTimeSeconds;
- group->clearState(LLSpatialGroup::GEOM_DIRTY);
- }
- void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
- {
- }
- BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
- {
- const OctreeNode* node = mOctreeNode;
- if (node->getData().empty())
- { //don't do anything if there are no objects
- if (empty && mOctreeNode->getParent())
- { //only root is allowed to be empty
- OCT_ERRS << "Empty leaf found in octree." << llendl;
- }
- return FALSE;
- }
- LLVector4a& newMin = mObjectExtents[0];
- LLVector4a& newMax = mObjectExtents[1];
-
- if (isState(OBJECT_DIRTY))
- { //calculate new bounding box
- clearState(OBJECT_DIRTY);
- //initialize bounding box to first element
- OctreeNode::const_element_iter i = node->getData().begin();
- LLDrawable* drawablep = *i;
- const LLVector4a* minMax = drawablep->getSpatialExtents();
- newMin = minMax[0];
- newMax = minMax[1];
- for (++i; i != node->getData().end(); ++i)
- {
- drawablep = *i;
- minMax = drawablep->getSpatialExtents();
-
- update_min_max(newMin, newMax, minMax[0]);
- update_min_max(newMin, newMax, minMax[1]);
- //bin up the object
- /*for (U32 i = 0; i < 3; i++)
- {
- if (minMax[0].mV[i] < newMin.mV[i])
- {
- newMin.mV[i] = minMax[0].mV[i];
- }
- if (minMax[1].mV[i] > newMax.mV[i])
- {
- newMax.mV[i] = minMax[1].mV[i];
- }
- }*/
- }
-
- mObjectBounds[0].setAdd(newMin, newMax);
- mObjectBounds[0].mul(0.5f);
- mObjectBounds[1].setSub(newMax, newMin);
- mObjectBounds[1].mul(0.5f);
- }
-
- if (empty)
- {
- minOut = newMin;
- maxOut = newMax;
- }
- else
- {
- minOut.setMin(minOut, newMin);
- maxOut.setMax(maxOut, newMax);
- }
-
- return TRUE;
- }
- void LLSpatialGroup::unbound()
- {
- if (isState(DIRTY))
- {
- return;
- }
- setState(DIRTY);
-
- //all the parent nodes need to rebound this child
- if (mOctreeNode)
- {
- OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
- while (parent != NULL)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0);
- if (group->isState(DIRTY))
- {
- return;
- }
-
- group->setState(DIRTY);
- parent = (OctreeNode*) parent->getParent();
- }
- }
- }
- LLSpatialGroup* LLSpatialGroup::getParent()
- {
- if (isDead())
- {
- return NULL;
- }
- if(!mOctreeNode)
- {
- return NULL;
- }
- OctreeNode* parent = mOctreeNode->getOctParent();
- if (parent)
- {
- return (LLSpatialGroup*) parent->getListener(0);
- }
- return NULL;
- }
- BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- unbound();
- if (mOctreeNode && !from_octree)
- {
- if (!mOctreeNode->remove(drawablep))
- {
- OCT_ERRS << "Could not remove drawable from spatial group" << llendl;
- }
- }
- else
- {
- drawablep->setSpatialGroup(NULL);
- setState(GEOM_DIRTY);
- gPipeline.markRebuild(this, TRUE);
- if (drawablep->isSpatialBridge())
- {
- for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
- {
- if (*i == drawablep)
- {
- mBridgeList.erase(i);
- break;
- }
- }
- }
- if (getElementCount() == 0)
- { //delete draw map on last element removal since a rebuild might never happen
- clearDrawMap();
- }
- }
- return TRUE;
- }
- void LLSpatialGroup::shift(const LLVector4a &offset)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- LLVector4a t = mOctreeNode->getCenter();
- t.add(offset);
- mOctreeNode->setCenter(t);
- mOctreeNode->updateMinMax();
- mBounds[0].add(offset);
- mExtents[0].add(offset);
- mExtents[1].add(offset);
- mObjectBounds[0].add(offset);
- mObjectExtents[0].add(offset);
- mObjectExtents[1].add(offset);
- //if (!mSpatialPartition->mRenderByGroup)
- {
- setState(GEOM_DIRTY);
- gPipeline.markRebuild(this, TRUE);
- }
- if (mOcclusionVerts.notNull())
- {
- setState(OCCLUSION_DIRTY);
- }
- }
- class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
- {
- public:
- U32 mState;
- LLSpatialSetState(U32 state) : mState(state) { }
- virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }
- };
- class LLSpatialSetStateDiff : public LLSpatialSetState
- {
- public:
- LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
- virtual void traverse(const LLSpatialGroup::OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
- if (!group->isState(mState))
- {
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- }
- };
- void LLSpatialGroup::setState(U32 state)
- {
- mState |= state;
-
- llassert(state <= LLSpatialGroup::STATE_MASK);
- }
- void LLSpatialGroup::setState(U32 state, S32 mode)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- llassert(state <= LLSpatialGroup::STATE_MASK);
-
- if (mode > STATE_MODE_SINGLE)
- {
- if (mode == STATE_MODE_DIFF)
- {
- LLSpatialSetStateDiff setter(state);
- setter.traverse(mOctreeNode);
- }
- else
- {
- LLSpatialSetState setter(state);
- setter.traverse(mOctreeNode);
- }
- }
- else
- {
- mState |= state;
- }
- }
- class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
- {
- public:
- U32 mState;
- LLSpatialClearState(U32 state) : mState(state) { }
- virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
- };
- class LLSpatialClearStateDiff : public LLSpatialClearState
- {
- public:
- LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
- virtual void traverse(const LLSpatialGroup::OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
- if (group->isState(mState))
- {
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- }
- };
- void LLSpatialGroup::clearState(U32 state)
- {
- llassert(state <= LLSpatialGroup::STATE_MASK);
- mState &= ~state;
- }
- void LLSpatialGroup::clearState(U32 state, S32 mode)
- {
- llassert(state <= LLSpatialGroup::STATE_MASK);
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- if (mode > STATE_MODE_SINGLE)
- {
- if (mode == STATE_MODE_DIFF)
- {
- LLSpatialClearStateDiff clearer(state);
- clearer.traverse(mOctreeNode);
- }
- else
- {
- LLSpatialClearState clearer(state);
- clearer.traverse(mOctreeNode);
- }
- }
- else
- {
- mState &= ~state;
- }
- }
- BOOL LLSpatialGroup::isState(U32 state) const
- {
- llassert(state <= LLSpatialGroup::STATE_MASK);
- return mState & state ? TRUE : FALSE;
- }
- //=====================================
- // Occlusion State Set/Clear
- //=====================================
- class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler
- {
- public:
- U32 mState;
- LLSpatialSetOcclusionState(U32 state) : mState(state) { }
- virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }
- };
- class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
- {
- public:
- LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
- virtual void traverse(const LLSpatialGroup::OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
- if (!group->isOcclusionState(mState))
- {
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- }
- };
- void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- if (mode > STATE_MODE_SINGLE)
- {
- if (mode == STATE_MODE_DIFF)
- {
- LLSpatialSetOcclusionStateDiff setter(state);
- setter.traverse(mOctreeNode);
- }
- else if (mode == STATE_MODE_BRANCH)
- {
- LLSpatialSetOcclusionState setter(state);
- setter.traverse(mOctreeNode);
- }
- else
- {
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
- {
- mOcclusionState[i] |= state;
- if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
- {
- sQueryPool.release(mOcclusionQuery[i]);
- mOcclusionQuery[i] = 0;
- }
- }
- }
- }
- else
- {
- mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
- if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
- }
- }
- }
- class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler
- {
- public:
- U32 mState;
-
- LLSpatialClearOcclusionState(U32 state) : mState(state) { }
- virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
- };
- class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
- {
- public:
- LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
- virtual void traverse(const LLSpatialGroup::OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
- if (group->isOcclusionState(mState))
- {
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- }
- };
- void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- if (mode > STATE_MODE_SINGLE)
- {
- if (mode == STATE_MODE_DIFF)
- {
- LLSpatialClearOcclusionStateDiff clearer(state);
- clearer.traverse(mOctreeNode);
- }
- else if (mode == STATE_MODE_BRANCH)
- {
- LLSpatialClearOcclusionState clearer(state);
- clearer.traverse(mOctreeNode);
- }
- else
- {
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
- {
- mOcclusionState[i] &= ~state;
- }
- }
- }
- else
- {
- mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
- }
- }
- //======================================
- // Octree Listener Implementation
- //======================================
- LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
- mState(0),
- mBuilt(0.f),
- mOctreeNode(node),
- mSpatialPartition(part),
- mVertexBuffer(NULL),
- mBufferUsage(part->mBufferUsage),
- mDistance(0.f),
- mDepth(0.f),
- mLastUpdateDistance(-1.f),
- mLastUpdateTime(gFrameTimeSeconds),
- mAtlasList(4),
- mCurUpdatingTime(0),
- mCurUpdatingSlotp(NULL),
- mCurUpdatingTexture (NULL)
- {
- sNodeCount++;
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- mViewAngle.splat(0.f);
- mLastUpdateViewAngle.splat(-1.f);
- mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =
- mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
- sg_assert(mOctreeNode->getListenerCount() == 0);
- mOctreeNode->addListener(this);
- setState(SG_INITIAL_STATE_MASK);
- gPipeline.markRebuild(this, TRUE);
- mBounds[0] = node->getCenter();
- mBounds[1] = node->getSize();
- part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
- mLODHash = part->mLODSeed;
- OctreeNode* oct_parent = node->getOctParent();
- LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL;
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
- {
- mOcclusionQuery[i] = 0;
- mOcclusionIssued[i] = 0;
- mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0;
- mVisible[i] = 0;
- }
- mOcclusionVerts = NULL;
- mRadius = 1;
- mPixelArea = 1024.f;
- }
- void LLSpatialGroup::updateDistance(LLCamera &camera)
- {
- if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
- {
- llwarns << "Attempted to update distance for camera other than world camera!" << llendl;
- return;
- }
- #if !LL_RELEASE_FOR_DOWNLOAD
- if (isState(LLSpatialGroup::OBJECT_DIRTY))
- {
- llerrs << "Spatial group dirty on distance update." << llendl;
- }
- #endif
- if (!getData().empty())
- {
- mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
- (F32) mOctreeNode->getSize().getLength3().getF32();
- mDistance = mSpatialPartition->calcDistance(this, camera);
- mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
- }
- }
- F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
- {
- LLVector4a eye;
- LLVector4a origin;
- origin.load3(camera.getOrigin().mV);
- eye.setSub(group->mObjectBounds[0], origin);
- F32 dist = 0.f;
- if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
- {
- LLVector4a v = eye;
- dist = eye.getLength3().getF32();
- eye.normalize3fast();
- if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
- {
- if (!group->mSpatialPartition->isBridge())
- {
- LLVector4a view_angle = eye;
- LLVector4a diff;
- diff.setSub(view_angle, group->mLastUpdateViewAngle);
- if (diff.getLength3().getF32() > 0.64f)
- {
- group->mViewAngle = view_angle;
- group->mLastUpdateViewAngle = view_angle;
- //for occasional alpha sorting within the group
- //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
- //not setting this node to dirty would be a very good thing
- group->setState(LLSpatialGroup::ALPHA_DIRTY);
- gPipeline.markRebuild(group, FALSE);
- }
- }
- }
- //calculate depth of node for alpha sorting
- LLVector3 at = camera.getAtAxis();
- LLVector4a ata;
- ata.load3(at.mV);
- LLVector4a t = ata;
- //front of bounding box
- t.mul(0.25f);
- t.mul(group->mObjectBounds[1]);
- v.sub(t);
-
- group->mDepth = v.dot3(ata).getF32();
- }
- else
- {
- dist = eye.getLength3().getF32();
- }
- if (dist < 16.f)
- {
- dist /= 16.f;
- dist *= dist;
- dist *= 16.f;
- }
- return dist;
- }
- F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
- {
- return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
- }
- F32 LLSpatialGroup::getUpdateUrgency() const
- {
- if (!isVisible())
- {
- return 0.f;
- }
- else
- {
- F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
- return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
- }
- }
- BOOL LLSpatialGroup::needsUpdate()
- {
- return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
- }
- BOOL LLSpatialGroup::changeLOD()
- {
- if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
- { ///a rebuild is going to happen, update distance and LoD
- return TRUE;
- }
- if (mSpatialPartition->mSlopRatio > 0.f)
- {
- F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
- if (fabsf(ratio) >= mSpatialPartition->mSlopRatio)
- {
- return TRUE;
- }
- if (mDistance > mRadius*2.f)
- {
- return FALSE;
- }
- }
-
- if (needsUpdate())
- {
- return TRUE;
- }
-
- return FALSE;
- }
- void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- addObject(drawablep, FALSE, TRUE);
- unbound();
- setState(OBJECT_DIRTY);
- }
- void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- removeObject(drawable, TRUE);
- setState(OBJECT_DIRTY);
- }
- void LLSpatialGroup::handleDestruction(const TreeNode* node)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- setState(DEAD);
-
- for (element_iter i = getData().begin(); i != getData().end(); ++i)
- {
- LLDrawable* drawable = *i;
- if (drawable->getSpatialGroup() == this)
- {
- drawable->setSpatialGroup(NULL);
- }
- }
-
- clearDrawMap();
- mVertexBuffer = NULL;
- mBufferMap.clear();
- sZombieGroups++;
- mOctreeNode = NULL;
- }
- void LLSpatialGroup::handleStateChange(const TreeNode* node)
- {
- //drop bounding box upon state change
- if (mOctreeNode != node)
- {
- mOctreeNode = (OctreeNode*) node;
- }
- unbound();
- }
- void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- if (child->getListenerCount() == 0)
- {
- new LLSpatialGroup(child, mSpatialPartition);
- }
- else
- {
- OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
- }
- unbound();
- assert_states_valid(this);
- }
- void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
- {
- unbound();
- }
- void LLSpatialGroup::destroyGL()
- {
- setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
- gPipeline.markRebuild(this, TRUE);
- mLastUpdateTime = gFrameTimeSeconds;
- mVertexBuffer = NULL;
- mBufferMap.clear();
- clearDrawMap();
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
- {
- if (mOcclusionQuery[i])
- {
- sQueryPool.release(mOcclusionQuery[i]);
- mOcclusionQuery[i] = 0;
- }
- }
- mOcclusionVerts = NULL;
- for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
- {
- LLDrawable* drawable = *i;
- for (S32 j = 0; j < drawable->getNumFaces(); j++)
- {
- LLFace* facep = drawable->getFace(j);
- facep->clearVertexBuffer();
- }
- }
- }
- BOOL LLSpatialGroup::rebound()
- {
- if (!isState(DIRTY))
- { //return TRUE if we're not empty
- return TRUE;
- }
-
- if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
- group->rebound();
-
- //copy single child's bounding box
- mBounds[0] = group->mBounds[0];
- mBounds[1] = group->mBounds[1];
- mExtents[0] = group->mExtents[0];
- mExtents[1] = group->mExtents[1];
-
- group->setState(SKIP_FRUSTUM_CHECK);
- }
- else if (mOctreeNode->isLeaf())
- { //copy object bounding box if this is a leaf
- boundObjects(TRUE, mExtents[0], mExtents[1]);
- mBounds[0] = mObjectBounds[0];
- mBounds[1] = mObjectBounds[1];
- }
- else
- {
- LLVector4a& newMin = mExtents[0];
- LLVector4a& newMax = mExtents[1];
- LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
- group->clearState(SKIP_FRUSTUM_CHECK);
- group->rebound();
- //initialize to first child
- newMin = group->mExtents[0];
- newMax = group->mExtents[1];
- //first, rebound children
- for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
- {
- group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
- group->clearState(SKIP_FRUSTUM_CHECK);
- group->rebound();
- const LLVector4a& max = group->mExtents[1];
- const LLVector4a& min = group->mExtents[0];
- newMax.setMax(newMax, max);
- newMin.setMin(newMin, min);
- }
- boundObjects(FALSE, newMin, newMax);
-
- mBounds[0].setAdd(newMin, newMax);
- mBounds[0].mul(0.5f);
- mBounds[1].setSub(newMax, newMin);
- mBounds[1].mul(0.5f);
- }
-
- setState(OCCLUSION_DIRTY);
-
- clearState(DIRTY);
- return TRUE;
- }
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait");
- void LLSpatialGroup::checkOcclusion()
- {
- if (LLPipeline::sUseOcclusion > 1)
- {
- LLFastTimer t(FTM_OCCLUSION_READBACK);
- LLSpatialGroup* parent = getParent();
- if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
- { //if the parent has been marked as occluded, the child is implicitly occluded
- clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
- }
- else if (isOcclusionState(QUERY_PENDING))
- { //otherwise, if a query is pending, read it back
- GLuint available = 0;
- if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
- if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
- { //query was issued last frame, wait until it's available
- S32 max_loop = 1024;
- LLFastTimer t(FTM_OCCLUSION_WAIT);
- while (!available && max_loop-- > 0)
- {
- F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f);
- //do some usefu work while we wait
- LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
- LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
- LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
-
- glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
- }
- }
- }
- else
- {
- available = 1;
- }
- if (available)
- { //result is available, read it back, otherwise wait until next frame
- GLuint res = 1;
- if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
- #if LL_TRACK_PENDING_OCCLUSION_QUERIES
- sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- #endif
- }
- else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
- { //delete the query to avoid holding onto hundreds of pending queries
- sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
- }
-
- if (isOcclusionState(DISCARD_QUERY))
- {
- res = 2;
- }
- if (res > 0)
- {
- assert_states_valid(this);
- clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
- }
- else
- {
- assert_states_valid(this);
- setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
- }
- clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
- }
- }
- else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
- { //check occlusion has been issued for occluded node that has not had a query issued
- assert_states_valid(this);
- clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
- }
- }
- }
- static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
- static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water");
- static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw");
- void LLSpatialGroup::doOcclusion(LLCamera* camera)
- {
- if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
- {
- // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
- if (earlyFail(camera, this))
- {
- LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
- setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
- assert_states_valid(this);
- clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
- assert_states_valid(this);
- }
- else
- {
- if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
- {
- { //no query pending, or previous query to be discarded
- LLFastTimer t(FTM_RENDER_OCCLUSION);
- if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- LLFastTimer t(FTM_OCCLUSION_ALLOCATE);
- mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
- }
- if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY))
- {
- LLFastTimer t(FTM_OCCLUSION_BUILD);
- buildOcclusion();
- }
-
- // Depth clamp all water to avoid it being culled as a result of being
- // behind the far clip plane, and in the case of edge water to avoid
- // it being culled while still visible.
- bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
- (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||
- mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
- LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);
-
- #if !LL_DARWIN
- U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB;
- #else
- U32 mode = GL_SAMPLES_PASSED_ARB;
- #endif
-
- #if LL_TRACK_PENDING_OCCLUSION_QUERIES
- sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- #endif
- {
- LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
-
- //store which frame this query was issued on
- mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
- {
- LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY);
- glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- }
-
- {
- LLFastTimer t(FTM_OCCLUSION_SET_BUFFER);
- mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
- }
- if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
- {
- LLFastTimer t(FTM_OCCLUSION_DRAW_WATER);
- LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
- if (camera->getOrigin().isExactlyZero())
- { //origin is invalid, draw entire box
- mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
- mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
- }
- else
- {
- mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
- }
- }
- else
- {
- LLFastTimer t(FTM_OCCLUSION_DRAW);
- if (camera->getOrigin().isExactlyZero())
- { //origin is invalid, draw entire box
- mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
- mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
- }
- else
- {
- mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
- }
- }
- {
- LLFastTimer t(FTM_OCCLUSION_END_QUERY);
- glEndQueryARB(mode);
- }
- }
- }
- {
- LLFastTimer t(FTM_SET_OCCLUSION_STATE);
- setOcclusionState(LLSpatialGroup::QUERY_PENDING);
- clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
- }
- }
- }
- }
- }
- //==============================================
- LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
- : mRenderByGroup(render_by_group)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- mOcclusionEnabled = TRUE;
- mDrawableType = 0;
- mPartitionType = LLViewerRegion::PARTITION_NONE;
- mLODSeed = 0;
- mLODPeriod = 1;
- mVertexDataMask = data_mask;
- mBufferUsage = buffer_usage;
- mDepthMask = FALSE;
- mSlopRatio = 0.25f;
- mInfiniteFarClip = FALSE;
- LLVector4a center, size;
- center.splat(0.f);
- size.splat(1.f);
- mOctree = new LLSpatialGroup::OctreeRoot(center,size,
- NULL);
- new LLSpatialGroup(mOctree, this);
- }
- LLSpatialPartition::~LLSpatialPartition()
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- delete mOctree;
- mOctree = NULL;
- }
- LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- drawablep->updateSpatialExtents();
- //keep drawable from being garbage collected
- LLPointer<LLDrawable> ptr = drawablep;
-
- assert_octree_valid(mOctree);
- mOctree->insert(drawablep);
- assert_octree_valid(mOctree);
-
- LLSpatialGroup* group = drawablep->getSpatialGroup();
- if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
- {
- group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
- }
- return group;
- }
- BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- drawablep->setSpatialGroup(NULL);
- if (!curp->removeObject(drawablep))
- {
- OCT_ERRS << "Failed to remove drawable from octree!" << llendl;
- }
- assert_octree_valid(mOctree);
-
- return TRUE;
- }
- void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
- {
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-
- // sanity check submitted by open source user bushing Spatula
- // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
- if (!drawablep)
- {
- OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl;
- return;
- }
-
- BOOL was_visible = curp ? curp->isVisible() : FALSE;
- if (curp && curp->mSpatialPartition != this)
- {
- //keep drawable from being garbage collected
- LLPointer<LLDrawable> ptr = drawablep;
- if (curp->mSpatialPartition->remove(drawablep, curp))
- {
- put(drawablep, was_visible);
- return;
- }
- else
- {
- OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl;
- }
- }
-
- if (curp && curp->updateInGroup(drawablep, immediate))
- {
- // Already updated, don't need to do anything
- assert_octree_valid(mOctree);
- return;
- }
- //keep drawable from being garbage collected
- LLPointer<LLDrawable> ptr = drawablep;
- if (curp && !remove(drawablep, curp))
- {
- OCT_ERRS << "Move couldn't find existing spatial group!" << llendl;
- }
- put(drawablep, was_visible);
- }
- class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
- {
- public:
- const LLVector4a& mOffset;
- LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
- virtual void visit(const LLSpatialGroup::OctreeNode* branch)
- {
- ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);
- }
- };
- void LLSpatialPartition::shift(const LLVector4a &offset)
- { //shift octree node bounding boxes by offset
- LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
- LLSpatialShift shifter(offset);
- shifter.traverse(mOctree);
- }
- class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
- {
- public:
- LLOctreeCull(LLCamera* camera)
- : mCamera(camera), mRes(0) { }
- virtual bool earlyFail(LLSpatialGroup* group)
- {
- group->checkOcclusion();
- if (group->mOctreeNode->getParent() && //never occlusion cull the root node
- LLPipeline::sUseOcclusion && //ignore occlusion if disabled
- group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- gPipeline.markOccluder(group);
- return true;
- }
-
- return false;
- }
-
- virtual void traverse(const LLSpatialGroup::OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
- if (earlyFail(group))
- {
- return;
- }
-
- if (mRes == 2 ||
- (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)))
- { //fully in, just add everything
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- else
- {
- mRes = frustumCheck(group);
-
- if (mRes)
- { //at least partially in, run on down
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- mRes = 0;
- }
- }
-
- virtual S32 frustumCheck(const LLSpatialGroup* group)
- {
- S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
- if (res != 0)
- {
- res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
- }
- return res;
- }
- virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
- {
- S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
- if (res != 0)
- {
- res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
- }
- return res;
- }
- virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group)
- {
- if (branch->getElementCount() == 0) //no elements
- {
- return false;
- }
- else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
- {
- return true;
- }
- else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
- {
- return false;
- }
-
- return true;
- }
- virtual void preprocess(LLSpatialGroup* group)
- {
-
- }
-
- virtual void processGroup(LLSpatialGroup* group)
- {
- if (group->needsUpdate() ||
- group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
- {
- group->doOcclusion(mCamera);
- }
- gPipeline.markNotCulled(group, *mCamera);
- }
-
- virtual void visit(const LLSpatialGroup::OctreeNode* branch)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
- preprocess(group);
-
- if (checkObjects(branch, group))
- {
- processGroup(group);
- }
- }
- LLCamera *mCamera;
- S32 mRes;
- };
- class LLOctreeCullNoFarClip : public LLOctreeCull
- {
- public:
- LLOctreeCullNoFarClip(LLCamera* camera)
- : LLOctreeCull(camera) { }
- virtual S32 frustumCheck(const LLSpatialGroup* group)
- {
- return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
- }
- virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
- {
- S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
- return res;
- }
- };
- class LLOctreeCullShadow : public LLOctreeCull
- {
- public:
- LLOctreeCullShadow(LLCamera* camera)
- : LLOctreeCull(camera) { }
- virtual S32 frustumCheck(const LLSpatialGroup* group)
- {
- return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
- }
- virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
- {
- return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
- }
- };
- class LLOctreeCullVisExtents: public LLOctreeCullShadow
- {
- public:
- LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
- : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
- virtual bool earlyFail(LLSpatialGroup* group)
- {
- if (group->mOctreeNode->getParent() && //never occlusion cull the root node
- LLPipeline::sUseOcclusion && //ignore occlusion if disabled
- group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- return true;
- }
-
- return false;
- }
- virtual void traverse(const LLSpatialGroup::OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
- if (earlyFail(group))
- {
- return;
- }
-
- if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
- mRes == 2)
- { //don't need to do frustum check
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- else
- {
- mRes = frustumCheck(group);
-
- if (mRes)
- { //at least partially in, run on down
- LLSpatialGroup::OctreeTraveler::traverse(n);
- }
- mRes = 0;
- }
- }
- virtual void processGroup(LLSpatialGroup* group)
- {
- llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty())
-
- if (mRes < 2)
- {
- if (mCamera->AABBInFru…
Large files files are truncated, but you can click here to view the full file