Files
SingularityViewer/indra/llmath/llvolumemgr.cpp
2016-04-06 01:56:39 -05:00

409 lines
8.4 KiB
C++

/**
* @file llvolumemgr.cpp
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llvolumemgr.h"
#include "llvolume.h"
const F32 BASE_THRESHOLD = 0.03f;
//static
F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
2*BASE_THRESHOLD,
8*BASE_THRESHOLD,
100*BASE_THRESHOLD};
//static
F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
//============================================================================
LLVolumeMgr::LLVolumeMgr()
: mDataMutex(NULL)
{
// the LLMutex magic interferes with easy unit testing,
// so you now must manually call useMutex() to use it
//mDataMutex = new LLMutex;
}
LLVolumeMgr::~LLVolumeMgr()
{
cleanup();
delete mDataMutex;
mDataMutex = NULL;
}
BOOL LLVolumeMgr::cleanup()
{
BOOL no_refs = TRUE;
if (mDataMutex)
{
mDataMutex->lock();
}
for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
end = mVolumeLODGroups.end();
iter != end; iter++)
{
LLVolumeLODGroup *volgroupp = iter->second;
if (volgroupp->cleanupRefs() == false)
{
no_refs = FALSE;
}
delete volgroupp;
}
mVolumeLODGroups.clear();
if (mDataMutex)
{
mDataMutex->unlock();
}
return no_refs;
}
// Always only ever store the results of refVolume in a LLPointer
// Note however that LLVolumeLODGroup that contains the volume
// also holds a LLPointer so the volume will only go away after
// anything holding the volume and the LODGroup are destroyed
LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
{
LLVolumeLODGroup* volgroupp;
if (mDataMutex)
{
mDataMutex->lock();
}
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
if( iter == mVolumeLODGroups.end() )
{
volgroupp = createNewGroup(volume_params);
}
else
{
volgroupp = iter->second;
}
if (mDataMutex)
{
mDataMutex->unlock();
}
return volgroupp->refLOD(detail);
}
// virtual
LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const
{
LLVolumeLODGroup* volgroupp = NULL;
if (mDataMutex)
{
mDataMutex->lock();
}
volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
if( iter != mVolumeLODGroups.end() )
{
volgroupp = iter->second;
}
if (mDataMutex)
{
mDataMutex->unlock();
}
return volgroupp;
}
void LLVolumeMgr::unrefVolume(LLVolume *volumep)
{
if (volumep->isUnique())
{
// TomY: Don't need to manage this volume. It is a unique instance.
return;
}
const LLVolumeParams* params = &(volumep->getParams());
if (mDataMutex)
{
mDataMutex->lock();
}
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
if( iter == mVolumeLODGroups.end() )
{
LL_ERRS() << "Warning! Tried to cleanup unknown volume type! " << *params << LL_ENDL;
if (mDataMutex)
{
mDataMutex->unlock();
}
return;
}
else
{
LLVolumeLODGroup* volgroupp = iter->second;
volgroupp->derefLOD(volumep);
if (volgroupp->getNumRefs() == 0)
{
mVolumeLODGroups.erase(params);
delete volgroupp;
}
}
if (mDataMutex)
{
mDataMutex->unlock();
}
}
// protected
void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup)
{
mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup;
}
// protected
LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
{
LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params);
insertGroup(volgroup);
return volgroup;
}
// virtual
void LLVolumeMgr::dump()
{
F32 avg = 0.f;
if (mDataMutex)
{
mDataMutex->lock();
}
for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
end = mVolumeLODGroups.end();
iter != end; iter++)
{
LLVolumeLODGroup *volgroupp = iter->second;
avg += volgroupp->dump();
}
int count = (int)mVolumeLODGroups.size();
avg = count ? avg / (F32)count : 0.0f;
if (mDataMutex)
{
mDataMutex->unlock();
}
LL_INFOS() << "Average usage of LODs " << avg << LL_ENDL;
}
void LLVolumeMgr::useMutex()
{
if (!mDataMutex)
{
mDataMutex = new LLMutex();
}
}
std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
{
s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
S32 total_refs = 0;
if (volume_mgr.mDataMutex)
{
volume_mgr.mDataMutex->lock();
}
for (LLVolumeMgr::volume_lod_group_map_t::const_iterator iter = volume_mgr.mVolumeLODGroups.begin();
iter != volume_mgr.mVolumeLODGroups.end(); ++iter)
{
LLVolumeLODGroup *volgroupp = iter->second;
total_refs += volgroupp->getNumRefs();
s << ", " << (*volgroupp);
}
if (volume_mgr.mDataMutex)
{
volume_mgr.mDataMutex->unlock();
}
s << ", total_refs=" << total_refs << " }";
return s;
}
LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams &params)
: mVolumeParams(params),
mRefs(0)
{
for (S32 i = 0; i < NUM_LODS; i++)
{
mLODRefs[i] = 0;
mAccessCount[i] = 0;
}
}
LLVolumeLODGroup::~LLVolumeLODGroup()
{
for (S32 i = 0; i < NUM_LODS; i++)
{
llassert_always(mLODRefs[i] == 0);
}
}
// Called from LLVolumeMgr::cleanup
bool LLVolumeLODGroup::cleanupRefs()
{
bool res = true;
if (mRefs != 0)
{
LL_WARNS() << "Volume group has remaining refs:" << getNumRefs() << LL_ENDL;
mRefs = 0;
for (S32 i = 0; i < NUM_LODS; i++)
{
if (mLODRefs[i] > 0)
{
LL_WARNS() << " LOD " << i << " refs = " << mLODRefs[i] << LL_ENDL;
mLODRefs[i] = 0;
mVolumeLODs[i] = NULL;
}
}
LL_WARNS() << *getVolumeParams() << LL_ENDL;
res = false;
}
return res;
}
LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
{
llassert(detail >=0 && detail < NUM_LODS);
mAccessCount[detail]++;
mRefs++;
if (mVolumeLODs[detail].isNull())
{
mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
}
mLODRefs[detail]++;
return mVolumeLODs[detail];
}
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
{
llassert_always(mRefs > 0);
mRefs--;
for (S32 i = 0; i < NUM_LODS; i++)
{
if (mVolumeLODs[i] == volumep)
{
llassert_always(mLODRefs[i] > 0);
mLODRefs[i]--;
#if 0 // SJB: Possible opt: keep other lods around
if (!mLODRefs[i])
{
mVolumeLODs[i] = NULL;
}
#endif
return TRUE;
}
}
LL_ERRS() << "Deref of non-matching LOD in volume LOD group" << LL_ENDL;
return FALSE;
}
S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
{
S32 i = 0;
while (i < (NUM_LODS - 1))
{
if (tan_angle <= mDetailThresholds[i])
{
return i;
}
i++;
}
return NUM_LODS - 1;
}
void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher)
{
S32 detail = getDetailFromTan(tan_angle);
if (detail > 0)
{
to_lower = tan_angle - mDetailThresholds[detail];
}
else
{
to_lower = 1024.f*1024.f;
}
if (detail < NUM_LODS-1)
{
to_higher = mDetailThresholds[detail+1] - tan_angle;
}
else
{
to_higher = 1024.f*1024.f;
}
}
F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
{
return mDetailScales[detail];
}
S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
{
for (S32 i = 1; i < 4; i++)
{
if (mDetailScales[i] > detail)
{
return i-1;
}
}
return 3;
}
F32 LLVolumeLODGroup::dump()
{
F32 usage = 0.f;
for (S32 i = 0; i < NUM_LODS; i++)
{
if (mAccessCount[i] > 0)
{
usage += 1.f;
}
}
usage = usage / (F32)NUM_LODS;
std::string dump_str = llformat("%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]);
LL_INFOS() << dump_str << LL_ENDL;
return usage;
}
std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
{
s << "{ numRefs=" << volgroup.getNumRefs();
s << ", mParams=" << volgroup.getVolumeParams();
s << " }";
return s;
}