Files
SingularityViewer/indra/llmath/llvolumemgr.cpp

405 lines
8.7 KiB
C++

/**
* @file llvolumemgr.cpp
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llvolumemgr.h"
#include "llmemtype.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() )
{
llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
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)
{
LLMemType m1(LLMemType::MTYPE_VOLUME);
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();
}
llinfos << "Average usage of LODs " << avg << llendl;
}
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)
{
llwarns << "Volume group has remaining refs:" << getNumRefs() << llendl;
mRefs = 0;
for (S32 i = 0; i < NUM_LODS; i++)
{
if (mLODRefs[i] > 0)
{
llwarns << " LOD " << i << " refs = " << mLODRefs[i] << llendl;
mLODRefs[i] = 0;
mVolumeLODs[i] = NULL;
}
}
llwarns << *getVolumeParams() << llendl;
res = false;
}
return res;
}
LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
{
llassert(detail >=0 && detail < NUM_LODS);
mAccessCount[detail]++;
mRefs++;
if (mVolumeLODs[detail].isNull())
{
LLMemType m1(LLMemType::MTYPE_VOLUME);
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 1 // SJB: Possible opt: keep other lods around
if (!mLODRefs[i])
{
mVolumeLODs[i] = NULL;
}
#endif
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;
}
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];
}
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]);
llinfos << dump_str << llendl;
return usage;
}
std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
{
s << "{ numRefs=" << volgroup.getNumRefs();
s << ", mParams=" << volgroup.getVolumeParams();
s << " }";
return s;
}