diff options
| author | Jonathan "Geenz" Goodman <geenz@lindenlab.com> | 2024-02-27 11:09:38 -0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-27 11:09:38 -0800 | 
| commit | 7d1e3e08fcfbb3801edde3b6d248080055cd0a75 (patch) | |
| tree | 6f7bdf27cf2a42b424ad7e821ae963432a4a4f89 /indra | |
| parent | 95e1badaa4566bea41479623bf5b5112f7184cd5 (diff) | |
| parent | ae9d3e719a0cdb7af5dc470369df6fadd3e04b49 (diff) | |
Merge pull request #891 from secondlife/geenz/mirrors-optimization-pass-1
#682  First mirrors optimization pass
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 22 | ||||
| -rw-r--r-- | indra/newview/llheroprobemanager.cpp | 95 | ||||
| -rw-r--r-- | indra/newview/llheroprobemanager.h | 12 | ||||
| -rw-r--r-- | indra/newview/llviewerdisplay.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 1 | ||||
| -rw-r--r-- | indra/newview/llvovolume.cpp | 9 | ||||
| -rw-r--r-- | indra/newview/pipeline.cpp | 16 | ||||
| -rw-r--r-- | indra/newview/pipeline.h | 2 | 
8 files changed, 123 insertions, 36 deletions
| diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e7d947b85f..e707e1eb5e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10390,6 +10390,28 @@  		<key>Value</key>  		<real>8</real>  	</map> +  <key>RenderHeroProbeUpdateRate</key> +  <map> +    <key>Comment</key> +    <string>How many frames to wait for until it's time to render the probe. E.g., every other frame (1), every two frames (2), every three frames (3) etc.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>S32</string> +    <key>Value</key> +    <integer>2</integer> +  </map> +  <key>RenderHeroProbeConservativeUpdateMultiplier</key> +  <map> +    <key>Comment</key> +    <string>How many probe updates to wait until it's time to update faces that are not directly facing the camera.  Acts as a multiplier.  E.g., frames to the periphery of the camera updating once every 3 updates, vs ones directly facing the camera updating every update.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>S32</string> +    <key>Value</key> +    <integer>16</integer> +  </map>      <key>RenderReflectionProbeVolumes</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index 2a81919856..a00b6d6b5d 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -114,20 +114,13 @@ void LLHeroProbeManager::update()          for (auto vo : mHeroVOList)          { -            if (vo && !vo->isDead()) +            if (vo && !vo->isDead() && vo->mDrawable.notNull())              { -                if (vo->mDrawable.notNull()) +                float distance = (LLViewerCamera::instance().getOrigin() - vo->getPositionAgent()).magVec(); +                if (distance < last_distance)                  { -                    if (vo->mDrawable->mDistanceWRTCamera < last_distance) -                    { -                        mNearestHero = vo; -                        last_distance = vo->mDrawable->mDistanceWRTCamera; -                    } -                } -                else -                { -                    // Valid drawables only please.  Unregister this one. -                    unregisterViewerObject(vo); +                    mNearestHero = vo; +                    last_distance = distance;                  }              }              else @@ -135,13 +128,13 @@ void LLHeroProbeManager::update()                  unregisterViewerObject(vo);              }          } - +                  if (mNearestHero != nullptr && !mNearestHero->isDead() && mNearestHero->mDrawable.notNull())          {              LLVector3 hero_pos = mNearestHero->getPositionAgent();              LLVector3 face_normal = LLVector3(0, 0, 1); - -            face_normal *= mNearestHero->mDrawable->getXform()->getWorldRotation(); +             +            face_normal *= mNearestHero->mDrawable->getWorldRotation();              face_normal.normalize();              LLVector3 offset = camera_pos - hero_pos; @@ -155,6 +148,32 @@ void LLHeroProbeManager::update()              probe_pos.load3(point.mV); + +            // Collect the list of faces that need updating based upon the camera's rotation. +            LLVector3 cam_direction = LLVector3(0, 0, 1) * LLViewerCamera::instance().getQuaternion(); + +            static LLVector3 cubeFaces[6] = {  +                LLVector3(1, 0, 0),  +                LLVector3(-1, 0, 0), +                LLVector3(0, 1, 0), +                LLVector3(0, -1, 0), +                LLVector3(0, 0, 1), +                LLVector3(0, 0, -1) +            }; + +            for (int i = 0; i < 6; i++) +            { +                float shouldUpdate = cam_direction * cubeFaces[i] * 0.5 + 0.5; +                 +                int updateRate = ceilf((1 - shouldUpdate) * gPipeline.RenderHeroProbeConservativeUpdateMultiplier); +                 +                // Chances are this is a face that's non-visible to the camera when it's being reflected. +                // Set it to 0.  It will be skipped below. +                if (updateRate == gPipeline.RenderHeroProbeConservativeUpdateMultiplier) +                    updateRate = 0; +                 +                mFaceUpdateList[i] = updateRate; +            }          }          else          {  @@ -185,13 +204,20 @@ void LLHeroProbeManager::update()          {              for (U32 i = 0; i < 6; ++i)              { -                updateProbeFace(mProbes[j], i, near_clip); +                if (mFaceUpdateList[i] > 0 && mCurrentProbeUpdateFrame % mFaceUpdateList[i] == 0) +                { +                    updateProbeFace(mProbes[j], i, near_clip); +                    mCurrentProbeUpdateFrame = 0; +                }              } +            generateRadiance(mProbes[j]);          }          mRenderingMirror = false;          gPipeline.mReflectionMapManager.mRadiancePass = radiance_pass;      } +     +    mCurrentProbeUpdateFrame++;  }  // Do the reflection map update render passes. @@ -242,7 +268,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, F32 n          LLRenderTarget *screen_rt = &gPipeline.mHeroProbeRT.screen;          LLRenderTarget *depth_rt  = &gPipeline.mHeroProbeRT.deferredScreen; -         +          // perform a gaussian blur on the super sampled render before downsampling          {              gGaussianProgram.bind(); @@ -318,14 +344,25 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, F32 n          gGL.getTexUnit(diffuseChannel)->unbind(LLTexUnit::TT_TEXTURE);          gReflectionMipProgram.unbind();      } +} -    if (face == 5) +// Separate out radiance generation as a separate stage. +// This is to better enable independent control over how we generate radiance vs. having it coupled with processing the final face of the probe. +// Useful when we may not always be rendering a full set of faces of the probe. +void LLHeroProbeManager::generateRadiance(LLReflectionMap* probe) +{ +    S32 sourceIdx = mReflectionProbeCount; + +    // Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes. +    sourceIdx += 1;      {          mMipChain[0].bindTarget();          static LLStaticHashedString sSourceIdx("sourceIdx");          { -            //generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map) + + +            // generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map)              gHeroRadianceGenProgram.bind();              mVertexBuffer->setBuffer(); @@ -334,10 +371,10 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, F32 n              gHeroRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);              gHeroRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);              gHeroRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, mHeroProbeStrength); -             +              U32 res = mMipChain[0].getWidth(); -            for (int i = 0; i < mMipChain.size(); ++i) +            for (int i = 0; i < mMipChain.size() / 4; ++i)              {                  LL_PROFILE_GPU_ZONE("probe radiance gen");                  static LLStaticHashedString sMipLevel("mipLevel"); @@ -351,7 +388,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, F32 n                  gHeroRadianceGenProgram.uniform1f(sStrength, 1);                  for (int cf = 0; cf < 6; ++cf) -                { // for each cube face +                {  // for each cube face                      LLCoordFrame frame;                      frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); @@ -539,21 +576,25 @@ void LLHeroProbeManager::doOcclusion()      }  } -void LLHeroProbeManager::registerViewerObject(LLVOVolume* drawablep) +bool LLHeroProbeManager::registerViewerObject(LLVOVolume* drawablep)  {      llassert(drawablep != nullptr); -    if (mHeroVOList.find(drawablep) == mHeroVOList.end()) +    if (std::find(mHeroVOList.begin(), mHeroVOList.end(), drawablep) == mHeroVOList.end())      {          // Probe isn't in our list for consideration.  Add it. -        mHeroVOList.insert(drawablep); +        mHeroVOList.push_back(drawablep); +        return true;      } +     +    return false;  }  void LLHeroProbeManager::unregisterViewerObject(LLVOVolume* drawablep)  { -    if (mHeroVOList.find(drawablep) != mHeroVOList.end()) +    std::vector<LLVOVolume*>::iterator found_itr = std::find(mHeroVOList.begin(), mHeroVOList.end(), drawablep); +    if (found_itr != mHeroVOList.end())      { -        mHeroVOList.erase(drawablep); +        mHeroVOList.erase(found_itr);      }  } diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h index 552c5dcaab..e430cae203 100644 --- a/indra/newview/llheroprobemanager.h +++ b/indra/newview/llheroprobemanager.h @@ -68,7 +68,7 @@ public:      // perform occlusion culling on all active reflection probes      void doOcclusion(); -    void registerViewerObject(LLVOVolume *drawablep); +    bool registerViewerObject(LLVOVolume *drawablep);      void unregisterViewerObject(LLVOVolume* drawablep);      bool isMirrorPass() const { return mRenderingMirror; } @@ -104,9 +104,10 @@ private:      // update the specified face of the specified probe      void updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip); +    void generateRadiance(LLReflectionMap *probe);      // list of active reflection maps -    std::vector<LLPointer<LLReflectionMap> > mProbes; +    std::vector<LLPointer<LLReflectionMap>> mProbes;      // handle to UBO      U32 mUBO = 0; @@ -134,8 +135,11 @@ private:      bool mReset = false;      bool mRenderingMirror = false; +    std::map<int, int> mFaceUpdateList; -    std::set<LLPointer<LLVOVolume>>               mHeroVOList; -    LLPointer<LLVOVolume>                         mNearestHero; +    U32 mCurrentProbeUpdateFrame = 0; +     +    std::vector<LLVOVolume*>                       mHeroVOList; +    LLVOVolume*                                 mNearestHero;  }; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index e6d9aed1a3..2a77146101 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -658,7 +658,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)  	{  		// Render mirrors and associated hero probes before we render the rest of the scene.  		// This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it. -        if (gPipeline.RenderMirrors && !gSnapshot) +        if (gPipeline.RenderMirrors && !gSnapshot && (gPipeline.RenderHeroProbeUpdateRate == 0 || (gFrameCount % gPipeline.RenderHeroProbeUpdateRate) == 0))          {              LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes");              gPipeline.mHeroProbeManager.update(); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 80da7b2f73..0c4d958aed 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -944,6 +944,7 @@ public:      // reflection probe state      bool mIsReflectionProbe = false;  // if true, this object should register itself with LLReflectionProbeManager      LLPointer<LLReflectionMap> mReflectionProbe = nullptr; // reflection probe coupled to this viewer object.  If not null, should be deregistered when this object is destroyed +    bool mIsHeroProbe = false; // This is a special case for mirrors and other high resolution probes.      // the amount of GPU time (in ms) it took to render this object according to LLPipeline::profileAvatar      // -1.f if no profile data available diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 27d2e6af71..d7af7a42d1 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -296,6 +296,11 @@ void LLVOVolume::markDead()  		{  			mLightTexture->removeVolume(LLRender::LIGHT_TEX, this);  		} +         +        if (mIsHeroProbe) +        { +            gPipeline.mHeroProbeManager.unregisterViewerObject(this); +        }  	}  	LLViewerObject::markDead(); @@ -4411,7 +4416,9 @@ void LLVOVolume::updateReflectionProbePtr()  		{  			// Geenz: This is a special case - what we want here is a hero probe.  			// What we want to do here is instantiate a hero probe from the hero probe manager. -            gPipeline.mHeroProbeManager.registerViewerObject(this); +             +            if (!mIsHeroProbe) +                mIsHeroProbe = gPipeline.mHeroProbeManager.registerViewerObject(this);  		}      }      else if (mReflectionProbe.notNull() || getReflectionProbeIsMirror()) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 6ceaca731b..94ec5c0817 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -199,6 +199,8 @@ F32 LLPipeline::RenderScreenSpaceReflectionAdaptiveStepMultiplier;  S32 LLPipeline::RenderScreenSpaceReflectionGlossySamples;  S32 LLPipeline::RenderBufferVisualization;  bool LLPipeline::RenderMirrors; +S32 LLPipeline::RenderHeroProbeUpdateRate; +S32 LLPipeline::RenderHeroProbeConservativeUpdateMultiplier;  LLTrace::EventStatHandle<S64> LLPipeline::sStatBatchSize("renderbatchsize");  const U32 LLPipeline::MAX_BAKE_WIDTH = 512; @@ -559,6 +561,8 @@ void LLPipeline::init()      connectRefreshCachedSettingsSafe("RenderScreenSpaceReflectionGlossySamples");  	connectRefreshCachedSettingsSafe("RenderBufferVisualization");      connectRefreshCachedSettingsSafe("RenderMirrors"); +    connectRefreshCachedSettingsSafe("RenderHeroProbeUpdateRate"); +    connectRefreshCachedSettingsSafe("RenderHeroProbeConservativeUpdateMultiplier");  	gSavedSettings.getControl("RenderAutoHideSurfaceAreaLimit")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings));  } @@ -786,9 +790,12 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)          U32 res = mReflectionMapManager.mProbeResolution * 4;  //multiply by 4 because probes will be 16x super sampled          allocateScreenBuffer(res, res, samples); -		res = mHeroProbeManager.mProbeResolution; // We also scale the hero probe RT to the probe res since we don't super sample it. -        mRT = &mHeroProbeRT; -        allocateScreenBuffer(res, res, samples); +		if (RenderMirrors) +        { +            res = mHeroProbeManager.mProbeResolution;  // We also scale the hero probe RT to the probe res since we don't super sample it. +            mRT = &mHeroProbeRT; +            allocateScreenBuffer(res, res, samples); +        }          mRT = &mMainRT;          gCubeSnapshot = FALSE; @@ -1068,6 +1075,9 @@ void LLPipeline::refreshCachedSettings()          LLViewerShaderMgr::instance()->clearShaderCache();          LLViewerShaderMgr::instance()->setShaders();      } +    RenderHeroProbeUpdateRate = gSavedSettings.getS32("RenderHeroProbeUpdateRate"); +    RenderHeroProbeConservativeUpdateMultiplier = gSavedSettings.getS32("RenderHeroProbeConservativeUpdateMultiplier"); +      sReflectionProbesEnabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionsEnabled") && gSavedSettings.getBOOL("RenderReflectionsEnabled");  	RenderSpotLight = nullptr; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 259dc3f9d0..817750b4a1 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -1056,6 +1056,8 @@ public:  	static S32 RenderScreenSpaceReflectionGlossySamples;  	static S32 RenderBufferVisualization;  	static bool RenderMirrors; +	static S32 RenderHeroProbeUpdateRate; +    static S32 RenderHeroProbeConservativeUpdateMultiplier;  };  void render_bbox(const LLVector3 &min, const LLVector3 &max); | 
