phoenix-firestorm/indra/llmath/llvolumemgr.cpp

296 lines
6.1 KiB
C++

/**
* @file llvolumemgr.cpp
*
* Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
* $License$
*/
#include "linden_common.h"
#include "llvolumemgr.h"
#include "llvolume.h"
//#define DEBUG_VOLUME
LLVolumeMgr* gVolumeMgr = 0;
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};
//============================================================================
//static
void LLVolumeMgr::initClass()
{
gVolumeMgr = new LLVolumeMgr();
}
//static
BOOL LLVolumeMgr::cleanupClass()
{
BOOL res = FALSE;
if (gVolumeMgr) {
res = gVolumeMgr->cleanup();
delete gVolumeMgr;
gVolumeMgr = 0;
}
return res;
}
//============================================================================
LLVolumeMgr::LLVolumeMgr()
{
mDataMutex = new LLMutex(gAPRPoolp);
// mNumVolumes = 0;
}
LLVolumeMgr::~LLVolumeMgr()
{
cleanup();
delete mDataMutex;
}
BOOL LLVolumeMgr::cleanup()
{
#ifdef DEBUG_VOLUME
{
lldebugs << "LLVolumeMgr::cleanup()" << llendl;
}
#endif
BOOL no_refs = TRUE;
mDataMutex->lock();
for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
end = mVolumeLODGroups.end();
iter != end; iter++)
{
LLVolumeLODGroup *volgroupp = iter->second;
if (volgroupp->getNumRefs() != 1)
{
llwarns << "Volume group " << volgroupp << " has "
<< volgroupp->getNumRefs() << " remaining refs" << llendl;
llwarns << volgroupp->getParams() << llendl;
no_refs = FALSE;
}
volgroupp->unref();// this );
}
mVolumeLODGroups.clear();
mDataMutex->unlock();
return no_refs;
}
LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32 detail)
{
LLVolumeLODGroup* volgroupp;
mDataMutex->lock();
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
if( iter == mVolumeLODGroups.end() )
{
volgroupp = new LLVolumeLODGroup(volume_params);
const LLVolumeParams* params = &(volgroupp->getParams());
mVolumeLODGroups[params] = volgroupp;
volgroupp->ref(); // initial reference
}
else
{
volgroupp = iter->second;
}
volgroupp->ref();// this );
mDataMutex->unlock();
// mNumVolumes++;
#ifdef DEBUG_VOLUME
{
lldebugs << "LLVolumeMgr::getVolume() " << (*this) << llendl;
}
#endif
return volgroupp->getLOD(detail);
}
void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
{
if (volumep->isUnique())
{
// TomY: Don't need to manage this volume. It is a unique instance.
return;
}
LLVolumeParams* params = (LLVolumeParams*) &(volumep->getParams());
mDataMutex->lock();
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
if( iter == mVolumeLODGroups.end() )
{
llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
mDataMutex->unlock();
return;
}
else
{
LLVolumeLODGroup* volgroupp = iter->second;
volgroupp->derefLOD(volumep);
volgroupp->unref();// this );
if (volgroupp->getNumRefs() == 1)
{
mVolumeLODGroups.erase(params);
volgroupp->unref();// this );
}
// mNumVolumes--;
}
mDataMutex->unlock();
#ifdef DEBUG_VOLUME
{
lldebugs << "LLVolumeMgr::cleanupVolume() " << (*this) << llendl;
}
#endif
}
void LLVolumeMgr::dump()
{
F32 avg = 0.f;
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;
mDataMutex->unlock();
llinfos << "Average usage of LODs " << avg << llendl;
}
std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
{
s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
S32 total_refs = 0;
volume_mgr.mDataMutex->lock();
LLVolumeMgr::volume_lod_group_map_iter iter = volume_mgr.mVolumeLODGroups.begin();
LLVolumeMgr::volume_lod_group_map_iter end = volume_mgr.mVolumeLODGroups.end();
for ( ; iter != end; ++iter)
{
LLVolumeLODGroup *volgroupp = iter->second;
total_refs += volgroupp->getNumRefs();
s << ", " << (*volgroupp);
}
volume_mgr.mDataMutex->unlock();
s << ", total_refs=" << total_refs << " }";
return s;
}
LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams &params)
{
S32 i;
mParams = params;
for (i = 0; i < NUM_LODS; i++)
{
mLODRefs[i] = 0;
mVolumeLODs[i] = NULL;
mAccessCount[i] = 0;
}
}
LLVolumeLODGroup::~LLVolumeLODGroup()
{
S32 i;
for (i = 0; i < NUM_LODS; i++)
{
delete mVolumeLODs[i];
mVolumeLODs[i] = NULL;
}
}
LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)
{
llassert(detail >=0 && detail < NUM_LODS);
mAccessCount[detail]++;
mLODRefs[detail]++;
if (!mVolumeLODs[detail])
{
mVolumeLODs[detail] = new LLVolume(mParams, mDetailScales[detail]);
}
return mVolumeLODs[detail];
}
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
{
S32 i;
for (i = 0; i < NUM_LODS; i++)
{
if (mVolumeLODs[i] == volumep)
{
mLODRefs[i]--;
if (!mLODRefs[i])
{
mVolumeLODs[i] = NULL;
}
return TRUE;
}
}
llerrs << "Deref of non-matching LOD in volume LOD group" << llendl;
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;
}
F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
{
return mDetailScales[detail];
}
F32 LLVolumeLODGroup::dump()
{
char dump_str[255]; /* Flawfinder: ignore */
F32 usage = 0.f;
for (S32 i = 0; i < NUM_LODS; i++)
{
if (mAccessCount[i] > 0)
{
usage += 1.f;
}
}
usage = usage / (F32)NUM_LODS;
snprintf(dump_str, sizeof(dump_str), "%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]); /* Flawfinder: ignore */
llinfos << dump_str << llendl;
return usage;
}
std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
{
s << "{ numRefs=" << volgroup.getNumRefs();
s << ", mParams=" << volgroup.mParams;
s << " }";
return s;
}