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"
#include "llviewermenufile.h"
#include "llnotificationsutil.h"
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4702) // compiler complains unreachable code
#endif
#define TINYEXR_USE_MINIZ 0
#include "zlib.h"
#define TINYEXR_IMPLEMENTATION
#include "tinyexr/tinyexr.h"
LLPointer<LLImageGL> gEXRImage;
void load_exr(const std::string& filename)
{
// reset reflection maps when previewing a new HDRI
gPipeline.mReflectionMapManager.reset();
gPipeline.mReflectionMapManager.initReflectionMaps();
float* out; // width * height * RGBA
int width;
int height;
const char* err = NULL; // or nullptr in C++11
int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err);
U32 texName = 0;
LLImageGL::generateTextures(1, &texName);
gEXRImage = new LLImageGL(texName, 4, GL_TEXTURE_2D, GL_RGB16F, GL_RGB16F, GL_FLOAT, LLTexUnit::TAM_CLAMP);
gEXRImage->setHasMipMaps(TRUE);
gEXRImage->setUseMipMaps(TRUE);
gEXRImage->setFilteringOption(LLTexUnit::TFO_TRILINEAR);
gGL.getTexUnit(0)->bind(gEXRImage);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGBA, GL_FLOAT, out);
glGenerateMipmap(GL_TEXTURE_2D);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
{
LLSD notif_args;
notif_args["WHAT"] = filename;
notif_args["REASON"] = "Unknown";
notif_args["REASON"] = std::string(err);
FreeEXRErrorMessage(err); // release memory of error message.
}
LLNotificationsUtil::add("CannotLoad", notif_args);
}
}
void hdri_preview()
{
LLFilePickerReplyThread::startPicker(
[](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
{
if (LLAppViewer::instance()->quitRequested())
{
return;
}
if (filenames.size() > 0)
{
load_exr(filenames[0]);
}
},
LLFilePicker::FFLOAD_HDRI,
true);
}
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;
Loading
Loading full blame...