diff options
author | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2023-08-18 21:47:40 -0700 |
---|---|---|
committer | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2023-08-18 21:47:40 -0700 |
commit | d5845fe3e7f3a620453f00421608211d6353905f (patch) | |
tree | 7821b75dab3be6e87ac0afa7c2f22614adc47a5a /indra | |
parent | 423820475c7201c39d03c0622dedbf4b1e8b1879 (diff) |
Latest updates to the hero probe manager.
DRTVWR-583
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/llappviewer.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llheroprobemanager.cpp | 923 | ||||
-rw-r--r-- | indra/newview/llheroprobemanager.h | 87 | ||||
-rw-r--r-- | indra/newview/pipeline.cpp | 31 | ||||
-rw-r--r-- | indra/newview/pipeline.h | 2 |
5 files changed, 75 insertions, 969 deletions
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 343778fe03..3b0ba77ea2 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1517,6 +1517,7 @@ bool LLAppViewer::doFrame() LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Snapshot"); pingMainloopTimeout("Main:Snapshot"); gPipeline.mReflectionMapManager.update(); + gPipeline.mHeroProbeManager.update(); LLFloaterSnapshot::update(); // take snapshots LLFloaterSimpleOutfitSnapshot::update(); gGLActive = FALSE; 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() diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h index be761a680e..95e3963d1a 100644 --- a/indra/newview/llheroprobemanager.h +++ b/indra/newview/llheroprobemanager.h @@ -35,13 +35,7 @@ class LLSpatialGroup; class LLViewerObject; // number of reflection probes to keep in vram -#define LL_MAX_REFLECTION_PROBE_COUNT 256 - -// reflection probe resolution -#define LL_IRRADIANCE_MAP_RESOLUTION 64 - -// reflection probe mininum scale -#define LL_REFLECTION_PROBE_MINIMUM_SCALE 1.f; +#define LL_MAX_HERO_PROBE_COUNT 2 class alignas(16) LLHeroProbeManager { @@ -63,30 +57,6 @@ public: // maintain reflection probes void update(); - // add a probe for the given spatial group - LLReflectionMap* addProbe(LLSpatialGroup* group = nullptr); - - // Populate "maps" with the N most relevant Reflection Maps where N is no more than maps.size() - // If less than maps.size() ReflectionMaps are available, will assign trailing elements to nullptr. - // maps -- presized array of Reflection Map pointers - void getReflectionMaps(std::vector<LLReflectionMap*>& maps); - - // called by LLSpatialGroup constructor - // If spatial group should receive a Reflection Probe, will create one for the specified spatial group - LLReflectionMap* registerSpatialGroup(LLSpatialGroup* group); - - // presently hacked into LLViewerObject::setTE - // Used by LLViewerObjects that are Reflection Probes - // vobj must not be null - // Guaranteed to not return null - LLReflectionMap* registerViewerObject(LLViewerObject* vobj); - - // reset all state on the next update - void reset(); - - // called on region crossing to "shift" probes into new coordinate frame - void shift(const LLVector4a& offset); - // debug display, called from llspatialpartition if reflection // probe debug display is active void renderDebug(); @@ -94,28 +64,12 @@ public: // call once at startup to allocate cubemap arrays void initReflectionMaps(); - // 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; - - // initialize mCubeFree array to default values - void initCubeFree(); - - // delete the probe with the given index in mProbes - void deleteProbe(U32 i); - - // get a free cube index - // returns -1 if allocation failed - S32 allocateCubeIndex(); - - // update the neighbors of the given probe - void updateNeighbors(LLReflectionMap* probe); - + // update UBO used for rendering (call only once per render pipe flush) void updateUniforms(); @@ -132,8 +86,6 @@ private: // storage for reflection probe radiance maps (plus two scratch space cubemaps) LLPointer<LLCubeMapArray> mTexture; - - LLPointer<LLCubeMapArray> mHeroArray; // vertex buffer for pushing verts to filter shaders LLPointer<LLVertexBuffer> mVertexBuffer; @@ -141,61 +93,28 @@ private: // storage for reflection probe irradiance maps LLPointer<LLCubeMapArray> mIrradianceMaps; - // list of free cubemap indices - std::list<S32> mCubeFree; - - // perform an update on the currently updating Probe - void doProbeUpdate(); - // update the specified face of the specified probe - void updateProbeFace(LLReflectionMap* probe, U32 face, U32 probeResolution, LLPointer<LLCubeMapArray> cubeArray, std::vector<LLRenderTarget> &mipChain, U32 probeCount); + void updateProbeFace(LLReflectionMap* probe, U32 face); // list of active reflection maps std::vector<LLPointer<LLReflectionMap> > mProbes; - // list of reflection maps to kill - std::vector<LLPointer<LLReflectionMap> > mKillList; - - // list of reflection maps to create - std::vector<LLPointer<LLReflectionMap> > mCreateList; - // handle to UBO U32 mUBO = 0; - - // Hero UBO - U32 mHeroUBO = 0; // list of maps being used for rendering std::vector<LLReflectionMap*> mReflectionMaps; LLReflectionMap* mUpdatingProbe = nullptr; - U32 mUpdatingFace = 0; - - // if true, we're generating the radiance map for the current probe, otherwise we're generating the irradiance map. - // Update sequence should be to generate the irradiance map from render of the world that has no irradiance, - // then generate the radiance map from a render of the world that includes irradiance. - // This should avoid feedback loops and ensure that the colors in the radiance maps match the colors in the environment. - bool mRadiancePass = false; - - // same as above, but for the realtime probe. - // Realtime probes should update all six sides of the irradiance map on "odd" frames and all six sides of the - // radiance map on "even" frames. - bool mRealtimeRadiancePass = false; LLPointer<LLReflectionMap> mDefaultProbe; // default reflection probe to fall back to for pixels with no probe influences (should always be at cube index 0) - - LLPointer<LLReflectionMap> mHeroProbe; // number of reflection probes to use for rendering U32 mReflectionProbeCount; - - U32 mHeroProbeCount; // resolution of reflection probes U32 mProbeResolution = 128; - U32 mHeroProbeResolution = 512; - // maximum LoD of reflection probes (mip levels - 1) F32 mMaxProbeLOD = 6.f; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 909c0f9aaa..4c951a9dea 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -642,6 +642,7 @@ void LLPipeline::cleanup() mCubeVB = NULL; mReflectionMapManager.cleanup(); + mHeroProbeManager.cleanup(); } //============================================================================ @@ -772,6 +773,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) { // hacky -- allocate auxillary buffer gCubeSnapshot = TRUE; mReflectionMapManager.initReflectionMaps(); + mHeroProbeManager.initReflectionMaps(); mRT = &mAuxillaryRT; U32 res = mReflectionMapManager.mProbeResolution * 4; //multiply by 4 because probes will be 16x super sampled allocateScreenBuffer(res, res, samples); @@ -2441,6 +2443,26 @@ void LLPipeline::doOcclusion(LLCamera& camera) gGL.setColorMask(true, true); } + + 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(); + + mHeroProbeManager.doOcclusion(); + gOcclusionCubeProgram.unbind(); + + gGL.setColorMask(true, true); + } if (LLPipeline::sUseOcclusion > 1 && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck)) @@ -3809,6 +3831,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) { //update reflection probe uniform mReflectionMapManager.updateUniforms(); + mHeroProbeManager.updateUniforms(); } U32 cur_type = 0; @@ -8461,14 +8484,14 @@ void LLPipeline::bindReflectionProbes(LLGLSLShader& shader) mReflectionMapManager.mIrradianceMaps->bind(channel); bound = true; } - /* + channel = shader.enableTexture(LLShaderMgr::HERO_PROBE, LLTexUnit::TT_CUBE_MAP_ARRAY); - if (channel > -1 && mReflectionMapManager.mHeroArray.notNull()) + if (channel > -1 && mHeroProbeManager.mTexture.notNull()) { - mReflectionMapManager.mHeroArray->bind(channel); + mHeroProbeManager.mTexture->bind(channel); bound = true; } - */ + if (bound) { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index f3b35e0325..bfb9b95f4d 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -39,6 +39,7 @@ #include "lldrawable.h" #include "llrendertarget.h" #include "llreflectionmapmanager.h" +#include "llheroprobemanager.h" #include <stack> @@ -454,6 +455,7 @@ public: void handleShadowDetailChanged(); LLReflectionMapManager mReflectionMapManager; + LLHeroProbeManager mHeroProbeManager; private: void unloadShaders(); |