00001
00031 #include "linden_common.h"
00032
00033 #include "llvolumemgr.h"
00034 #include "llvolume.h"
00035
00036
00037
00038
00039 LLVolumeMgr* gVolumeMgr = 0;
00040
00041 const F32 BASE_THRESHOLD = 0.03f;
00042
00043
00044 F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
00045 2*BASE_THRESHOLD,
00046 8*BASE_THRESHOLD,
00047 100*BASE_THRESHOLD};
00048
00049
00050 F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
00051
00052
00053
00054 void LLVolumeMgr::initClass()
00055 {
00056 gVolumeMgr = new LLVolumeMgr();
00057 }
00058
00059
00060 BOOL LLVolumeMgr::cleanupClass()
00061 {
00062 BOOL res = FALSE;
00063 if (gVolumeMgr) {
00064 res = gVolumeMgr->cleanup();
00065 delete gVolumeMgr;
00066 gVolumeMgr = 0;
00067 }
00068 return res;
00069 }
00070
00071
00072
00073 LLVolumeMgr::LLVolumeMgr()
00074 {
00075 mDataMutex = new LLMutex(gAPRPoolp);
00076
00077 }
00078
00079 LLVolumeMgr::~LLVolumeMgr()
00080 {
00081 cleanup();
00082 delete mDataMutex;
00083 }
00084
00085 BOOL LLVolumeMgr::cleanup()
00086 {
00087 #ifdef DEBUG_VOLUME
00088 {
00089 lldebugs << "LLVolumeMgr::cleanup()" << llendl;
00090 }
00091 #endif
00092 BOOL no_refs = TRUE;
00093 mDataMutex->lock();
00094 for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
00095 end = mVolumeLODGroups.end();
00096 iter != end; iter++)
00097 {
00098 LLVolumeLODGroup *volgroupp = iter->second;
00099 if (volgroupp->getNumRefs() != 1)
00100 {
00101 llwarns << "Volume group " << volgroupp << " has "
00102 << volgroupp->getNumRefs() << " remaining refs" << llendl;
00103 llwarns << volgroupp->getParams() << llendl;
00104 no_refs = FALSE;
00105 }
00106 volgroupp->unref();
00107 }
00108 mVolumeLODGroups.clear();
00109 mDataMutex->unlock();
00110 return no_refs;
00111 }
00112
00113 LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32 detail)
00114 {
00115 LLVolumeLODGroup* volgroupp;
00116 mDataMutex->lock();
00117 volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
00118 if( iter == mVolumeLODGroups.end() )
00119 {
00120 volgroupp = new LLVolumeLODGroup(volume_params);
00121 const LLVolumeParams* params = &(volgroupp->getParams());
00122 mVolumeLODGroups[params] = volgroupp;
00123 volgroupp->ref();
00124 }
00125 else
00126 {
00127 volgroupp = iter->second;
00128 }
00129 volgroupp->ref();
00130 mDataMutex->unlock();
00131
00132 #ifdef DEBUG_VOLUME
00133 {
00134 lldebugs << "LLVolumeMgr::getVolume() " << (*this) << llendl;
00135 }
00136 #endif
00137 return volgroupp->getLOD(detail);
00138 }
00139
00140 void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
00141 {
00142 if (volumep->isUnique())
00143 {
00144
00145 return;
00146 }
00147 LLVolumeParams* params = (LLVolumeParams*) &(volumep->getParams());
00148 mDataMutex->lock();
00149 volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
00150 if( iter == mVolumeLODGroups.end() )
00151 {
00152 llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
00153 mDataMutex->unlock();
00154 return;
00155 }
00156 else
00157 {
00158 LLVolumeLODGroup* volgroupp = iter->second;
00159
00160 volgroupp->derefLOD(volumep);
00161 volgroupp->unref();
00162 if (volgroupp->getNumRefs() == 1)
00163 {
00164 mVolumeLODGroups.erase(params);
00165 volgroupp->unref();
00166 }
00167
00168 }
00169 mDataMutex->unlock();
00170
00171 #ifdef DEBUG_VOLUME
00172 {
00173 lldebugs << "LLVolumeMgr::cleanupVolume() " << (*this) << llendl;
00174 }
00175 #endif
00176 }
00177
00178 void LLVolumeMgr::dump()
00179 {
00180 F32 avg = 0.f;
00181 mDataMutex->lock();
00182 for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
00183 end = mVolumeLODGroups.end();
00184 iter != end; iter++)
00185 {
00186 LLVolumeLODGroup *volgroupp = iter->second;
00187 avg += volgroupp->dump();
00188 }
00189 int count = (int)mVolumeLODGroups.size();
00190 avg = count ? avg / (F32)count : 0.0f;
00191 mDataMutex->unlock();
00192 llinfos << "Average usage of LODs " << avg << llendl;
00193 }
00194
00195 std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
00196 {
00197 s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
00198
00199 S32 total_refs = 0;
00200 volume_mgr.mDataMutex->lock();
00201
00202 LLVolumeMgr::volume_lod_group_map_iter iter = volume_mgr.mVolumeLODGroups.begin();
00203 LLVolumeMgr::volume_lod_group_map_iter end = volume_mgr.mVolumeLODGroups.end();
00204 for ( ; iter != end; ++iter)
00205 {
00206 LLVolumeLODGroup *volgroupp = iter->second;
00207 total_refs += volgroupp->getNumRefs();
00208 s << ", " << (*volgroupp);
00209 }
00210
00211 volume_mgr.mDataMutex->unlock();
00212
00213 s << ", total_refs=" << total_refs << " }";
00214 return s;
00215 }
00216
00217 LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms)
00218 {
00219 S32 i;
00220 mParams = params;
00221
00222 for (i = 0; i < NUM_LODS; i++)
00223 {
00224 mLODRefs[i] = 0;
00225 mVolumeLODs[i] = NULL;
00226 mAccessCount[i] = 0;
00227 }
00228 }
00229
00230 LLVolumeLODGroup::~LLVolumeLODGroup()
00231 {
00232 S32 i;
00233 for (i = 0; i < NUM_LODS; i++)
00234 {
00235 delete mVolumeLODs[i];
00236 mVolumeLODs[i] = NULL;
00237 }
00238 }
00239
00240
00241 LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)
00242 {
00243 llassert(detail >=0 && detail < NUM_LODS);
00244 mAccessCount[detail]++;
00245 mLODRefs[detail]++;
00246 if (!mVolumeLODs[detail])
00247 {
00248 mVolumeLODs[detail] = new LLVolume(mParams, mDetailScales[detail]);
00249 }
00250 return mVolumeLODs[detail];
00251 }
00252
00253 BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
00254 {
00255 S32 i;
00256 for (i = 0; i < NUM_LODS; i++)
00257 {
00258 if (mVolumeLODs[i] == volumep)
00259 {
00260 mLODRefs[i]--;
00261 if (!mLODRefs[i])
00262 {
00263 mVolumeLODs[i] = NULL;
00264 }
00265 return TRUE;
00266 }
00267 }
00268 llerrs << "Deref of non-matching LOD in volume LOD group" << llendl;
00269 return FALSE;
00270 }
00271
00272 S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
00273 {
00274 S32 i = 0;
00275 while (i < (NUM_LODS - 1))
00276 {
00277 if (tan_angle <= mDetailThresholds[i])
00278 {
00279 return i;
00280 }
00281 i++;
00282 }
00283 return NUM_LODS - 1;
00284 }
00285
00286 F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
00287 {
00288 return mDetailScales[detail];
00289 }
00290
00291 F32 LLVolumeLODGroup::dump()
00292 {
00293 char dump_str[255];
00294 F32 usage = 0.f;
00295 for (S32 i = 0; i < NUM_LODS; i++)
00296 {
00297 if (mAccessCount[i] > 0)
00298 {
00299 usage += 1.f;
00300 }
00301 }
00302 usage = usage / (F32)NUM_LODS;
00303
00304 snprintf(dump_str, sizeof(dump_str), "%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]);
00305
00306 llinfos << dump_str << llendl;
00307 return usage;
00308 }
00309
00310 std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
00311 {
00312 s << "{ numRefs=" << volgroup.getNumRefs();
00313 s << ", mParams=" << volgroup.mParams;
00314 s << " }";
00315
00316 return s;
00317 }
00318