123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- /**
- * @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 "llvolume.h"
- constexpr F32 BASE_THRESHOLD = 0.03f;
- LLVolumeMgr* gVolumeMgrp = NULL;
- // Static members
- F32 LLVolumeLODGroup::sDetailThresholds[NUM_LODS] = { BASE_THRESHOLD,
- 2 * BASE_THRESHOLD,
- 8 * BASE_THRESHOLD,
- 100 * BASE_THRESHOLD };
- F32 LLVolumeLODGroup::sDetailScales[NUM_LODS] = { 1.f, 1.5f, 2.5f, 4.f };
- //static
- void LLVolumeMgr::initClass()
- {
- if (gVolumeMgrp)
- {
- llerrs << "A volume manager already exists !" << llendl;
- }
- gVolumeMgrp = new LLVolumeMgr;
- }
- //static
- void LLVolumeMgr::cleanupClass()
- {
- if (gVolumeMgrp)
- {
- delete gVolumeMgrp;
- gVolumeMgrp = NULL;
- llinfos << "Volume manager destroyed." << llendl;
- }
- }
- LLVolumeMgr::~LLVolumeMgr()
- {
- U32 remaining = 0;
- 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)
- {
- ++remaining;
- }
- delete volgroupp;
- }
- mVolumeLODGroups.clear();
- mDataMutex.unlock();
- if (remaining)
- {
- llwarns << "There were " << remaining
- << " remaining references in the volume manager." << llendl;
- }
- }
- // Always only ever store the results of refVolume in a LLPointer. Note however
- // that LLVolumeLODGroup which 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,
- S32 detail)
- {
- if (detail < 0 || detail >= LLVolumeLODGroup::NUM_LODS)
- {
- llwarns << "Attempt to reference a volume for out of range LOD: "
- << detail << llendl;
- return NULL;
- }
- mDataMutex.lock();
- volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
- LLVolumeLODGroup* volgroupp;
- if (iter == mVolumeLODGroups.end())
- {
- volgroupp = createNewGroup(volume_params);
- }
- else
- {
- volgroupp = iter->second;
- }
- mDataMutex.unlock();
- return volgroupp->refLOD(detail);
- }
- LLVolumeLODGroup* LLVolumeMgr::getGroup(const LLVolumeParams& volume_params)
- {
- LLVolumeLODGroup* volgroupp = NULL;
- mDataMutex.lock();
- volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
- if (iter != mVolumeLODGroups.end())
- {
- volgroupp = iter->second;
- }
- 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());
- mDataMutex.lock();
- volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
- if (iter == mVolumeLODGroups.end())
- {
- mDataMutex.unlock();
- llwarns << "Tried to cleanup unknown volume type ! " << *params
- << llendl;
- llassert(false);
- return;
- }
- else
- {
- LLVolumeLODGroup* volgroupp = iter->second;
- if (volgroupp)
- {
- volgroupp->derefLOD(volumep);
- if (volgroupp->getNumRefs() == 0)
- {
- mVolumeLODGroups.erase(params);
- delete volgroupp;
- }
- }
- else
- {
- llwarns << "Found a NULL volume LOD group !" << llendl;
- }
- }
- mDataMutex.unlock();
- }
- void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup)
- {
- mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup;
- }
- LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
- {
- LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params);
- insertGroup(volgroup);
- return volgroup;
- }
- 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();
- }
- S32 count = 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;
- // Cheating out const-ness...
- LLMutex* mutex = &const_cast<LLVolumeMgr&>(volume_mgr).mDataMutex;
- mutex->lock();
- for (LLVolumeMgr::volume_lod_group_map_t::const_iterator
- iter = volume_mgr.mVolumeLODGroups.begin(),
- end = volume_mgr.mVolumeLODGroups.end();
- iter != end; ++iter)
- {
- LLVolumeLODGroup* volgroupp = iter->second;
- total_refs += volgroupp->getNumRefs();
- s << ", " << (*volgroupp);
- }
- mutex->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(S32 detail)
- {
- if (detail < 0 || detail >= NUM_LODS)
- {
- llwarns << "Attempt to reference out of range LOD " << detail
- << " in volume group " << std::hex << this << std::dec
- << llendl;
- llassert(false);
- return NULL;
- }
- ++mAccessCount[detail];
- ++mRefs;
- if (mVolumeLODs[detail].isNull())
- {
- mVolumeLODs[detail] = new LLVolume(mVolumeParams,
- sDetailScales[detail]);
- }
- ++mLODRefs[detail];
- return mVolumeLODs[detail];
- }
- bool LLVolumeLODGroup::derefLOD(LLVolume* volumep)
- {
- if (mRefs > 0)
- {
- --mRefs;
- }
- else
- {
- llwarns << "Attempt to dereference a zero count volume: "
- << std::hex << volumep << std::dec << llendl;
- llassert(false);
- return false;
- }
- for (S32 i = 0; i < NUM_LODS; ++i)
- {
- if (mVolumeLODs[i] == volumep)
- {
- #if 0 // SJB: Possible opt: keep other LODs around
- if (!mLODRefs[i])
- {
- mVolumeLODs[i] = NULL;
- }
- else
- #endif
- if (mLODRefs[i] > 0)
- {
- --mLODRefs[i];
- }
- else
- {
- llwarns << "Unreferenced LOD (" << i << ") for volume: "
- << std::hex << volumep << std::dec << llendl;
- }
- return true;
- }
- }
- llwarns << "Attempt to dereference a non-matching LOD in volume LOD group for volume: "
- << std::hex << volumep << std::dec << llendl;
- return false;
- }
- S32 LLVolumeLODGroup::getDetailFromTan(F32 tan_angle)
- {
- for (S32 i = 0; i < NUM_LODS - 1; ++i)
- {
- if (tan_angle <= sDetailThresholds[i])
- {
- return i;
- }
- }
- return NUM_LODS - 1;
- }
- void LLVolumeLODGroup::getDetailProximity(F32 tan_angle, F32& to_lower,
- F32& to_higher)
- {
- S32 detail = getDetailFromTan(tan_angle);
- if (detail > 0)
- {
- to_lower = tan_angle - sDetailThresholds[detail];
- }
- else
- {
- to_lower = 1024.f * 1024.f;
- }
- if (detail < NUM_LODS - 1)
- {
- to_higher = sDetailThresholds[detail + 1] - tan_angle;
- }
- else
- {
- to_higher = 1024.f * 1024.f;
- }
- }
- F32 LLVolumeLODGroup::getVolumeScaleFromDetail(S32 detail)
- {
- return sDetailScales[detail];
- }
- S32 LLVolumeLODGroup::getVolumeDetailFromScale(F32 scale)
- {
- for (S32 i = 1; i < 4; ++i)
- {
- if (sDetailScales[i] > scale)
- {
- 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]);
- 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;
- }
|