summaryrefslogtreecommitdiff
path: root/indra/newview/llheroprobemanager.cpp
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@geenzo.com>2023-08-18 21:47:40 -0700
committerJonathan "Geenz" Goodman <geenz@geenzo.com>2023-08-18 21:47:40 -0700
commitd5845fe3e7f3a620453f00421608211d6353905f (patch)
tree7821b75dab3be6e87ac0afa7c2f22614adc47a5a /indra/newview/llheroprobemanager.cpp
parent423820475c7201c39d03c0622dedbf4b1e8b1879 (diff)
Latest updates to the hero probe manager.
DRTVWR-583
Diffstat (limited to 'indra/newview/llheroprobemanager.cpp')
-rw-r--r--indra/newview/llheroprobemanager.cpp923
1 files changed, 42 insertions, 881 deletions
diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp
index 54a61d000e..5edf819fff 100644
--- a/indra/newview/llheroprobemanager.cpp
+++ b/indra/newview/llheroprobemanager.cpp
@@ -57,55 +57,6 @@ static void touch_default_probe(LLReflectionMap* probe)
LLHeroProbeManager::LLHeroProbeManager()
{
- initCubeFree();
-}
-
-void LLHeroProbeManager::initCubeFree()
-{
- // start at 1 because index 0 is reserved for mDefaultProbe
- for (int i = 1; i < LL_MAX_REFLECTION_PROBE_COUNT; ++i)
- {
- mCubeFree.push_back(i);
- }
-}
-
-struct CompareProbeDistance
-{
- LLReflectionMap* mDefaultProbe;
-
- bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs)
- {
- return lhs->mDistance < rhs->mDistance;
- }
-};
-
-static F32 update_score(LLReflectionMap* p)
-{
- return gFrameTimeSeconds - p->mLastUpdateTime - p->mDistance*0.1f;
-}
-
-// return true if a is higher priority for an update than b
-static bool check_priority(LLReflectionMap* a, LLReflectionMap* b)
-{
- if (a->mCubeIndex == -1)
- { // not a candidate for updating
- return false;
- }
- else if (b->mCubeIndex == -1)
- { // certainly higher priority than b
- return true;
- }
- else if (!a->mComplete && !b->mComplete)
- { //neither probe is complete, use distance
- return a->mDistance < b->mDistance;
- }
- else if (a->mComplete && b->mComplete)
- { //both probes are complete, use update_score metric
- return update_score(a) > update_score(b);
- }
-
- // one of these probes is not complete, if b is complete, a is higher priority
- return b->mComplete;
}
// helper class to seed octree with probes
@@ -131,17 +82,10 @@ void LLHeroProbeManager::update()
U32 targetRes = mProbeResolution * 4; // super sample
mRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
}
-
- if (!mHeroRenderTarget.isComplete())
- {
- U32 color_fmt = GL_RGB16F;
- U32 targetRes = mHeroProbeResolution * 2;
- mHeroRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
- }
if (mMipChain.empty())
{
- U32 res = mHeroProbeResolution;
+ U32 res = mProbeResolution;
U32 count = log2((F32)res) + 0.5f;
mMipChain.resize(count);
@@ -156,422 +100,22 @@ void LLHeroProbeManager::update()
LLVector4a camera_pos;
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
-
- // process kill list
- for (auto& probe : mKillList)
- {
- auto const & iter = std::find(mProbes.begin(), mProbes.end(), probe);
- if (iter != mProbes.end())
- {
- deleteProbe(iter - mProbes.begin());
- }
- }
-
- mKillList.clear();
- // process create list
- for (auto& probe : mCreateList)
- {
- mProbes.push_back(probe);
- }
-
- mCreateList.clear();
-
- if (mProbes.empty())
- {
- return;
- }
-
-
- bool did_update = false;
-
- static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
- static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
-
- bool realtime = sDetail >= (S32)LLHeroProbeManager::DetailLevel::REALTIME;
-
- LLReflectionMap* closestDynamic = nullptr;
-
- LLReflectionMap* oldestProbe = nullptr;
- LLReflectionMap* oldestOccluded = nullptr;
-
- if (mUpdatingProbe != nullptr)
- {
- did_update = true;
- doProbeUpdate();
- }
-
- // update distance to camera for all probes
- std::sort(mProbes.begin()+1, mProbes.end(), CompareProbeDistance());
- llassert(mProbes[0] == mDefaultProbe);
- llassert(mProbes[0]->mCubeArray == mTexture);
- llassert(mProbes[0]->mCubeIndex == 0);
-
- // make sure we're assigning cube slots to the closest probes
+ static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
+ static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
- // first free any cube indices for distant probes
- for (U32 i = mReflectionProbeCount; i < mProbes.size(); ++i)
- {
- LLReflectionMap* probe = mProbes[i];
- llassert(probe != nullptr);
-
- if (probe->mCubeIndex != -1 && mUpdatingProbe != probe)
- { // free this index
- mCubeFree.push_back(probe->mCubeIndex);
-
- probe->mCubeArray = nullptr;
- probe->mCubeIndex = -1;
- probe->mComplete = false;
- }
- }
-
- // next distribute the free indices
- U32 count = llmin(mReflectionProbeCount, (U32)mProbes.size());
-
- for (S32 i = 1; i < count && !mCubeFree.empty(); ++i)
- {
- // find the closest probe that needs a cube index
- LLReflectionMap* probe = mProbes[i];
-
- if (probe->mCubeIndex == -1)
- {
- S32 idx = allocateCubeIndex();
- llassert(idx > 0); //if we're still in this loop, mCubeFree should not be empty and allocateCubeIndex should be returning good indices
- probe->mCubeArray = mTexture;
- probe->mCubeIndex = idx;
- }
- }
-
- for (int i = 0; i < mProbes.size(); ++i)
- {
- LLReflectionMap* probe = mProbes[i];
- if (probe->getNumRefs() == 1)
- { // no references held outside manager, delete this probe
- deleteProbe(i);
- --i;
- continue;
- }
-
- if (probe != mDefaultProbe && !probe->isRelevant())
- {
- continue;
- }
-
- LLVector4a d;
-
- if (probe != mDefaultProbe)
- {
- if (probe->mViewerObject) //make sure probes track the viewer objects they are attached to
- {
- probe->mOrigin.load3(probe->mViewerObject->getPositionAgent().mV);
- }
- d.setSub(camera_pos, probe->mOrigin);
- probe->mDistance = d.getLength3().getF32() - probe->mRadius;
- }
- else if (probe->mComplete)
- {
- // make default probe have a distance of 64m for the purposes of prioritization (if it's already been generated once)
- probe->mDistance = 64.f;
- }
- else
- {
- probe->mDistance = -4096.f; //boost priority of default probe when it's not complete
- }
-
- if (probe->mComplete)
- {
- probe->autoAdjustOrigin();
- probe->mFadeIn = llmin((F32) (probe->mFadeIn + gFrameIntervalSeconds), 1.f);
- }
- if (probe->mOccluded && probe->mComplete)
- {
- if (oldestOccluded == nullptr)
- {
- oldestOccluded = probe;
- }
- else if (probe->mLastUpdateTime < oldestOccluded->mLastUpdateTime)
- {
- oldestOccluded = probe;
- }
- }
- else
- {
- if (!did_update &&
- i < mReflectionProbeCount &&
- (oldestProbe == nullptr ||
- check_priority(probe, oldestProbe)))
- {
- oldestProbe = probe;
- }
- }
-
- if (realtime &&
- closestDynamic == nullptr &&
- probe->mCubeIndex != -1 &&
- probe->getIsDynamic())
- {
- closestDynamic = probe;
- }
- }
-
- if (realtime && closestDynamic != nullptr)
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmu - realtime");
- // update the closest dynamic probe realtime
- // should do a full irradiance pass on "odd" frames and a radiance pass on "even" frames
- closestDynamic->autoAdjustOrigin();
-
- // store and override the value of "isRadiancePass" -- parts of the render pipe rely on "isRadiancePass" to set
- // lighting values etc
- bool radiance_pass = isRadiancePass();
- mRadiancePass = mRealtimeRadiancePass;
- for (U32 i = 0; i < 6; ++i)
- {
- updateProbeFace(closestDynamic, i, mProbeResolution, mTexture, mMipChain, mReflectionProbeCount);
- }
- mRealtimeRadiancePass = !mRealtimeRadiancePass;
-
- // restore "isRadiancePass"
- mRadiancePass = radiance_pass;
- }
-
-
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmu - realtime");
- mHeroProbe->mOrigin.load3(LLViewerCamera::instance().mOrigin.mV);
- bool radiance_pass = isRadiancePass();
- mRadiancePass = true;
- for (U32 i = 0; i < 6; ++i)
- {
- updateProbeFace(mHeroProbe, i, mHeroProbeResolution, mHeroArray, mMipChain, mHeroProbeCount);
- }
-
- // restore "isRadiancePass"
- mRadiancePass = radiance_pass;
- }
-
- static LLCachedControl<F32> sUpdatePeriod(gSavedSettings, "RenderDefaultProbeUpdatePeriod", 2.f);
- if ((gFrameTimeSeconds - mDefaultProbe->mLastUpdateTime) < sUpdatePeriod)
- {
- if (sLevel == 0)
- { // when probes are disabled don't update the default probe more often than the prescribed update period
- oldestProbe = nullptr;
- }
- }
- else if (sLevel > 0)
- { // when probes are enabled don't update the default probe less often than the prescribed update period
- oldestProbe = mDefaultProbe;
- }
-
- // switch to updating the next oldest probe
- if (!did_update && oldestProbe != nullptr)
- {
- LLReflectionMap* probe = oldestProbe;
- llassert(probe->mCubeIndex != -1);
-
- probe->autoAdjustOrigin();
-
- mUpdatingProbe = probe;
- 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;
- }
-}
-
-LLReflectionMap* LLHeroProbeManager::addProbe(LLSpatialGroup* group)
-{
- LLReflectionMap* probe = new LLReflectionMap();
- probe->mGroup = group;
-
- if (mDefaultProbe.isNull())
- { //safety check to make sure default probe is always first probe added
- mDefaultProbe = new LLReflectionMap();
- mProbes.push_back(mDefaultProbe);
- }
-
- llassert(mProbes[0] == mDefaultProbe);
-
- if (group)
- {
- probe->mOrigin = group->getOctreeNode()->getCenter();
- }
-
- if (gCubeSnapshot)
- { //snapshot is in progress, mProbes is being iterated over, defer insertion until next update
- mCreateList.push_back(probe);
- }
- else
- {
- mProbes.push_back(probe);
- }
-
- return probe;
-}
-
-struct CompareProbeDepth
-{
- bool operator()(const LLReflectionMap* lhs, const LLReflectionMap* rhs)
- {
- return lhs->mMinDepth < rhs->mMinDepth;
- }
-};
-
-void LLHeroProbeManager::getReflectionMaps(std::vector<LLReflectionMap*>& maps)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
-
- LLMatrix4a modelview;
- modelview.loadu(gGLModelView);
- LLVector4a oa; // scratch space for transformed origin
-
- U32 count = 0;
- U32 lastIdx = 0;
- for (U32 i = 0; count < maps.size() && i < mProbes.size(); ++i)
- {
- mProbes[i]->mLastBindTime = gFrameTimeSeconds; // something wants to use this probe, indicate it's been requested
- if (mProbes[i]->mCubeIndex != -1)
+ // Probe 0 is always our mirror probe. Probe N - 1 is our water probe.
+ mProbes[0]->mOrigin.load3(LLViewerCamera::instance().mOrigin.mV);
+ for (U32 j = 0; j < mProbes.size(); j++)
{
- if (!mProbes[i]->mOccluded && mProbes[i]->mComplete)
+ for (U32 i = 0; i < 6; ++i)
{
- maps[count++] = mProbes[i];
- modelview.affineTransform(mProbes[i]->mOrigin, oa);
- mProbes[i]->mMinDepth = -oa.getF32ptr()[2] - mProbes[i]->mRadius;
- mProbes[i]->mMaxDepth = -oa.getF32ptr()[2] + mProbes[i]->mRadius;
+ updateProbeFace(mProbes[j], i);
}
}
- else
- {
- mProbes[i]->mProbeIndex = -1;
- }
- lastIdx = i;
- }
-
- // set remaining probe indices to -1
- for (U32 i = lastIdx+1; i < mProbes.size(); ++i)
- {
- mProbes[i]->mProbeIndex = -1;
- }
-
- if (count > 1)
- {
- std::sort(maps.begin(), maps.begin() + count, CompareProbeDepth());
- }
-
- for (U32 i = 0; i < count; ++i)
- {
- maps[i]->mProbeIndex = i;
- }
-
- // null terminate list
- if (count < maps.size())
- {
- maps[count] = nullptr;
- }
-}
-
-LLReflectionMap* LLHeroProbeManager::registerSpatialGroup(LLSpatialGroup* group)
-{
- if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
- {
- OctreeNode* node = group->getOctreeNode();
- F32 size = node->getSize().getF32ptr()[0];
- if (size >= 15.f && size <= 17.f)
- {
- return addProbe(group);
- }
- }
-
- return nullptr;
-}
-
-LLReflectionMap* LLHeroProbeManager::registerViewerObject(LLViewerObject* vobj)
-{
- llassert(vobj != nullptr);
-
- LLReflectionMap* probe = new LLReflectionMap();
- probe->mViewerObject = vobj;
- probe->mOrigin.load3(vobj->getPositionAgent().mV);
-
- if (gCubeSnapshot)
- { //snapshot is in progress, mProbes is being iterated over, defer insertion until next update
- mCreateList.push_back(probe);
- }
- else
- {
- mProbes.push_back(probe);
- }
-
- return probe;
-}
-
-S32 LLHeroProbeManager::allocateCubeIndex()
-{
- if (!mCubeFree.empty())
- {
- S32 ret = mCubeFree.front();
- mCubeFree.pop_front();
- return ret;
- }
-
- return -1;
-}
-
-void LLHeroProbeManager::deleteProbe(U32 i)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- LLReflectionMap* probe = mProbes[i];
-
- llassert(probe != mDefaultProbe);
-
- if (probe->mCubeIndex != -1)
- { // mark the cube index used by this probe as being free
- mCubeFree.push_back(probe->mCubeIndex);
- }
- if (mUpdatingProbe == probe)
- {
- mUpdatingProbe = nullptr;
- mUpdatingFace = 0;
- }
-
- // remove from any Neighbors lists
- for (auto& other : probe->mNeighbors)
- {
- auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
- llassert(iter != other->mNeighbors.end());
- other->mNeighbors.erase(iter);
- }
-
- mProbes.erase(mProbes.begin() + i);
-}
-
-
-void LLHeroProbeManager::doProbeUpdate()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- llassert(mUpdatingProbe != nullptr);
-
- updateProbeFace(mUpdatingProbe, mUpdatingFace, mProbeResolution, mTexture, mMipChain, mReflectionProbeCount);
-
- if (++mUpdatingFace == 6)
- {
- updateNeighbors(mUpdatingProbe);
- mUpdatingFace = 0;
- if (isRadiancePass())
- {
- mUpdatingProbe->mComplete = true;
- mUpdatingProbe = nullptr;
- mRadiancePass = false;
- }
- else
- {
- mRadiancePass = true;
- }
}
}
@@ -583,53 +127,36 @@ void LLHeroProbeManager::doProbeUpdate()
// The next six passes render the scene with both radiance and irradiance into the same scratch space cube map and generate a simple mip chain.
// At the end of these passes, a radiance map is generated for this probe and placed into the radiance cube map array at the index for this probe.
// In effect this simulates single-bounce lighting.
-void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 probeResolution, LLPointer<LLCubeMapArray> cubeArray, std::vector<LLRenderTarget> &mipChain, U32 probeCount)
+void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face)
{
// hacky hot-swap of camera specific render targets
gPipeline.mRT = &gPipeline.mAuxillaryRT;
-
- LLRenderTarget* target = &mRenderTarget;
-
- S32 sourceIdx = probeCount;
-
- if (probeResolution == mHeroProbeResolution)
- {
- sourceIdx = 0;
- target = &mHeroRenderTarget;
- }
mLightScale = 1.f;
static LLCachedControl<F32> max_local_light_ambiance(gSavedSettings, "RenderReflectionProbeMaxLocalLightAmbiance", 8.f);
- if (!isRadiancePass() && probe->getAmbiance() > max_local_light_ambiance)
+ if (probe->getAmbiance() > max_local_light_ambiance)
{
mLightScale = max_local_light_ambiance / probe->getAmbiance();
}
- if (probe == mDefaultProbe)
{
- touch_default_probe(probe);
-
gPipeline.pushRenderTypeMask();
//only render sky, water, terrain, and clouds
gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_VOIDWATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES);
+ LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_VOIDWATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::END_RENDER_TYPES);
- probe->update(target->getWidth(), face);
+ probe->update(mRenderTarget.getWidth(), face);
gPipeline.popRenderTypeMask();
}
- else
- {
- probe->update(target->getWidth(), face);
- }
gPipeline.mRT = &gPipeline.mMainRT;
- if (probe != mUpdatingProbe && probe->mType != LLReflectionMap::ProbeType::REFLECTION)
- { // this is the "realtime" probe that's updating every frame, use the secondary scratch space channel
- sourceIdx += 1;
- }
+ S32 sourceIdx = mReflectionProbeCount;
+
+ // Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes.
+ sourceIdx += 1;
gGL.setColorMask(true, true);
LLGLDepthTest depth(GL_FALSE, GL_FALSE);
@@ -647,7 +174,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
gGL.loadIdentity();
gGL.flush();
- U32 res = probeResolution * 2;
+ U32 res = mProbeResolution * 2;
static LLStaticHashedString resScale("resScale");
static LLStaticHashedString direction("direction");
@@ -659,20 +186,20 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
// perform a gaussian blur on the super sampled render before downsampling
{
gGaussianProgram.bind();
- gGaussianProgram.uniform1f(resScale, 1.f / (probeResolution * 2));
+ gGaussianProgram.uniform1f(resScale, 1.f / (mProbeResolution * 2));
S32 diffuseChannel = gGaussianProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
// horizontal
gGaussianProgram.uniform2f(direction, 1.f, 0.f);
gGL.getTexUnit(diffuseChannel)->bind(screen_rt);
- target->bindTarget();
+ mRenderTarget.bindTarget();
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- target->flush();
+ mRenderTarget.flush();
// vertical
gGaussianProgram.uniform2f(direction, 0.f, 1.f);
- gGL.getTexUnit(diffuseChannel)->bind(target);
+ gGL.getTexUnit(diffuseChannel)->bind(&mRenderTarget);
screen_rt->bindTarget();
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
@@ -680,7 +207,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
}
- S32 mips = log2((F32)probeResolution) + 0.5f;
+ S32 mips = log2((F32)mProbeResolution) + 0.5f;
gReflectionMipProgram.bind();
S32 diffuseChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
@@ -699,7 +226,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
}
- gReflectionMipProgram.uniform1f(resScale, 1.f/(probeResolution*2));
+ gReflectionMipProgram.uniform1f(resScale, 1.f/(mProbeResolution*2));
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
@@ -711,11 +238,14 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
if (mip >= 0)
{
LL_PROFILE_GPU_ZONE("probe mip copy");
- cubeArray->bind(0);
-
+ mTexture->bind(0);
+ //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, sourceIdx * 6 + face, 0, 0, res, res);
-
- cubeArray->unbind();
+ //if (i == 0)
+ //{
+ //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res);
+ //}
+ mTexture->unbind();
}
mMipChain[i].flush();
}
@@ -733,14 +263,13 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
mMipChain[0].bindTarget();
static LLStaticHashedString sSourceIdx("sourceIdx");
- if (isRadiancePass())
{
//generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map)
gRadianceGenProgram.bind();
mVertexBuffer->setBuffer();
S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
- cubeArray->bind(channel);
+ mTexture->bind(channel);
gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
@@ -755,7 +284,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1));
gRadianceGenProgram.uniform1f(sMipLevel, i);
- gRadianceGenProgram.uniform1i(sWidth, probeResolution);
+ gRadianceGenProgram.uniform1i(sWidth, mProbeResolution);
for (int cf = 0; cf < 6; ++cf)
{ // for each cube face
@@ -780,50 +309,6 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
gRadianceGenProgram.unbind();
}
- else
- {
- //generate irradiance map
- gIrradianceGenProgram.bind();
- S32 channel = gIrradianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
- cubeArray->bind(channel);
-
- gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
- gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
-
- mVertexBuffer->setBuffer();
- int start_mip = 0;
- // find the mip target to start with based on irradiance map resolution
- for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip)
- {
- if (mMipChain[start_mip].getWidth() == LL_IRRADIANCE_MAP_RESOLUTION)
- {
- break;
- }
- }
-
- //for (int i = start_mip; i < mMipChain.size(); ++i)
- {
- int i = start_mip;
- LL_PROFILE_GPU_ZONE("probe irradiance gen");
- glViewport(0, 0, mMipChain[i].getWidth(), mMipChain[i].getHeight());
- for (int cf = 0; cf < 6; ++cf)
- { // for each cube face
- LLCoordFrame frame;
- frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]);
-
- F32 mat[16];
- frame.getOpenGLRotation(mat);
- gGL.loadMatrix(mat);
-
- mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
-
- S32 res = mMipChain[i].getWidth();
- mIrradianceMaps->bind(channel);
- glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i - start_mip, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
- cubeArray->bind(channel);
- }
- }
- }
mMipChain[0].flush();
@@ -831,59 +316,6 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, U32 p
}
}
-void LLHeroProbeManager::reset()
-{
- mReset = true;
-}
-
-void LLHeroProbeManager::shift(const LLVector4a& offset)
-{
- for (auto& probe : mProbes)
- {
- probe->mOrigin.add(offset);
- }
-}
-
-void LLHeroProbeManager::updateNeighbors(LLReflectionMap* probe)
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- if (mDefaultProbe == probe)
- {
- return;
- }
-
- //remove from existing neighbors
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear");
-
- for (auto& other : probe->mNeighbors)
- {
- auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
- llassert(iter != other->mNeighbors.end()); // <--- bug davep if this ever happens, something broke badly
- other->mNeighbors.erase(iter);
- }
-
- probe->mNeighbors.clear();
- }
-
- // search for new neighbors
- if (probe->isRelevant())
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - search");
- for (auto& other : mProbes)
- {
- if (other != mDefaultProbe && other != probe)
- {
- if (other->isRelevant() && probe->intersects(other))
- {
- probe->mNeighbors.push_back(other);
- other->mNeighbors.push_back(probe);
- }
- }
- }
- }
-}
-
void LLHeroProbeManager::updateUniforms()
{
if (!LLPipeline::sReflectionProbesEnabled)
@@ -892,229 +324,6 @@ void LLHeroProbeManager::updateUniforms()
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
-
- // structure for packing uniform buffer object
- // see class3/deferred/reflectionProbeF.glsl
- struct ReflectionProbeData
- {
- // for box probes, matrix that transforms from camera space to a [-1, 1] cube representing the bounding box of
- // the box probe
- LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT];
-
- // for sphere probes, origin (xyz) and radius (w) of refmaps in clip space
- LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT];
-
- // extra parameters
- // x - irradiance scale
- // y - radiance scale
- // z - fade in
- // w - znear
- LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT];
-
- // indices used by probe:
- // [i][0] - cubemap array index for this probe
- // [i][1] - index into "refNeighbor" for probes that intersect this probe
- // [i][2] - number of probes that intersect this probe, or -1 for no neighbors
- // [i][3] - priority (probe type stored in sign bit - positive for spheres, negative for boxes)
- GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4];
-
- // list of neighbor indices
- GLint refNeighbor[4096];
-
- GLint refBucket[256][4]; //lookup table for which index to start with for the given Z depth
- // numbrer of active refmaps
- GLint refmapCount;
- };
-
- mReflectionMaps.resize(mReflectionProbeCount);
- getReflectionMaps(mReflectionMaps);
-
- ReflectionProbeData rpd;
-
- F32 minDepth[256];
-
- for (int i = 0; i < 256; ++i)
- {
- rpd.refBucket[i][0] = mReflectionProbeCount;
- rpd.refBucket[i][1] = mReflectionProbeCount;
- rpd.refBucket[i][2] = mReflectionProbeCount;
- rpd.refBucket[i][3] = mReflectionProbeCount;
- minDepth[i] = FLT_MAX;
- }
-
- // load modelview matrix into matrix 4a
- LLMatrix4a modelview;
- modelview.loadu(gGLModelView);
- LLVector4a oa; // scratch space for transformed origin
-
- S32 count = 0;
- U32 nc = 0; // neighbor "cursor" - index into refNeighbor to start writing the next probe's list of neighbors
-
- LLEnvironment& environment = LLEnvironment::instance();
- LLSettingsSky::ptr_t psky = environment.getCurrentSky();
-
- static LLCachedControl<F32> cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f);
- static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
- F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance(cloud_shadow_scale, should_auto_adjust);
-
- bool is_ambiance_pass = gCubeSnapshot && !isRadiancePass();
- F32 ambscale = is_ambiance_pass ? 0.f : 1.f;
- F32 radscale = is_ambiance_pass ? 0.5f : 1.f;
-
- for (auto* refmap : mReflectionMaps)
- {
- if (refmap == nullptr)
- {
- break;
- }
-
- if (refmap != mDefaultProbe)
- {
- // bucket search data
- // theory of operation:
- // 1. Determine minimum and maximum depth of each influence volume and store in mDepth (done in getReflectionMaps)
- // 2. Sort by minimum depth
- // 3. Prepare a bucket for each 1m of depth out to 256m
- // 4. For each bucket, store the index of the nearest probe that might influence pixels in that bucket
- // 5. In the shader, lookup the bucket for the pixel depth to get the index of the first probe that could possibly influence
- // the current pixel.
- int depth_min = llclamp(llfloor(refmap->mMinDepth), 0, 255);
- int depth_max = llclamp(llfloor(refmap->mMaxDepth), 0, 255);
- for (U32 i = depth_min; i <= depth_max; ++i)
- {
- if (refmap->mMinDepth < minDepth[i])
- {
- minDepth[i] = refmap->mMinDepth;
- rpd.refBucket[i][0] = refmap->mProbeIndex;
- }
- }
- }
-
- llassert(refmap->mProbeIndex == count);
- llassert(mReflectionMaps[refmap->mProbeIndex] == refmap);
-
- llassert(refmap->mCubeIndex >= 0); // should always be true, if not, getReflectionMaps is bugged
-
- {
- if (refmap->mViewerObject)
- { // have active manual probes live-track the object they're associated with
- refmap->mOrigin.load3(refmap->mViewerObject->getPositionAgent().mV);
- refmap->mRadius = refmap->mViewerObject->getScale().mV[0] * 0.5f;
-
- }
- modelview.affineTransform(refmap->mOrigin, oa);
- rpd.refSphere[count].set(oa.getF32ptr());
- rpd.refSphere[count].mV[3] = refmap->mRadius;
- }
-
- rpd.refIndex[count][0] = refmap->mCubeIndex;
- llassert(nc % 4 == 0);
- rpd.refIndex[count][1] = nc / 4;
- rpd.refIndex[count][3] = refmap->mPriority;
-
- // for objects that are reflection probes, use the volume as the influence volume of the probe
- // only possibile influence volumes are boxes and spheres, so detect boxes and treat everything else as spheres
- if (refmap->getBox(rpd.refBox[count]))
- { // negate priority to indicate this probe has a box influence volume
- rpd.refIndex[count][3] = -rpd.refIndex[count][3];
- }
-
- rpd.refParams[count].set(
- llmax(minimum_ambiance, refmap->getAmbiance())*ambscale, // ambiance scale
- radscale, // radiance scale
- refmap->mFadeIn, // fade in weight
- oa.getF32ptr()[2] - refmap->mRadius); // z near
-
- S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors
- {
- //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refNeighbors");
- //pack neghbor list
- const U32 max_neighbors = 64;
- U32 neighbor_count = 0;
-
- for (auto& neighbor : refmap->mNeighbors)
- {
- if (ni >= 4096)
- { // out of space
- break;
- }
-
- GLint idx = neighbor->mProbeIndex;
- if (idx == -1 || neighbor->mOccluded || neighbor->mCubeIndex == -1)
- {
- continue;
- }
-
- // this neighbor may be sampled
- rpd.refNeighbor[ni++] = idx;
-
- neighbor_count++;
- if (neighbor_count >= max_neighbors)
- {
- break;
- }
- }
- }
-
- if (nc == ni)
- {
- //no neighbors, tag as empty
- rpd.refIndex[count][1] = -1;
- }
- else
- {
- rpd.refIndex[count][2] = ni - nc;
-
- // move the cursor forward
- nc = ni;
- if (nc % 4 != 0)
- { // jump to next power of 4 for compatibility with ivec4
- nc += 4 - (nc % 4);
- }
- }
-
-
- count++;
- }
-
-#if 0
- {
- // fill in gaps in refBucket
- S32 probe_idx = mReflectionProbeCount;
-
- for (int i = 0; i < 256; ++i)
- {
- if (i < count)
- { // for debugging, store depth of mReflectionsMaps[i]
- rpd.refBucket[i][1] = (S32) (mReflectionMaps[i]->mDepth * 10);
- }
-
- if (rpd.refBucket[i][0] == mReflectionProbeCount)
- {
- rpd.refBucket[i][0] = probe_idx;
- }
- else
- {
- probe_idx = rpd.refBucket[i][0];
- }
- }
- }
-#endif
-
- rpd.refmapCount = count;
-
- //copy rpd into uniform buffer object
- if (mUBO == 0)
- {
- glGenBuffers(1, &mUBO);
- }
-
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer");
- glBindBuffer(GL_UNIFORM_BUFFER, mUBO);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeData), &rpd, GL_STREAM_DRAW);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
- }
struct HeroProbeData
{
@@ -1124,22 +333,23 @@ void LLHeroProbeManager::updateUniforms()
HeroProbeData hpd;
+ LLMatrix4a modelview;
modelview.loadu(gGLModelView);
-
+ LLVector4a oa; // scratch space for transformed origin
oa.set(0, 0, 0, 0);
hpd.heroProbeCount = 1;
- modelview.affineTransform(mHeroProbe->mOrigin, oa);
+ modelview.affineTransform(mProbes[0]->mOrigin, oa);
hpd.heroPosition[0].set(oa.getF32ptr());
//copy rpd into uniform buffer object
if (mUBO == 0)
{
- glGenBuffers(1, &mHeroUBO);
+ glGenBuffers(1, &mUBO);
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer");
- glBindBuffer(GL_UNIFORM_BUFFER, mHeroUBO);
+ glBindBuffer(GL_UNIFORM_BUFFER, mUBO);
glBufferData(GL_UNIFORM_BUFFER, sizeof(HeroProbeData), &hpd, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -1190,11 +400,11 @@ void LLHeroProbeManager::initReflectionMaps()
{
U32 count = LL_MAX_REFLECTION_PROBE_COUNT;
- if (mTexture.isNull() || mReflectionProbeCount != count || mReset || mHeroArray.isNull())
+ if (mTexture.isNull() || mReflectionProbeCount != count || mReset)
{
mReset = false;
mReflectionProbeCount = count;
- mProbeResolution = nhpo2(llclamp(gSavedSettings.getU32("RenderReflectionProbeResolution"), (U32)64, (U32)512));
+ mProbeResolution = nhpo2(llclamp(gSavedSettings.getU32("RenderHeroProbeResolution"), (U32)128, (U32)1024));
mMaxProbeLOD = log2f(mProbeResolution) - 1.f; // number of mips - 1
mTexture = new LLCubeMapArray();
@@ -1205,25 +415,6 @@ void LLHeroProbeManager::initReflectionMaps()
mIrradianceMaps = new LLCubeMapArray();
mIrradianceMaps->allocate(LL_IRRADIANCE_MAP_RESOLUTION, 3, mReflectionProbeCount, FALSE);
- // reset probe state
- mUpdatingFace = 0;
- mUpdatingProbe = nullptr;
- mRadiancePass = false;
- mRealtimeRadiancePass = false;
-
- for (auto& probe : mProbes)
- {
- probe->mLastUpdateTime = 0.f;
- probe->mComplete = false;
- probe->mProbeIndex = -1;
- probe->mCubeArray = nullptr;
- probe->mCubeIndex = -1;
- probe->mNeighbors.clear();
- }
-
- mCubeFree.clear();
- initCubeFree();
-
if (mDefaultProbe.isNull())
{
llassert(mProbes.empty()); // default probe MUST be the first probe created
@@ -1233,6 +424,8 @@ void LLHeroProbeManager::initReflectionMaps()
llassert(mProbes[0] == mDefaultProbe);
+ // For hero probes, we treat this as the main mirror probe.
+
mDefaultProbe->mCubeIndex = 0;
mDefaultProbe->mCubeArray = mTexture;
mDefaultProbe->mDistance = 64.f;
@@ -1240,27 +433,7 @@ void LLHeroProbeManager::initReflectionMaps()
mDefaultProbe->mProbeIndex = 0;
touch_default_probe(mDefaultProbe);
- mHeroProbeResolution = 128;
-
- // Revise when we have both water and mirrors in hero probes.
- mHeroProbeCount = 1;
-
- mHeroArray = new LLCubeMapArray();
-
- // We use an extra probe for scratch space on these.
- mHeroArray->allocate(mHeroProbeResolution, 3, mHeroProbeCount + 1, true);
-
- if (mHeroProbe.isNull()) {
- mHeroProbe = new LLReflectionMap();
- }
-
- mHeroProbe->mCubeIndex = 0;
- mHeroProbe->mCubeArray = mHeroArray;
- mHeroProbe->mDistance = 64.f;
- mHeroProbe->mRadius = 4096.f;
- mHeroProbe->mProbeIndex = 0;
- touch_default_probe(mHeroProbe);
-
+ mProbes.push_back(mDefaultProbe);
}
if (mVertexBuffer.isNull())
@@ -1294,28 +467,16 @@ void LLHeroProbeManager::cleanup()
mTexture = nullptr;
mIrradianceMaps = nullptr;
- mHeroArray = nullptr;
mProbes.clear();
- mKillList.clear();
- mCreateList.clear();
mReflectionMaps.clear();
- mUpdatingFace = 0;
mDefaultProbe = nullptr;
mUpdatingProbe = nullptr;
-
- mHeroProbe = nullptr;
glDeleteBuffers(1, &mUBO);
mUBO = 0;
-
- glDeleteBuffers(1, &mHeroUBO);
- mHeroUBO = 0;
-
- // note: also called on teleport (not just shutdown), so make sure we're in a good "starting" state
- initCubeFree();
}
void LLHeroProbeManager::doOcclusion()