summaryrefslogtreecommitdiff
path: root/indra/llmath/llvolumemgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath/llvolumemgr.cpp')
-rw-r--r--indra/llmath/llvolumemgr.cpp269
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 &params)
+ : 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;