Merge pull request #891 from secondlife/geenz/mirrors-optimization-pass-1
#682 First mirrors optimization passmaster
commit
7d1e3e08fc
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue