summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2023-02-21 20:42:25 -0600
committerDave Parks <davep@lindenlab.com>2023-02-21 20:42:25 -0600
commit19f7497d9a01731cbd82be4b522d8b879cdcb8a0 (patch)
tree4b2e59c87cb5d96b2e9c4e7be0c0131876df8897 /indra/newview
parent131d116ffd21ef1e726e21c8fe2e6b7068c6c3d9 (diff)
DRTVWR-559 WIP -- occlusion culling for reflection probes -- has a defect for objects close to the camera at some angles and leaks query objects, will follow up.
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/lldrawpool.cpp3
-rw-r--r--indra/newview/lldrawpool.h5
-rw-r--r--indra/newview/lldrawpoolpbropaque.cpp31
-rw-r--r--indra/newview/lldrawpoolpbropaque.h16
-rw-r--r--indra/newview/llreflectionmap.cpp81
-rw-r--r--indra/newview/llreflectionmap.h11
-rw-r--r--indra/newview/llreflectionmapmanager.cpp54
-rw-r--r--indra/newview/llreflectionmapmanager.h3
-rw-r--r--indra/newview/pipeline.cpp42
-rw-r--r--indra/newview/pipeline.h2
10 files changed, 210 insertions, 38 deletions
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 56377069bb..c61618c056 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -116,6 +116,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
break;
case POOL_GLTF_PBR:
poolp = new LLDrawPoolGLTFPBR();
+ break;
+ case POOL_GLTF_PBR_ALPHA_MASK:
+ poolp = new LLDrawPoolGLTFPBR(LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK);
break;
default:
LL_ERRS() << "Unknown draw pool type!" << LL_ENDL;
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 2c5e31f579..5e741b2b95 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -58,8 +58,9 @@ public:
POOL_BUMP,
POOL_TERRAIN,
POOL_MATERIALS,
- POOL_GRASS,
POOL_GLTF_PBR,
+ POOL_GRASS,
+ POOL_GLTF_PBR_ALPHA_MASK,
POOL_TREE,
POOL_ALPHA_MASK,
POOL_FULLBRIGHT_ALPHA_MASK,
@@ -109,7 +110,7 @@ public:
virtual void render(S32 pass = 0) {};
virtual void prerender() {};
- virtual U32 getVertexDataMask() = 0;
+ virtual U32 getVertexDataMask() { return 0; } // DEPRECATED -- draw pool doesn't actually determine vertex data mask any more
virtual BOOL verify() const { return TRUE; } // Verify that all data in the draw pool is correct!
virtual S32 getShaderLevel() const { return mShaderLevel; }
diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp
index d30fc22393..b75c83e73a 100644
--- a/indra/newview/lldrawpoolpbropaque.cpp
+++ b/indra/newview/lldrawpoolpbropaque.cpp
@@ -33,9 +33,17 @@
static const U32 gltf_render_types[] = { LLPipeline::RENDER_TYPE_PASS_GLTF_PBR, LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK };
-LLDrawPoolGLTFPBR::LLDrawPoolGLTFPBR() :
- LLRenderPass(POOL_GLTF_PBR)
+LLDrawPoolGLTFPBR::LLDrawPoolGLTFPBR(U32 type) :
+ LLRenderPass(type)
{
+ if (type == LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK)
+ {
+ mRenderType = LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK;
+ }
+ else
+ {
+ mRenderType = LLPipeline::RENDER_TYPE_PASS_GLTF_PBR;
+ }
}
S32 LLDrawPoolGLTFPBR::getNumDeferredPasses()
@@ -47,14 +55,11 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
{
llassert(!LLPipeline::sRenderingHUDs);
- for (U32 type : gltf_render_types)
- {
- gDeferredPBROpaqueProgram.bind();
- pushGLTFBatches(type);
+ gDeferredPBROpaqueProgram.bind();
+ pushGLTFBatches(mRenderType);
- gDeferredPBROpaqueProgram.bind(true);
- pushRiggedGLTFBatches(type + 1);
- }
+ gDeferredPBROpaqueProgram.bind(true);
+ pushRiggedGLTFBatches(mRenderType + 1);
}
S32 LLDrawPoolGLTFPBR::getNumPostDeferredPasses()
@@ -67,12 +72,9 @@ void LLDrawPoolGLTFPBR::renderPostDeferred(S32 pass)
if (LLPipeline::sRenderingHUDs)
{
gHUDPBROpaqueProgram.bind();
- for (U32 type : gltf_render_types)
- {
- pushGLTFBatches(type);
- }
+ pushGLTFBatches(mRenderType);
}
- else
+ else if (mRenderType == LLPipeline::RENDER_TYPE_PASS_GLTF_PBR) // HACK -- don't render glow except for the non-alpha masked implementation
{
gGL.setColorMask(false, true);
gPBRGlowProgram.bind();
@@ -85,4 +87,3 @@ void LLDrawPoolGLTFPBR::renderPostDeferred(S32 pass)
}
}
-
diff --git a/indra/newview/lldrawpoolpbropaque.h b/indra/newview/lldrawpoolpbropaque.h
index 69e063b322..c8a28461fa 100644
--- a/indra/newview/lldrawpoolpbropaque.h
+++ b/indra/newview/lldrawpoolpbropaque.h
@@ -32,21 +32,9 @@
class LLDrawPoolGLTFPBR final : public LLRenderPass
{
public:
- enum
- {
- // See: DEFERRED_VB_MASK
- VERTEX_DATA_MASK = 0
- | LLVertexBuffer::MAP_VERTEX
- | LLVertexBuffer::MAP_NORMAL
- | LLVertexBuffer::MAP_TEXCOORD0 // Diffuse
- | LLVertexBuffer::MAP_TEXCOORD1 // Normal
- | LLVertexBuffer::MAP_TEXCOORD2 // Spec <-- ORM Occlusion Roughness Metal
- | LLVertexBuffer::MAP_TANGENT
- | LLVertexBuffer::MAP_COLOR
- };
- U32 getVertexDataMask() override { return VERTEX_DATA_MASK; }
+ LLDrawPoolGLTFPBR(U32 type = LLDrawPool::POOL_GLTF_PBR);
- LLDrawPoolGLTFPBR();
+ U32 mRenderType = 0;
S32 getNumDeferredPasses() override;
void renderDeferred(S32 pass) override;
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index 394596feea..9fcc6ae902 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -31,9 +31,12 @@
#include "llviewerwindow.h"
#include "llviewerregion.h"
#include "llworld.h"
+#include "llshadermgr.h"
extern F32SecondsImplicit gFrameTimeSeconds;
+extern U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
+
LLReflectionMap::LLReflectionMap()
{
}
@@ -245,3 +248,81 @@ bool LLReflectionMap::getBox(LLMatrix4& box)
return false;
}
+
+bool LLReflectionMap::isActive()
+{
+ return mCubeIndex != -1;
+}
+
+void LLReflectionMap::doOcclusion(const LLVector4a& eye)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+#if 1
+ // super sloppy, but we're doing an occlusion cull against a bounding cube of
+ // a bounding sphere, pad radius so we assume if the eye is within
+ // the bounding sphere of the bounding cube, the node is not culled
+ F32 dist = mRadius * F_SQRT3 + 1.f;
+
+ LLVector4a o;
+ o.setSub(mOrigin, eye);
+
+ bool do_query = false;
+
+ if (o.getLength3().getF32() < dist)
+ { // eye is inside radius, don't attempt to occlude
+ mOccluded = false;
+ if (mViewerObject)
+ {
+ mViewerObject->setDebugText("Camera Non-Occluded");
+ }
+ return;
+ }
+
+ if (mOcclusionQuery == 0)
+ { // no query was previously issued, allocate one and issue
+ glGenQueries(1, &mOcclusionQuery);
+ do_query = true;
+ }
+ else
+ { // query was previously issued, check it and only issue a new query
+ // if previous query is available
+ GLuint result = (GLuint) 0xFFFFFFFF;
+ glGetQueryObjectuiv(mOcclusionQuery, GL_QUERY_RESULT_NO_WAIT, &result);
+
+ if (result != (GLuint) 0xFFFFFFFF)
+ {
+ do_query = true;
+ mOccluded = result == 0;
+ mOcclusionPendingFrames = 0;
+ }
+ else
+ {
+ mOcclusionPendingFrames++;
+ if (mViewerObject)
+ {
+ mViewerObject->setDebugText(llformat("Query Pending - %d", mOcclusionPendingFrames));
+ }
+ }
+ }
+
+ if (do_query)
+ {
+ glBeginQuery(GL_ANY_SAMPLES_PASSED, mOcclusionQuery);
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mOrigin.getF32ptr());
+ F32 r = mRadius + 0.25f; // pad by 1/4m for near clip plane etc
+ shader->uniform3f(LLShaderMgr::BOX_SIZE, mRadius, mRadius, mRadius);
+
+ gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(LLViewerCamera::getInstance(), mOrigin));
+
+ glEndQuery(GL_ANY_SAMPLES_PASSED);
+
+ if (mViewerObject)
+ {
+ mViewerObject->setDebugText(llformat("Query Issued - %.2f, %.2f, %.2f", o.getLength3().getF32(), dist, mRadius));
+ }
+ }
+#endif
+}
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 04bc8d824c..0405d06eb5 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -64,6 +64,12 @@ public:
// return false if no bounding box (treat as sphere influence volume)
bool getBox(LLMatrix4& box);
+ // return true if this probe is active for rendering
+ bool isActive();
+
+ // perform occlusion query/readback
+ void doOcclusion(const LLVector4a& eye);
+
// point at which environment map was last generated from (in agent space)
LLVector4a mOrigin;
@@ -101,5 +107,10 @@ public:
// 0 - automatic probe
// 1 - manual probe
U32 mPriority = 0;
+
+ // occlusion culling state
+ GLuint mOcclusionQuery = 0;
+ bool mOccluded = false;
+ U32 mOcclusionPendingFrames = 0;
};
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index e760bc794c..bfc8b595c2 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -157,6 +157,7 @@ void LLReflectionMapManager::update()
LLReflectionMap* closestDynamic = nullptr;
LLReflectionMap* oldestProbe = nullptr;
+ LLReflectionMap* oldestOccluded = nullptr;
if (mUpdatingProbe != nullptr)
{
@@ -179,12 +180,27 @@ void LLReflectionMapManager::update()
probe->mProbeIndex = i;
LLVector4a d;
-
- if (!did_update &&
- i < mReflectionProbeCount &&
- (oldestProbe == nullptr || probe->mLastUpdateTime < oldestProbe->mLastUpdateTime))
+
+ if (probe->mOccluded)
{
- oldestProbe = probe;
+ if (oldestOccluded == nullptr)
+ {
+ oldestOccluded = probe;
+ }
+ else if (probe->mLastUpdateTime < oldestOccluded->mLastUpdateTime)
+ {
+ oldestOccluded = probe;
+ }
+ }
+ else
+ {
+ if (!did_update &&
+ i < mReflectionProbeCount &&
+ (oldestProbe == nullptr ||
+ probe->mLastUpdateTime < oldestProbe->mLastUpdateTime))
+ {
+ oldestProbe = probe;
+ }
}
if (realtime &&
@@ -240,6 +256,13 @@ void LLReflectionMapManager::update()
doProbeUpdate();
}
+ if (oldestOccluded)
+ {
+ // as far as this occluded probe is concerned, an origin/radius update is as good as a full update
+ oldestOccluded->autoAdjustOrigin();
+ oldestOccluded->mLastUpdateTime = gFrameTimeSeconds;
+ }
+
// update distance to camera for all probes
std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance());
}
@@ -277,8 +300,11 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma
mProbes[i]->mLastBindTime = gFrameTimeSeconds; // something wants to use this probe, indicate it's been requested
if (mProbes[i]->mCubeIndex != -1)
{
- mProbes[i]->mProbeIndex = count;
- maps[count++] = mProbes[i];
+ if (!mProbes[i]->mOccluded)
+ {
+ mProbes[i]->mProbeIndex = count;
+ maps[count++] = mProbes[i];
+ }
}
else
{
@@ -1038,3 +1064,17 @@ void LLReflectionMapManager::cleanup()
// note: also called on teleport (not just shutdown), so make sure we're in a good "starting" state
initCubeFree();
}
+
+void LLReflectionMapManager::doOcclusion()
+{
+ LLVector4a eye;
+ eye.load3(LLViewerCamera::instance().getOrigin().mV);
+
+ for (auto& probe : mProbes)
+ {
+ if (probe != nullptr)
+ {
+ probe->doOcclusion(eye);
+ }
+ }
+}
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index 85f428d75b..fef308541d 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -96,6 +96,9 @@ public:
// True if currently updating a radiance map, false if currently updating an irradiance map
bool isRadiancePass() { return mRadiancePass; }
+ // perform occlusion culling on all active reflection probes
+ void doOcclusion();
+
private:
friend class LLPipeline;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 69b149f82d..d0688d26a9 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -432,6 +432,7 @@ void LLPipeline::init()
getPool(LLDrawPool::POOL_MATERIALS);
getPool(LLDrawPool::POOL_GLOW);
getPool(LLDrawPool::POOL_GLTF_PBR);
+ getPool(LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK);
resetFrameStats();
@@ -1545,6 +1546,9 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
case LLDrawPool::POOL_GLTF_PBR:
poolp = mPBROpaquePool;
break;
+ case LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK:
+ poolp = mPBRAlphaMaskPool;
+ break;
default:
llassert(0);
@@ -2432,6 +2436,26 @@ void LLPipeline::doOcclusion(LLCamera& camera)
LL_PROFILE_GPU_ZONE("doOcclusion");
llassert(!gCubeSnapshot);
+ if (sReflectionProbesEnabled && sUseOcclusion > 1 && !LLPipeline::sShadowRender && !gCubeSnapshot)
+ {
+ gGL.setColorMask(false, false);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ gOcclusionCubeProgram.bind();
+
+ if (mCubeVB.isNull())
+ { //cube VB will be used for issuing occlusion queries
+ mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX);
+ }
+ mCubeVB->setBuffer();
+
+ mReflectionMapManager.doOcclusion();
+ gOcclusionCubeProgram.unbind();
+
+ gGL.setColorMask(true, true);
+ }
+
if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested &&
(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
{
@@ -5192,6 +5216,19 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
}
break;
+ case LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK:
+ if (mPBRAlphaMaskPool)
+ {
+ llassert(0);
+ LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate PBR Alpha Mask Pool" << LL_ENDL;
+ }
+ else
+ {
+ mPBRAlphaMaskPool = new_poolp;
+ }
+ break;
+
+
default:
llassert(0);
LL_WARNS() << "Invalid Pool Type in LLPipeline::addPool()" << LL_ENDL;
@@ -5308,6 +5345,11 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
mPBROpaquePool = NULL;
break;
+ case LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK:
+ llassert(poolp == mPBRAlphaMaskPool);
+ mPBRAlphaMaskPool = NULL;
+ break;
+
default:
llassert(0);
LL_WARNS() << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << LL_ENDL;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 85878dd21d..29dd42e4ec 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -895,6 +895,8 @@ protected:
LLDrawPool* mMaterialsPool = nullptr;
LLDrawPool* mWLSkyPool = nullptr;
LLDrawPool* mPBROpaquePool = nullptr;
+ LLDrawPool* mPBRAlphaMaskPool = nullptr;
+
// Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar
public: