diff options
Diffstat (limited to 'indra/llmath/llvolumemgr.cpp')
-rw-r--r-- | indra/llmath/llvolumemgr.cpp | 269 |
1 files changed, 163 insertions, 106 deletions
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 945d74f7c1..88c195936c 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -1,43 +1,35 @@ /** * @file llvolumemgr.cpp * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * 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://secondlife.com/developers/opensource/gplv2 + * 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. * - * 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://secondlife.com/developers/opensource/flossexception + * 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. * - * 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. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llvolumemgr.h" +#include "llmemtype.h" #include "llvolume.h" -//#define DEBUG_VOLUME - -LLVolumeMgr* gVolumeMgr = 0; - const F32 BASE_THRESHOLD = 0.03f; //static @@ -49,108 +41,118 @@ F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {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(NULL) { - mDataMutex = new LLMutex(gAPRPoolp); -// mNumVolumes = 0; + // the LLMutex magic interferes with easy unit testing, + // so you now must manually call useMutex() to use it + //mDataMutex = new LLMutex(gAPRPoolp); } LLVolumeMgr::~LLVolumeMgr() { cleanup(); + delete mDataMutex; + mDataMutex = NULL; } BOOL LLVolumeMgr::cleanup() { - #ifdef DEBUG_VOLUME + BOOL no_refs = TRUE; + if (mDataMutex) { - lldebugs << "LLVolumeMgr::cleanup()" << llendl; + mDataMutex->lock(); } - #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) + if (volgroupp->cleanupRefs() == false) { - llwarns << "Volume group " << volgroupp << " has " - << volgroupp->getNumRefs() << " remaining refs" << llendl; - llwarns << volgroupp->getParams() << llendl; no_refs = FALSE; } - volgroupp->unref();// this ); + delete volgroupp; } mVolumeLODGroups.clear(); - mDataMutex->unlock(); + if (mDataMutex) + { + mDataMutex->unlock(); + } return no_refs; } -LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32 detail) +// 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; - mDataMutex->lock(); + if (mDataMutex) + { + 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 + volgroupp = createNewGroup(volume_params); } else { volgroupp = iter->second; } - volgroupp->ref();// this ); - mDataMutex->unlock(); - // mNumVolumes++; - #ifdef DEBUG_VOLUME + 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) { - lldebugs << "LLVolumeMgr::getVolume() " << (*this) << llendl; + mDataMutex->unlock(); } - #endif - return volgroupp->getLOD(detail); + return volgroupp; } -void LLVolumeMgr::cleanupVolume(LLVolume *volumep) +void LLVolumeMgr::unrefVolume(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(); + 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; - mDataMutex->unlock(); + if (mDataMutex) + { + mDataMutex->unlock(); + } return; } else @@ -158,27 +160,42 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep) LLVolumeLODGroup* volgroupp = iter->second; volgroupp->derefLOD(volumep); - volgroupp->unref();// this ); - if (volgroupp->getNumRefs() == 1) + if (volgroupp->getNumRefs() == 0) { mVolumeLODGroups.erase(params); - volgroupp->unref();// this ); + delete volgroupp; } - // mNumVolumes--; } - mDataMutex->unlock(); - - #ifdef DEBUG_VOLUME + if (mDataMutex) { - lldebugs << "LLVolumeMgr::cleanupVolume() " << (*this) << llendl; + mDataMutex->unlock(); } - #endif + +} + +// 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; - mDataMutex->lock(); + if (mDataMutex) + { + mDataMutex->lock(); + } for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(), end = mVolumeLODGroups.end(); iter != end; iter++) @@ -188,80 +205,121 @@ void LLVolumeMgr::dump() } int count = (int)mVolumeLODGroups.size(); avg = count ? avg / (F32)count : 0.0f; - mDataMutex->unlock(); + if (mDataMutex) + { + mDataMutex->unlock(); + } llinfos << "Average usage of LODs " << avg << llendl; } +void LLVolumeMgr::useMutex() +{ + if (!mDataMutex) + { + mDataMutex = new LLMutex(gAPRPoolp); + } +} + std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr) { s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", "; S32 total_refs = 0; - volume_mgr.mDataMutex->lock(); + if (volume_mgr.mDataMutex) + { + 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) + 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); } - volume_mgr.mDataMutex->unlock(); + if (volume_mgr.mDataMutex) + { + volume_mgr.mDataMutex->unlock(); + } s << ", total_refs=" << total_refs << " }"; return s; } LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms) + : mVolumeParams(params), + mRefs(0) { - S32 i; - mParams = params; - - for (i = 0; i < NUM_LODS; i++) + for (S32 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++) + for (S32 i = 0; i < NUM_LODS; i++) { - delete mVolumeLODs[i]; - mVolumeLODs[i] = NULL; + 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::getLOD(const S32 detail) +LLVolume* LLVolumeLODGroup::refLOD(const S32 detail) { llassert(detail >=0 && detail < NUM_LODS); mAccessCount[detail]++; - mLODRefs[detail]++; - if (!mVolumeLODs[detail]) + + mRefs++; + if (mVolumeLODs[detail].isNull()) { - mVolumeLODs[detail] = new LLVolume(mParams, mDetailScales[detail]); + LLMemType m1(LLMemType::MTYPE_VOLUME); + mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]); } + mLODRefs[detail]++; return mVolumeLODs[detail]; } BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) { - S32 i; - for (i = 0; i < NUM_LODS; i++) + 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; } } @@ -313,7 +371,6 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail) F32 LLVolumeLODGroup::dump() { - char dump_str[255]; /* Flawfinder: ignore */ F32 usage = 0.f; for (S32 i = 0; i < NUM_LODS; i++) { @@ -324,7 +381,7 @@ F32 LLVolumeLODGroup::dump() } 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 */ + 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; @@ -333,7 +390,7 @@ F32 LLVolumeLODGroup::dump() std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup) { s << "{ numRefs=" << volgroup.getNumRefs(); - s << ", mParams=" << volgroup.mParams; + s << ", mParams=" << volgroup.getVolumeParams(); s << " }"; return s; |