Newer
Older
/**
* @file llreflectionmapmanager.cpp
* @brief LLReflectionMapManager class implementation
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llreflectionmapmanager.h"
#include "llviewercamera.h"
#include "llspatialpartition.h"
#include "llviewerregion.h"
#include "pipeline.h"
#include "llviewershadermgr.h"
#include "llviewercontrol.h"
#include "llenvironment.h"
David Parks
committed
#include "llstartup.h"
extern BOOL gCubeSnapshot;
extern BOOL gTeleportDisplay;
static U32 sUpdateCount = 0;
David Parks
committed
// get the next highest power of two of v (or v if v is already a power of two)
//defined in llvertexbuffer.cpp
extern U32 nhpo2(U32 v);
David Parks
committed
static void touch_default_probe(LLReflectionMap* probe)
{
David Parks
committed
if (LLViewerCamera::getInstance())
{
LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
origin.mV[2] += 64.f;
David Parks
committed
David Parks
committed
probe->mOrigin.load3(origin.mV);
}
David Parks
committed
}
LLReflectionMapManager::LLReflectionMapManager()
{
initCubeFree();
}
void LLReflectionMapManager::initCubeFree()
{
David Parks
committed
// start at 1 because index 0 is reserved for mDefaultProbe
David Parks
committed
for (int i = 1; i < LL_MAX_REFLECTION_PROBE_COUNT; ++i)
David Parks
committed
mCubeFree.push_back(i);
}
struct CompareProbeDistance
{
David Parks
committed
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)
{
David Parks
committed
if (a->mCubeIndex == -1)
{ // not a candidate for updating
return false;
}
else if (b->mCubeIndex == -1)
{ // b is not a candidate for updating, a is higher priority by default
David Parks
committed
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);
// a or b is not complete,
if (sUpdateCount % 3 == 0)
{ // every third update, allow complete probes to cut in line in front of non-complete probes to avoid spammy probe generators from deadlocking scheduler (SL-20258))
return !b->mComplete;
}
// prioritize incomplete probe
return b->mComplete;
}
// helper class to seed octree with probes
void LLReflectionMapManager::update()
{
David Parks
committed
if (!LLPipeline::sReflectionProbesEnabled || gTeleportDisplay || LLStartUp::getStartupState() < STATE_PRECACHE)
{
return;
}
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
llassert(!gCubeSnapshot); // assert a snapshot is not in progress
if (LLAppViewer::instance()->logoutRequestSent())
{
return;
}
initReflectionMaps();
David Parks
committed
llassert(mProbes[0] == mDefaultProbe);
David Parks
committed
LLVector4a camera_pos;
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
// process kill list
David Parks
committed
for (auto& probe : mKillList)
{
Brad Kittenbrink
committed
auto const & iter = std::find(mProbes.begin(), mProbes.end(), probe);
David Parks
committed
if (iter != mProbes.end())
David Parks
committed
deleteProbe(iter - mProbes.begin());
}
mKillList.clear();
// process create list
for (auto& probe : mCreateList)
{
mProbes.push_back(probe);
}
mCreateList.clear();
if (mProbes.empty())
{
return;
}
David Parks
committed
bool did_update = false;
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
David Parks
committed
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME;
LLReflectionMap* closestDynamic = nullptr;
LLReflectionMap* oldestProbe = nullptr;
David Parks
committed
LLReflectionMap* oldestOccluded = nullptr;
if (mUpdatingProbe != nullptr)
{
did_update = true;
doProbeUpdate();
}
David Parks
committed
// 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
// 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);
Loading
Loading full blame...