summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorXiaohong Bao <bao@lindenlab.com>2013-05-23 18:25:21 -0600
committerXiaohong Bao <bao@lindenlab.com>2013-05-23 18:25:21 -0600
commit16616ae48d86da75b3809fa6be6c846a9d420603 (patch)
tree6af6a40e0d586d2c7f2a7c2bf1b80f321bda173f /indra
parent8026ac0dc9cb98eec6bb34cb6766c4150f876bf8 (diff)
for SH-4145: Interesting: Implement occlusion culling for object cache
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llappviewer.cpp31
-rw-r--r--indra/newview/llappviewer.h3
-rw-r--r--indra/newview/lldrawable.cpp2
-rw-r--r--indra/newview/lldrawpoolalpha.cpp10
-rw-r--r--indra/newview/llscenemonitor.cpp4
-rw-r--r--indra/newview/llspatialpartition.cpp678
-rw-r--r--indra/newview/llspatialpartition.h79
-rw-r--r--indra/newview/llvieweroctree.cpp620
-rw-r--r--indra/newview/llvieweroctree.h99
-rwxr-xr-xindra/newview/llviewerwindow.cpp4
-rw-r--r--indra/newview/llvocache.cpp41
-rw-r--r--indra/newview/llvovolume.cpp12
-rw-r--r--indra/newview/pipeline.cpp16
13 files changed, 845 insertions, 754 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 0b0db432c8..cb813ea889 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1415,18 +1415,7 @@ bool LLAppViewer::mainLoop()
S32 io_pending = 0;
F32 max_time = llmin(gFrameIntervalSeconds.value() *10.f, 1.f);
- {
- LLFastTimer ftm(FTM_TEXTURE_CACHE);
- work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
- }
- {
- LLFastTimer ftm(FTM_DECODE);
- work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
- }
- {
- LLFastTimer ftm(FTM_DECODE);
- work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
- }
+ work_pending += updateTextureThreads(max_time);
{
LLFastTimer ftm(FTM_VFS);
@@ -1544,6 +1533,24 @@ bool LLAppViewer::mainLoop()
return true;
}
+S32 LLAppViewer::updateTextureThreads(F32 max_time)
+{
+ S32 work_pending = 0;
+ {
+ LLFastTimer ftm(FTM_TEXTURE_CACHE);
+ work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
+ }
+ {
+ LLFastTimer ftm(FTM_DECODE);
+ work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
+ }
+ {
+ LLFastTimer ftm(FTM_DECODE);
+ work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
+ }
+ return work_pending;
+}
+
void LLAppViewer::flushVFSIO()
{
while (1)
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 627652dc30..30e208d01c 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -171,7 +171,8 @@ public:
void purgeCache(); // Clear the local cache.
void purgeCacheImmediate(); //clear local cache immediately.
-
+ S32 updateTextureThreads(F32 max_time);
+
// mute/unmute the system's master audio
virtual void setMasterSystemAudioMute(bool mute);
virtual bool getMasterSystemAudioMute();
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 4d72dd1343..17f610829d 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1145,7 +1145,7 @@ LLSpatialBridge::~LLSpatialBridge()
LLSpatialGroup* group = getSpatialGroup();
if (group)
{
- group->mSpatialPartition->remove(this, group);
+ group->getSpatialPartition()->remove(this, group);
}
}
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 313b310e1e..7020db917b 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -351,7 +351,7 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
{
LLSpatialGroup* group = *i;
- if (group->mSpatialPartition->mRenderByGroup &&
+ if (group->getSpatialPartition()->mRenderByGroup &&
!group->isDead())
{
LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
@@ -389,15 +389,15 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
{
LLSpatialGroup* group = *i;
llassert(group);
- llassert(group->mSpatialPartition);
+ llassert(group->getSpatialPartition());
- if (group->mSpatialPartition->mRenderByGroup &&
+ if (group->getSpatialPartition()->mRenderByGroup &&
!group->isDead())
{
bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow.
// All particle systems seem to come off the wire with texture entries which claim that they glow. This is probably a bug in the data. Suppress.
- group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_PARTICLE &&
- group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE;
+ group->getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_PARTICLE &&
+ group->getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE;
LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 15fe77f028..c592fd0a38 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -107,7 +107,7 @@ void LLSceneMonitor::reset()
if(mQueryObject > 0)
{
- release_occlusion_query_object_name(mQueryObject);
+ LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(mQueryObject);
mQueryObject = 0;
}
}
@@ -437,7 +437,7 @@ void LLSceneMonitor::calcDiffAggregate()
if(!mQueryObject)
{
- mQueryObject = get_new_occlusion_query_object_name();
+ mQueryObject = LLOcclusionCullingGroup::getNewOcclusionQueryObjectName();
}
LLGLDepthTest depth(true, false, GL_ALWAYS);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 53f5658815..3f426d8f8a 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -51,32 +51,16 @@
#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 Partition");
-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
-
extern bool gShiftFrame;
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;
@@ -84,57 +68,6 @@ BOOL LLSpatialGroup::sNoDelete = FALSE;
static F32 sLastMaxTexPriority = 1.f;
static F32 sCurMaxTexPriority = 1.f;
-class LLOcclusionQueryPool : public LLGLNamePool
-{
-public:
- LLOcclusionQueryPool()
- {
- mCurQuery = 1;
- }
-
-protected:
-
- std::list<GLuint> mAvailableName;
- GLuint mCurQuery;
-
- virtual GLuint allocateName()
- {
- GLuint ret = 0;
-
- if (!mAvailableName.empty())
- {
- ret = mAvailableName.front();
- mAvailableName.pop_front();
- }
- else
- {
- ret = mCurQuery++;
- }
-
- return ret;
- }
-
- virtual void releaseName(GLuint name)
- {
-#if LL_TRACK_PENDING_OCCLUSION_QUERIES
- LLSpatialGroup::sPendingQueries.erase(name);
-#endif
- llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end());
- mAvailableName.push_back(name);
- }
-};
-
-static LLOcclusionQueryPool sQueryPool;
-
-GLuint get_new_occlusion_query_object_name()
-{
- return sQueryPool.allocate();
-}
-
-void release_occlusion_query_object_name(GLuint name)
-{
- sQueryPool.release(name);
-}
//static counter for frame to switch LOD on
@@ -148,97 +81,6 @@ void sg_assert(BOOL expr)
#endif
}
-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);
-}
-
-//create a vertex buffer for efficiently rendering cubes
-LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage)
-{
- LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage);
-
- ret->allocateBuffer(8, 64, true);
-
- LLStrider<LLVector3> pos;
- LLStrider<U16> idx;
-
- ret->getVertexStrider(pos);
- ret->getIndexStrider(idx);
-
- pos[0] = LLVector3(-1,-1,-1);
- pos[1] = LLVector3(-1,-1, 1);
- pos[2] = LLVector3(-1, 1,-1);
- pos[3] = LLVector3(-1, 1, 1);
- pos[4] = LLVector3( 1,-1,-1);
- pos[5] = LLVector3( 1,-1, 1);
- pos[6] = LLVector3( 1, 1,-1);
- pos[7] = LLVector3( 1, 1, 1);
-
- for (U32 i = 0; i < 64; i++)
- {
- idx[i] = sOcclusionIndices[i];
- }
-
- ret->flush();
-
- return ret;
-}
-
-static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
-
-BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
-
//returns:
// 0 if sphere and AABB are not intersecting
// 1 if they are
@@ -285,18 +127,7 @@ LLSpatialGroup::~LLSpatialGroup()
sZombieGroups--;
}
- sNodeCount--;
-
- if (gGLManager.mHasOcclusionQuery)
- {
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
- {
- if (mOcclusionQuery[i])
- {
- release_occlusion_query_object_name(mOcclusionQuery[i]);
- }
- }
- }
+ sNodeCount--;
clearDrawMap();
clearAtlasList() ;
@@ -431,7 +262,7 @@ void LLSpatialGroup::clearDrawMap()
BOOL LLSpatialGroup::isHUDGroup()
{
- return mSpatialPartition && mSpatialPartition->isHUDPartition() ;
+ return getSpatialPartition() && getSpatialPartition()->isHUDPartition() ;
}
BOOL LLSpatialGroup::isRecentlyVisible() const
@@ -461,7 +292,7 @@ void LLSpatialGroup::validate()
sg_assert(drawable->getSpatialGroup() == this);
if (drawable->getSpatialBridge())
{
- sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
+ sg_assert(drawable->getSpatialBridge() == getSpatialPartition()->asBridge());
}
/*if (drawable->isSpatialBridge())
@@ -501,14 +332,6 @@ void LLSpatialGroup::validate()
#endif
}
-void LLSpatialGroup::checkStates()
-{
-#if LL_OCTREE_PARANOIA_CHECK
- //LLOctreeStateCheck checker;
- //checker.traverse(mOctreeNode);
-#endif
-}
-
void LLSpatialGroup::validateDrawMap()
{
#if LL_OCTREE_PARANOIA_CHECK
@@ -574,7 +397,7 @@ void LLSpatialGroup::rebuildGeom()
{
if (!isDead())
{
- mSpatialPartition->rebuildGeom(this);
+ getSpatialPartition()->rebuildGeom(this);
if (hasState(LLSpatialGroup::MESH_DIRTY))
{
@@ -587,7 +410,7 @@ void LLSpatialGroup::rebuildMesh()
{
if (!isDead())
{
- mSpatialPartition->rebuildMesh(this);
+ getSpatialPartition()->rebuildMesh(this);
}
}
@@ -665,23 +488,7 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
LLSpatialGroup* LLSpatialGroup::getParent()
{
- if (isDead())
- {
- return NULL;
- }
-
- if(!mOctreeNode)
- {
- return NULL;
- }
- OctreeNode* parent = mOctreeNode->getOctParent();
-
- if (parent)
- {
- return (LLSpatialGroup*) parent->getListener(0);
- }
-
- return NULL;
+ return (LLSpatialGroup*)LLviewerOctreeGroup::getParent();
}
BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
@@ -735,10 +542,10 @@ void LLSpatialGroup::shift(const LLVector4a &offset)
mObjectExtents[0].add(offset);
mObjectExtents[1].add(offset);
- if (!mSpatialPartition->mRenderByGroup &&
- mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TREE &&
- mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TERRAIN &&
- mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_BRIDGE)
+ if (!getSpatialPartition()->mRenderByGroup &&
+ getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TREE &&
+ getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TERRAIN &&
+ getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_BRIDGE)
{
setState(GEOM_DIRTY);
gPipeline.markRebuild(this, TRUE);
@@ -839,135 +646,15 @@ void LLSpatialGroup::clearState(U32 state, S32 mode)
}
}
-//=====================================
-// Occlusion State Set/Clear
-//=====================================
-class LLSpatialSetOcclusionState : public OctreeTraveler
-{
-public:
- U32 mState;
- LLSpatialSetOcclusionState(U32 state) : mState(state) { }
- virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }
-};
-
-class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
-{
-public:
- LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
-
- virtual void traverse(const OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
- if (!group->isOcclusionState(mState))
- {
- OctreeTraveler::traverse(n);
- }
- }
-};
-
-
-void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
-{
- 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])
- {
- release_occlusion_query_object_name(mOcclusionQuery[i]);
- mOcclusionQuery[i] = 0;
- }
- }
- }
- }
- else
- {
- mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
- if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
- {
- release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
- mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
- }
- }
-}
-
-class LLSpatialClearOcclusionState : public OctreeTraveler
-{
-public:
- U32 mState;
-
- LLSpatialClearOcclusionState(U32 state) : mState(state) { }
- virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
-};
-
-class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
-{
-public:
- LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
-
- virtual void traverse(const OctreeNode* n)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
- if (group->isOcclusionState(mState))
- {
- OctreeTraveler::traverse(n);
- }
- }
-};
-
-void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
-{
- 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) : LLviewerOctreeGroup(node),
+LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLOcclusionCullingGroup(node, part),
mObjectBoxSize(1.f),
mGeometryBytes(0),
mSurfaceArea(0.f),
- mBuilt(0.f),
- mSpatialPartition(part),
+ mBuilt(0.f),
mVertexBuffer(NULL),
mBufferUsage(part->mBufferUsage),
mDistance(0.f),
@@ -990,21 +677,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLv
setState(SG_INITIAL_STATE_MASK);
gPipeline.markRebuild(this, TRUE);
- 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;
- }
-
mRadius = 1;
mPixelArea = 1024.f;
}
@@ -1030,10 +702,10 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
#endif
if (!isEmpty())
{
- mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
+ mRadius = getSpatialPartition()->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
(F32) mOctreeNode->getSize().getLength3().getF32();
- mDistance = mSpatialPartition->calcDistance(this, camera);
- mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
+ mDistance = getSpatialPartition()->calcDistance(this, camera);
+ mPixelArea = getSpatialPartition()->calcPixelArea(this, camera);
}
}
@@ -1056,7 +728,7 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
if (!group->hasState(LLSpatialGroup::ALPHA_DIRTY))
{
- if (!group->mSpatialPartition->isBridge())
+ if (!group->getSpatialPartition()->isBridge())
{
LLVector4a view_angle = eye;
@@ -1124,11 +796,6 @@ F32 LLSpatialGroup::getUpdateUrgency() const
}
}
-BOOL LLSpatialGroup::needsUpdate()
-{
- return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
-}
-
BOOL LLSpatialGroup::changeLOD()
{
if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
@@ -1136,11 +803,11 @@ BOOL LLSpatialGroup::changeLOD()
return TRUE;
}
- if (mSpatialPartition->mSlopRatio > 0.f)
+ if (getSpatialPartition()->mSlopRatio > 0.f)
{
F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
- if (fabsf(ratio) >= mSpatialPartition->mSlopRatio)
+ if (fabsf(ratio) >= getSpatialPartition()->mSlopRatio)
{
return TRUE;
}
@@ -1193,7 +860,7 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
}
//clean up avatar attachment stats
- LLSpatialBridge* bridge = mSpatialPartition->asBridge();
+ LLSpatialBridge* bridge = getSpatialPartition()->asBridge();
if (bridge)
{
if (bridge->mAvatar.notNull())
@@ -1214,7 +881,7 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
{
if (child->getListenerCount() == 0)
{
- new LLSpatialGroup(child, mSpatialPartition);
+ new LLSpatialGroup(child, getSpatialPartition());
}
else
{
@@ -1243,14 +910,7 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
if (!keep_occlusion)
{
- for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
- {
- if (mOcclusionQuery[i])
- {
- release_occlusion_query_object_name(mOcclusionQuery[i]);
- mOcclusionQuery[i] = 0;
- }
- }
+ releaseOcclusionQueryObjectNames();
}
@@ -1272,233 +932,13 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
}
}
-static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
-static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion 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);
-
- static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion");
-
- if (wait_for_query && 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.value()*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
- release_occlusion_query_object_name(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] = get_new_occlusion_query_object_name();
- }
-
- // 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]);
- }
-
- LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
- llassert(shader);
-
- shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mBounds[0].getF32ptr());
- shader->uniform3f(LLShaderMgr::BOX_SIZE, mBounds[1][0]+SG_OCCLUSION_FUDGE,
- mBounds[1][1]+SG_OCCLUSION_FUDGE,
- mBounds[1][2]+SG_OCCLUSION_FUDGE);
-
- 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
- gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
- gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
- }
- else
- {
- gPipeline.mCubeVB->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
- gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
- gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
- }
- else
- {
- gPipeline.mCubeVB->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, LLViewerRegion* regionp)
: mRenderByGroup(render_by_group), mBridge(NULL)
{
- mRegionp = regionp;
- mOcclusionEnabled = TRUE;
- mDrawableType = 0;
- mPartitionType = LLViewerRegion::PARTITION_NONE;
- mLODSeed = 0;
- mLODPeriod = 1;
+ mRegionp = regionp;
+ mPartitionType = LLViewerRegion::PARTITION_NONE;
mVertexDataMask = data_mask;
mBufferUsage = buffer_usage;
mDepthMask = FALSE;
@@ -1566,11 +1006,11 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL
BOOL was_visible = curp ? curp->isVisible() : FALSE;
- if (curp && curp->mSpatialPartition != this)
+ if (curp && curp->getSpatialPartition() != this)
{
//keep drawable from being garbage collected
LLPointer<LLDrawable> ptr = drawablep;
- if (curp->mSpatialPartition->remove(drawablep, curp))
+ if (curp->getSpatialPartition()->remove(drawablep, curp))
{
put(drawablep, was_visible);
return;
@@ -1961,7 +1401,7 @@ public:
{
continue;
}
- if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)
+ if (drawable->getVObj().notNull() && !group->getSpatialPartition()->mRenderByGroup)
{
gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
}
@@ -1985,11 +1425,6 @@ void LLSpatialPartition::resetVertexBuffers()
dirty.traverse(mOctree);
}
-BOOL LLSpatialPartition::isOcclusionEnabled()
-{
- return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
-}
-
BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
{
LLVector4a visMina, visMaxa;
@@ -2075,51 +1510,6 @@ S32 LLSpatialPartition::cull(LLCamera &camera)
return 0;
}
-BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
-{
- if (camera->getOrigin().isExactlyZero())
- {
- return FALSE;
- }
-
- const F32 vel = SG_OCCLUSION_FUDGE*2.f;
- LLVector4a fudge;
- fudge.splat(vel);
-
- const LLVector4a* bounds = group->getBounds();
- const LLVector4a& c = bounds[0];
- LLVector4a r;
- r.setAdd(bounds[1], fudge);
-
- /*if (r.magVecSquared() > 1024.0*1024.0)
- {
- return TRUE;
- }*/
-
- LLVector4a e;
- e.load3(camera->getOrigin().mV);
-
- LLVector4a min;
- min.setSub(c,r);
- LLVector4a max;
- max.setAdd(c,r);
-
- S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
- if (lt)
- {
- return FALSE;
- }
-
- S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
- if (gt)
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
void pushVerts(LLDrawInfo* params, U32 mask)
{
LLRenderPass::applyModelMatrix(*params);
@@ -2191,7 +1581,7 @@ void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
void pushBufferVerts(LLSpatialGroup* group, U32 mask)
{
- if (group->mSpatialPartition->mRenderByGroup)
+ if (group->getSpatialPartition()->mRenderByGroup)
{
if (!group->mDrawMap.empty())
{
@@ -2292,7 +1682,7 @@ void renderOctree(LLSpatialGroup* group)
{
continue;
}
- if (!group->mSpatialPartition->isBridge())
+ if (!group->getSpatialPartition()->isBridge())
{
gGL.pushMatrix();
LLVector3 trans = drawable->getRegion()->getOriginAgent();
@@ -2324,7 +1714,7 @@ void renderOctree(LLSpatialGroup* group)
}
}
- if (!group->mSpatialPartition->isBridge())
+ if (!group->getSpatialPartition()->isBridge())
{
gGL.popMatrix();
}
@@ -2336,7 +1726,7 @@ void renderOctree(LLSpatialGroup* group)
else
{
if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->isEmpty()
- && group->mSpatialPartition->mRenderByGroup)
+ && group->getSpatialPartition()->mRenderByGroup)
{
col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
}
@@ -2373,7 +1763,7 @@ void renderOctree(LLSpatialGroup* group)
drawBoxOutline(bounds[0], bounds[1]);
//draw bounding box for draw info
- /*if (group->mSpatialPartition->mRenderByGroup)
+ /*if (group->getSpatialPartition()->mRenderByGroup)
{
gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f);
for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
@@ -3147,7 +2537,7 @@ void renderPhysicsShapes(LLSpatialGroup* group)
LLVOVolume* volume = drawable->getVOVolume();
if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
{
- if (!group->mSpatialPartition->isBridge())
+ if (!group->getSpatialPartition()->isBridge())
{
gGL.pushMatrix();
LLVector3 trans = drawable->getRegion()->getOriginAgent();
@@ -4225,9 +3615,9 @@ public:
LLVector3 local_start = mStart;
LLVector3 local_end = mEnd;
- if (group->mSpatialPartition->isBridge())
+ if (group->getSpatialPartition()->isBridge())
{
- LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix();
+ LLMatrix4 local_matrix = group->getSpatialPartition()->asBridge()->mDrawable->getRenderMatrix();
local_matrix.invert();
local_start = mStart * local_matrix;
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index b592e73403..406e796d4d 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -55,12 +55,6 @@ class LLViewerRegion;
void pushVerts(LLFace* face, U32 mask);
-// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
-U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
-U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center);
-GLuint get_new_occlusion_query_object_name();
-void release_occlusion_query_object_name(GLuint name);
-
class LLDrawInfo : public LLRefCount
{
protected:
@@ -191,13 +185,13 @@ public:
};
LL_ALIGN_PREFIX(16)
-class LLSpatialGroup : public LLviewerOctreeGroup
+class LLSpatialGroup : public LLOcclusionCullingGroup
{
friend class LLSpatialPartition;
friend class LLOctreeStateCheck;
public:
- LLSpatialGroup(const LLSpatialGroup& rhs) : LLviewerOctreeGroup(rhs)
+ LLSpatialGroup(const LLSpatialGroup& rhs) : LLOcclusionCullingGroup(rhs)
{
*this = rhs;
}
@@ -218,7 +212,6 @@ public:
return *this;
}
- static std::set<GLuint> sPendingQueries; //pending occlusion queries
static U32 sNodeCount;
static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE
@@ -256,17 +249,7 @@ public:
typedef enum
{
- OCCLUDED = 0x00010000,
- QUERY_PENDING = 0x00020000,
- ACTIVE_OCCLUSION = 0x00040000,
- DISCARD_QUERY = 0x00080000,
- EARLY_FAIL = 0x00100000,
- } eOcclusionState;
-
- typedef enum
- {
- DEAD = LLviewerOctreeGroup::INVALID_STATE,
- GEOM_DIRTY = (DEAD << 1),
+ GEOM_DIRTY = LLviewerOctreeGroup::INVALID_STATE,
ALPHA_DIRTY = (GEOM_DIRTY << 1),
IN_IMAGE_QUEUE = (ALPHA_DIRTY << 1),
IMAGE_DIRTY = (IN_IMAGE_QUEUE << 1),
@@ -275,33 +258,19 @@ public:
IN_BUILD_Q1 = (NEW_DRAWINFO << 1),
IN_BUILD_Q2 = (IN_BUILD_Q1 << 1),
STATE_MASK = 0x0000FFFF,
- } eSpatialState;
-
- typedef enum
- {
- STATE_MODE_SINGLE = 0, //set one node
- STATE_MODE_BRANCH, //set entire branch
- STATE_MODE_DIFF, //set entire branch as long as current state is different
- STATE_MODE_ALL_CAMERAS, //used for occlusion state, set state for all cameras
- } eSetStateMode;
+ } eSpatialState;
LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part);
- BOOL isHUDGroup() ;
- BOOL isDead() { return hasState(DEAD); }
- BOOL isOcclusionState(U32 state) const { return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; }
+ BOOL isHUDGroup() ;
void clearDrawMap();
void validate();
- void checkStates();
void validateDrawMap();
void setState(U32 state, S32 mode);
void clearState(U32 state, S32 mode);
- void clearState(U32 state) {mState &= ~state;}
-
- void setOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
- void clearOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
+ void clearState(U32 state) {mState &= ~state;}
LLSpatialGroup* getParent();
@@ -309,13 +278,10 @@ public:
BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);
BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group
BOOL isRecentlyVisible() const;
- void shift(const LLVector4a &offset);
- void checkOcclusion(); //read back last occlusion query (if any)
- void doOcclusion(LLCamera* camera); //issue occlusion query
+ void shift(const LLVector4a &offset);
void destroyGL(bool keep_occlusion = false);
void updateDistance(LLCamera& camera);
- BOOL needsUpdate();
F32 getUpdateUrgency() const;
BOOL changeLOD();
void rebuildGeom();
@@ -327,6 +293,8 @@ public:
void drawObjectBox(LLColor4 col);
+ LLSpatialPartition* getSpatialPartition() {return (LLSpatialPartition*)mSpatialPartition;}
+
//LISTENER FUNCTIONS
virtual void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* face);
virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* face);
@@ -372,12 +340,8 @@ private:
//-------------------
protected:
- virtual ~LLSpatialGroup();
-
- U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS];
- U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS];
-
- S32 mLODHash;
+ virtual ~LLSpatialGroup();
+
static S32 sLODSeed;
public:
@@ -387,11 +351,9 @@ public:
U32 mGeometryBytes; //used by volumes to track how many bytes of geometry data are in this node
F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node
- F32 mBuilt;
- LLSpatialPartition* mSpatialPartition;
+ F32 mBuilt;
- LLPointer<LLVertexBuffer> mVertexBuffer;
- GLuint mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];
+ LLPointer<LLVertexBuffer> mVertexBuffer;
U32 mBufferUsage;
draw_map_t mDrawMap;
@@ -461,21 +423,18 @@ public:
void renderDebug();
void renderIntersectingBBoxes(LLCamera* camera);
void restoreGL();
- void resetVertexBuffers();
- BOOL isOcclusionEnabled();
+ void resetVertexBuffers();
+
BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax);
public:
LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this
// use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe
- // to call asBridge() from the destructor
- BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
+ // to call asBridge() from the destructor
+
BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
- U32 mBufferUsage;
- U32 mDrawableType;
- const BOOL mRenderByGroup;
- U32 mLODSeed;
- U32 mLODPeriod; //number of frames between LOD updates for a given spatial group (staggered by mLODSeed)
+ U32 mBufferUsage;
+ const BOOL mRenderByGroup;
U32 mVertexDataMask;
F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25);
BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 926d791d1f..844075089f 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -27,6 +27,11 @@
#include "llviewerprecompiledheaders.h"
#include "llvieweroctree.h"
#include "llviewerregion.h"
+#include "pipeline.h"
+#include "llviewercontrol.h"
+#include "llappviewer.h"
+#include "llglslshader.h"
+#include "llviewershadermgr.h"
//-----------------------------------------------------------------------------------
//static variables definitions
@@ -37,6 +42,100 @@ BOOL LLViewerOctreeDebug::sInDebug = FALSE;
//-----------------------------------------------------------------------------------
//some global functions definitions
//-----------------------------------------------------------------------------------
+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);
+}
+
+//create a vertex buffer for efficiently rendering cubes
+LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage)
+{
+ LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage);
+
+ ret->allocateBuffer(8, 64, true);
+
+ LLStrider<LLVector3> pos;
+ LLStrider<U16> idx;
+
+ ret->getVertexStrider(pos);
+ ret->getIndexStrider(idx);
+
+ pos[0] = LLVector3(-1,-1,-1);
+ pos[1] = LLVector3(-1,-1, 1);
+ pos[2] = LLVector3(-1, 1,-1);
+ pos[3] = LLVector3(-1, 1, 1);
+ pos[4] = LLVector3( 1,-1,-1);
+ pos[5] = LLVector3( 1,-1, 1);
+ pos[6] = LLVector3( 1, 1,-1);
+ pos[7] = LLVector3( 1, 1, 1);
+
+ for (U32 i = 0; i < 64; i++)
+ {
+ idx[i] = sOcclusionIndices[i];
+ }
+
+ ret->flush();
+
+ return ret;
+}
+
+
+#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
+
+const F32 SG_OCCLUSION_FUDGE = 0.25f;
+#define SG_DISCARD_TOLERANCE 0.01f
+
+
S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
{
return AABBSphereIntersectR2(min, max, origin, rad*rad);
@@ -540,6 +639,11 @@ void LLviewerOctreeGroup::handleChildRemoval(const OctreeNode* parent, const Oct
LLviewerOctreeGroup* LLviewerOctreeGroup::getParent()
{
+ if (isDead())
+ {
+ return NULL;
+ }
+
if(!mOctreeNode)
{
return NULL;
@@ -629,10 +733,519 @@ void LLviewerOctreeGroup::setVisible()
{
mVisible[LLViewerCamera::sCurCameraID] = LLViewerOctreeEntryData::getCurrentFrame();
}
+
+void LLviewerOctreeGroup::checkStates()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ //LLOctreeStateCheck checker;
+ //checker.traverse(mOctreeNode);
+#endif
+}
+
+//-------------------------------------------------------------------------------------------
+//occulsion culling functions and classes
+//-------------------------------------------------------------------------------------------
+std::set<U32> LLOcclusionCullingGroup::sPendingQueries;
+class LLOcclusionQueryPool : public LLGLNamePool
+{
+public:
+ LLOcclusionQueryPool()
+ {
+ mCurQuery = 1;
+ }
+
+protected:
+
+ std::list<GLuint> mAvailableName;
+ GLuint mCurQuery;
+
+ virtual GLuint allocateName()
+ {
+ GLuint ret = 0;
+
+ if (!mAvailableName.empty())
+ {
+ ret = mAvailableName.front();
+ mAvailableName.pop_front();
+ }
+ else
+ {
+ ret = mCurQuery++;
+ }
+
+ return ret;
+ }
+
+ virtual void releaseName(GLuint name)
+ {
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ LLSpatialGroup::sPendingQueries.erase(name);
+#endif
+ llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end());
+ mAvailableName.push_back(name);
+ }
+};
+
+static LLOcclusionQueryPool sQueryPool;
+U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()
+{
+ return sQueryPool.allocate();
+}
+
+void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)
+{
+ sQueryPool.release(name);
+}
+
+//=====================================
+// Occlusion State Set/Clear
+//=====================================
+class LLSpatialSetOcclusionState : public OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialSetOcclusionState(U32 state) : mState(state) { }
+ virtual void visit(const OctreeNode* branch) { ((LLOcclusionCullingGroup*) branch->getListener(0))->setOcclusionState(mState); }
+};
+
+class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
+{
+public:
+ LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
+
+ virtual void traverse(const OctreeNode* n)
+ {
+ LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*) n->getListener(0);
+
+ if (!group->isOcclusionState(mState))
+ {
+ OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+
+LLOcclusionCullingGroup::LLOcclusionCullingGroup(OctreeNode* node, LLViewerOctreePartition* part) :
+ LLviewerOctreeGroup(node),
+ mSpatialPartition(part)
+{
+ part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
+ mLODHash = part->mLODSeed;
+
+ OctreeNode* oct_parent = node->getOctParent();
+ LLOcclusionCullingGroup* parent = oct_parent ? (LLOcclusionCullingGroup*) 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;
+ }
+}
+
+LLOcclusionCullingGroup::~LLOcclusionCullingGroup()
+{
+ releaseOcclusionQueryObjectNames();
+}
+
+BOOL LLOcclusionCullingGroup::needsUpdate()
+{
+ return (LLDrawable::getCurrentFrame() % mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
+}
+
+//virtual
+void LLOcclusionCullingGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
+{
+ if (child->getListenerCount() == 0)
+ {
+ new LLOcclusionCullingGroup(child, mSpatialPartition);
+ }
+ else
+ {
+ OCT_ERRS << "LLOcclusionCullingGroup redundancy detected." << llendl;
+ }
+
+ unbound();
+
+ ((LLviewerOctreeGroup*)child->getListener(0))->unbound();
+}
+
+void LLOcclusionCullingGroup::releaseOcclusionQueryObjectNames()
+{
+ if (gGLManager.mHasOcclusionQuery)
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
+ {
+ if (mOcclusionQuery[i])
+ {
+ releaseOcclusionQueryObjectName(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
+ }
+ }
+}
+
+void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode)
+{
+ 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])
+ {
+ releaseOcclusionQueryObjectName(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+ }
+}
+
+class LLSpatialClearOcclusionState : public OctreeTraveler
+{
+public:
+ U32 mState;
+
+ LLSpatialClearOcclusionState(U32 state) : mState(state) { }
+ virtual void visit(const OctreeNode* branch) { ((LLOcclusionCullingGroup*) branch->getListener(0))->clearOcclusionState(mState); }
+};
+
+class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
+{
+public:
+ LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
+
+ virtual void traverse(const OctreeNode* n)
+ {
+ LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*) n->getListener(0);
+
+ if (group->isOcclusionState(mState))
+ {
+ OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode)
+{
+ 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;
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait");
+
+BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera)
+{
+ if (camera->getOrigin().isExactlyZero())
+ {
+ return FALSE;
+ }
+
+ const F32 vel = SG_OCCLUSION_FUDGE*2.f;
+ LLVector4a fudge;
+ fudge.splat(vel);
+
+ const LLVector4a* bounds = getBounds();
+ const LLVector4a& c = bounds[0];
+ LLVector4a r;
+ r.setAdd(bounds[1], fudge);
+
+ /*if (r.magVecSquared() > 1024.0*1024.0)
+ {
+ return TRUE;
+ }*/
+
+ LLVector4a e;
+ e.load3(camera->getOrigin().mV);
+
+ LLVector4a min;
+ min.setSub(c,r);
+ LLVector4a max;
+ max.setAdd(c,r);
+
+ S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
+ if (lt)
+ {
+ return FALSE;
+ }
+
+ S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
+ if (gt)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void LLOcclusionCullingGroup::checkOcclusion()
+{
+ if (LLPipeline::sUseOcclusion > 1)
+ {
+ LLFastTimer t(FTM_OCCLUSION_READBACK);
+ LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent();
+ if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::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);
+
+ static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion");
+
+ if (wait_for_query && 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)
+ {
+ //do some usefu work while we wait
+ F32 max_time = llmin(gFrameIntervalSeconds.value()*10.f, 1.f);
+ LLAppViewer::instance()->updateTextureThreads(max_time);
+
+ 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
+ releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+
+ if (isOcclusionState(DISCARD_QUERY))
+ {
+ res = 2;
+ }
+
+ if (res > 0)
+ {
+ assert_states_valid(this);
+ clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ assert_states_valid(this);
+
+ setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF);
+
+ assert_states_valid(this);
+ }
+
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
+ }
+ else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED))
+ { //check occlusion has been issued for occluded node that has not had a query issued
+ assert_states_valid(this);
+ clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::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 LLOcclusionCullingGroup::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))
+ {
+ LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
+ setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
+ assert_states_valid(this);
+ clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::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] = getNewOcclusionQueryObjectName();
+ }
+
+ // 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]);
+ }
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(shader);
+
+ shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mBounds[0].getF32ptr());
+ shader->uniform3f(LLShaderMgr::BOX_SIZE, mBounds[1][0]+SG_OCCLUSION_FUDGE,
+ mBounds[1][1]+SG_OCCLUSION_FUDGE,
+ mBounds[1][2]+SG_OCCLUSION_FUDGE);
+
+ 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
+ gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ gPipeline.mCubeVB->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
+ gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+ gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);
+ }
+ else
+ {
+ gPipeline.mCubeVB->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(LLOcclusionCullingGroup::QUERY_PENDING);
+ clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY);
+ }
+ }
+ }
+ }
+}
+//-------------------------------------------------------------------------------------------
+//end of occulsion culling functions and classes
+//-------------------------------------------------------------------------------------------
+
//-----------------------------------------------------------------------------------
//class LLViewerOctreePartition definitions
//-----------------------------------------------------------------------------------
-LLViewerOctreePartition::LLViewerOctreePartition() : mRegionp(NULL)
+LLViewerOctreePartition::LLViewerOctreePartition() :
+ mRegionp(NULL),
+ mOcclusionEnabled(TRUE),
+ mDrawableType(0),
+ mLODSeed(0),
+ mLODPeriod(1)
{
LLVector4a center, size;
center.splat(0.f);
@@ -647,6 +1260,11 @@ LLViewerOctreePartition::~LLViewerOctreePartition()
mOctree = NULL;
}
+BOOL LLViewerOctreePartition::isOcclusionEnabled()
+{
+ return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
+}
+
//-----------------------------------------------------------------------------------
//class LLViewerOctreeCull definitions
//-----------------------------------------------------------------------------------
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index b6faf4c7ba..ed77e4bb7e 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -43,6 +43,7 @@ class LLViewerRegion;
class LLViewerOctreeEntryData;
class LLviewerOctreeGroup;
class LLViewerOctreeEntry;
+class LLViewerOctreePartition;
typedef LLOctreeListener<LLViewerOctreeEntry> OctreeListener;
typedef LLTreeNode<LLViewerOctreeEntry> TreeNode;
@@ -50,6 +51,18 @@ typedef LLOctreeNode<LLViewerOctreeEntry> OctreeNode;
typedef LLOctreeRoot<LLViewerOctreeEntry> OctreeRoot;
typedef LLOctreeTraveler<LLViewerOctreeEntry> OctreeTraveler;
+#if LL_OCTREE_PARANOIA_CHECK
+#define assert_octree_valid(x) x->validate()
+#define assert_states_valid(x) ((LLviewerOctreeGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates()
+#else
+#define assert_octree_valid(x)
+#define assert_states_valid(x)
+#endif
+
+// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
+U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
+U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center);
+
S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad);
S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared);
@@ -181,14 +194,15 @@ class LLviewerOctreeGroup : public LLOctreeListener<LLViewerOctreeEntry>
protected:
~LLviewerOctreeGroup();
-public:
+public:
enum
{
CLEAN = 0x00000000,
DIRTY = 0x00000001,
OBJECT_DIRTY = 0x00000002,
SKIP_FRUSTUM_CHECK = 0x00000004,
- INVALID_STATE = 0x00000008,
+ DEAD = 0x00000008,
+ INVALID_STATE = 0x00000010,
};
public:
@@ -216,6 +230,8 @@ public:
virtual void unbound();
virtual void rebound();
+
+ BOOL isDead() { return hasState(DEAD); }
void setVisible();
BOOL isVisible() const;
@@ -251,9 +267,11 @@ public:
U32 getElementCount() const { return mOctreeNode->getElementCount(); }
bool hasElement(LLViewerOctreeEntryData* data);
+protected:
+ void checkStates();
private:
- virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut);
-
+ virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut);
+
protected:
U32 mState;
OctreeNode* mOctreeNode;
@@ -261,12 +279,76 @@ protected:
LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects)
LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node
LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
- LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node
+ LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node
public:
- S32 mVisible[LLViewerCamera::NUM_CAMERAS];
+ S32 mVisible[LLViewerCamera::NUM_CAMERAS];
+
}LL_ALIGN_POSTFIX(16);
+//octree group which has capability to support occlusion culling
+//LL_ALIGN_PREFIX(16)
+class LLOcclusionCullingGroup : public LLviewerOctreeGroup
+{
+public:
+ typedef enum
+ {
+ OCCLUDED = 0x00010000,
+ QUERY_PENDING = 0x00020000,
+ ACTIVE_OCCLUSION = 0x00040000,
+ DISCARD_QUERY = 0x00080000,
+ EARLY_FAIL = 0x00100000,
+ } eOcclusionState;
+
+ typedef enum
+ {
+ STATE_MODE_SINGLE = 0, //set one node
+ STATE_MODE_BRANCH, //set entire branch
+ STATE_MODE_DIFF, //set entire branch as long as current state is different
+ STATE_MODE_ALL_CAMERAS, //used for occlusion state, set state for all cameras
+ } eSetStateMode;
+
+public:
+ LLOcclusionCullingGroup(OctreeNode* node, LLViewerOctreePartition* part);
+ LLOcclusionCullingGroup(const LLOcclusionCullingGroup& rhs) : LLviewerOctreeGroup(rhs)
+ {
+ *this = rhs;
+ }
+ ~LLOcclusionCullingGroup();
+
+ void setOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
+ void clearOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
+ void checkOcclusion(); //read back last occlusion query (if any)
+ void doOcclusion(LLCamera* camera); //issue occlusion query
+ BOOL isOcclusionState(U32 state) const { return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; }
+
+ BOOL needsUpdate();
+
+ //virtual
+ void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
+
+ static U32 getNewOcclusionQueryObjectName();
+ static void releaseOcclusionQueryObjectName(U32 name);
+
+protected:
+ void releaseOcclusionQueryObjectNames();
+
+private:
+ BOOL earlyFail(LLCamera* camera);
+
+protected:
+ U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS];
+ U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS];
+
+ S32 mLODHash;
+
+ LLViewerOctreePartition* mSpatialPartition;
+ U32 mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];
+
+public:
+ static std::set<U32> sPendingQueries;
+};//LL_ALIGN_POSTFIX(16);
+
class LLViewerOctreePartition
{
public:
@@ -275,11 +357,16 @@ public:
// Cull on arbitrary frustum
virtual S32 cull(LLCamera &camera) = 0;
+ BOOL isOcclusionEnabled();
public:
U32 mPartitionType;
+ U32 mDrawableType;
OctreeNode* mOctree;
LLViewerRegion* mRegionp; // the region this partition belongs to.
+ BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
+ U32 mLODSeed;
+ U32 mLODPeriod; //number of frames between LOD updates for a given spatial group (staggered by mLODSeed)
};
class LLViewerOctreeCull : public OctreeTraveler
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index fea44a38c6..eb004106c3 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -594,9 +594,9 @@ public:
ypos += y_inc;
- if (!LLSpatialGroup::sPendingQueries.empty())
+ if (!LLOcclusionCullingGroup::sPendingQueries.empty())
{
- addText(xpos,ypos, llformat("%d Queries pending", LLSpatialGroup::sPendingQueries.size()));
+ addText(xpos,ypos, llformat("%d Queries pending", LLOcclusionCullingGroup::sPendingQueries.size()));
ypos += y_inc;
}
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index eba768fef4..6261540765 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -372,10 +372,11 @@ void LLVOCacheEntry::setBoundingInfo(const LLVector3& pos, const LLVector3& scal
//-------------------------------------------------------------------
LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
{
+ mLODPeriod = 16;
mRegionp = regionp;
mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;
- new LLviewerOctreeGroup(mOctree);
+ new LLOcclusionCullingGroup(mOctree, this);
}
void LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry)
@@ -400,11 +401,31 @@ public:
mLocalShift = shift;
}
+ virtual bool earlyFail(LLviewerOctreeGroup* base_group)
+ {
+ LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)base_group;
+ if(group->needsUpdate())
+ {
+ return false; //needs to issue new occlusion culling check.
+ }
+
+ group->checkOcclusion();
+
+ if (group->getOctreeNode()->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
{
- //S32 res = AABBInRegionFrustumGroupBounds(group);
+ S32 res = AABBInRegionFrustumGroupBounds(group);
- S32 res = AABBInRegionFrustumNoFarClipGroupBounds(group);
+ //S32 res = AABBInRegionFrustumNoFarClipGroupBounds(group);
if (res != 0)
{
res = llmin(res, AABBRegionSphereIntersectGroupExtents(group, mLocalShift));
@@ -414,9 +435,9 @@ public:
virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
{
- //S32 res = AABBInRegionFrustumObjectBounds(group);
+ S32 res = AABBInRegionFrustumObjectBounds(group);
- S32 res = AABBInRegionFrustumNoFarClipObjectBounds(group);
+ //S32 res = AABBInRegionFrustumNoFarClipObjectBounds(group);
if (res != 0)
{
res = llmin(res, AABBRegionSphereIntersectObjectExtents(group, mLocalShift));
@@ -426,7 +447,15 @@ public:
virtual void processGroup(LLviewerOctreeGroup* base_group)
{
- mRegionp->addVisibleGroup(base_group);
+ LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)base_group;
+ if (group->needsUpdate() || group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
+ {
+ ((LLOcclusionCullingGroup*)group)->doOcclusion(mCamera);
+ group->setVisible();
+ return; //wait for occlusion culling results
+ }
+
+ mRegionp->addVisibleGroup(group);
}
private:
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 12f268d324..d1c1602437 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4190,7 +4190,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LLVOAvatar* pAvatarVO = NULL;
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+ LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
if (bridge)
{
if (bridge->mAvatar.isNull())
@@ -4227,10 +4227,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
std::vector<LLFace*> simple_faces;
std::vector<LLFace*> alpha_faces;
- U32 useage = group->mSpatialPartition->mBufferUsage;
+ U32 useage = group->getSpatialPartition()->mBufferUsage;
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
- U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
+ U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
U32 cur_total = 0;
@@ -4837,7 +4837,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
#endif
//calculate maximum number of vertices to store in a single buffer
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
{
@@ -5228,7 +5228,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
{
//initialize to default usage for this partition
- U32 usage = group->mSpatialPartition->mBufferUsage;
+ U32 usage = group->getSpatialPartition()->mBufferUsage;
//clear off any old faces
mFaceList.clear();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 1b5148e560..a8156b46ed 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1663,7 +1663,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
if (drawablep->getSpatialGroup())
{
LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
- if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
+ if (!drawablep->getSpatialGroup()->getSpatialPartition()->remove(drawablep, drawablep->getSpatialGroup()))
{
#ifdef LL_RELEASE_FOR_DOWNLOAD
llwarns << "Couldn't remove object from spatial group!" << llendl;
@@ -2480,7 +2480,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
assertInitialized();
- if (!group->mSpatialPartition->mRenderByGroup)
+ if (!group->getSpatialPartition()->mRenderByGroup)
{ //render by drawable
sCull->pushDrawableGroup(group);
}
@@ -2729,7 +2729,7 @@ void LLPipeline::rebuildGroups()
{
group->rebuildGeom();
- if (group->mSpatialPartition->mRenderByGroup)
+ if (group->getSpatialPartition()->mRenderByGroup)
{
count++;
}
@@ -3052,9 +3052,9 @@ void LLPipeline::markMeshDirty(LLSpatialGroup* group)
void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
{
- if (group && !group->isDead() && group->mSpatialPartition)
+ if (group && !group->isDead() && group->getSpatialPartition())
{
- if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
+ if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD)
{
priority = TRUE;
}
@@ -3631,7 +3631,7 @@ void LLPipeline::postSort(LLCamera& camera)
if (alpha != group->mDrawMap.end())
{ //store alpha groups for sorting
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+ LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
{
if (bridge)
@@ -5202,7 +5202,7 @@ void LLPipeline::renderDebug()
continue;
}
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+ LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
{
@@ -9990,7 +9990,7 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu
LLSpatialGroup* group = *i;
if (!group->isDead() &&
(!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
- gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
+ gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) &&
group->mDrawMap.find(type) != group->mDrawMap.end())
{
pass->renderGroup(group,type,mask,texture);