diff options
author | Dave Parks <davep@lindenlab.com> | 2023-02-21 20:42:25 -0600 |
---|---|---|
committer | Dave Parks <davep@lindenlab.com> | 2023-02-21 20:42:25 -0600 |
commit | 19f7497d9a01731cbd82be4b522d8b879cdcb8a0 (patch) | |
tree | 4b2e59c87cb5d96b2e9c4e7be0c0131876df8897 | |
parent | 131d116ffd21ef1e726e21c8fe2e6b7068c6c3d9 (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.
-rw-r--r-- | indra/newview/lldrawpool.cpp | 3 | ||||
-rw-r--r-- | indra/newview/lldrawpool.h | 5 | ||||
-rw-r--r-- | indra/newview/lldrawpoolpbropaque.cpp | 31 | ||||
-rw-r--r-- | indra/newview/lldrawpoolpbropaque.h | 16 | ||||
-rw-r--r-- | indra/newview/llreflectionmap.cpp | 81 | ||||
-rw-r--r-- | indra/newview/llreflectionmap.h | 11 | ||||
-rw-r--r-- | indra/newview/llreflectionmapmanager.cpp | 54 | ||||
-rw-r--r-- | indra/newview/llreflectionmapmanager.h | 3 | ||||
-rw-r--r-- | indra/newview/pipeline.cpp | 42 | ||||
-rw-r--r-- | indra/newview/pipeline.h | 2 |
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: |