00001
00031 #include "linden_common.h"
00032
00033 #include "llvolumemgr.h"
00034 #include "llmemtype.h"
00035 #include "llvolume.h"
00036
00037
00038 const F32 BASE_THRESHOLD = 0.03f;
00039
00040
00041 F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
00042 2*BASE_THRESHOLD,
00043 8*BASE_THRESHOLD,
00044 100*BASE_THRESHOLD};
00045
00046
00047 F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
00048
00049
00050
00051
00052 LLVolumeMgr::LLVolumeMgr()
00053 : mDataMutex(NULL)
00054 {
00055
00056
00057
00058 }
00059
00060 LLVolumeMgr::~LLVolumeMgr()
00061 {
00062 cleanup();
00063
00064 delete mDataMutex;
00065 mDataMutex = NULL;
00066 }
00067
00068 BOOL LLVolumeMgr::cleanup()
00069 {
00070 BOOL no_refs = TRUE;
00071 if (mDataMutex)
00072 {
00073 mDataMutex->lock();
00074 }
00075 for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
00076 end = mVolumeLODGroups.end();
00077 iter != end; iter++)
00078 {
00079 LLVolumeLODGroup *volgroupp = iter->second;
00080 if (volgroupp->cleanupRefs() == false)
00081 {
00082 no_refs = FALSE;
00083 }
00084 delete volgroupp;
00085 }
00086 mVolumeLODGroups.clear();
00087 if (mDataMutex)
00088 {
00089 mDataMutex->unlock();
00090 }
00091 return no_refs;
00092 }
00093
00094
00095
00096
00097
00098 LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
00099 {
00100 LLVolumeLODGroup* volgroupp;
00101 if (mDataMutex)
00102 {
00103 mDataMutex->lock();
00104 }
00105 volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
00106 if( iter == mVolumeLODGroups.end() )
00107 {
00108 volgroupp = createNewGroup(volume_params);
00109 }
00110 else
00111 {
00112 volgroupp = iter->second;
00113 }
00114 if (mDataMutex)
00115 {
00116 mDataMutex->unlock();
00117 }
00118 return volgroupp->getLODVolume(detail);
00119 }
00120
00121
00122 LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const
00123 {
00124 LLVolumeLODGroup* volgroupp = NULL;
00125 if (mDataMutex)
00126 {
00127 mDataMutex->lock();
00128 }
00129 volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
00130 if( iter != mVolumeLODGroups.end() )
00131 {
00132 volgroupp = iter->second;
00133 }
00134 if (mDataMutex)
00135 {
00136 mDataMutex->unlock();
00137 }
00138 return volgroupp;
00139 }
00140
00141 void LLVolumeMgr::unrefVolume(LLVolume *volumep)
00142 {
00143 if (volumep->isUnique())
00144 {
00145
00146 return;
00147 }
00148 const LLVolumeParams* params = &(volumep->getParams());
00149 if (mDataMutex)
00150 {
00151 mDataMutex->lock();
00152 }
00153 volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
00154 if( iter == mVolumeLODGroups.end() )
00155 {
00156 llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
00157 if (mDataMutex)
00158 {
00159 mDataMutex->unlock();
00160 }
00161 return;
00162 }
00163 else
00164 {
00165 LLVolumeLODGroup* volgroupp = iter->second;
00166
00167 volgroupp->derefLOD(volumep);
00168 if (volgroupp->getNumRefs() == 0)
00169 {
00170 mVolumeLODGroups.erase(params);
00171 delete volgroupp;
00172 }
00173 }
00174 if (mDataMutex)
00175 {
00176 mDataMutex->unlock();
00177 }
00178
00179 }
00180
00181
00182 void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup)
00183 {
00184 mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup;
00185 }
00186
00187
00188 LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
00189 {
00190 LLMemType m1(LLMemType::MTYPE_VOLUME);
00191 LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params);
00192 insertGroup(volgroup);
00193 return volgroup;
00194 }
00195
00196
00197 void LLVolumeMgr::dump()
00198 {
00199 F32 avg = 0.f;
00200 if (mDataMutex)
00201 {
00202 mDataMutex->lock();
00203 }
00204 for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
00205 end = mVolumeLODGroups.end();
00206 iter != end; iter++)
00207 {
00208 LLVolumeLODGroup *volgroupp = iter->second;
00209 avg += volgroupp->dump();
00210 }
00211 int count = (int)mVolumeLODGroups.size();
00212 avg = count ? avg / (F32)count : 0.0f;
00213 if (mDataMutex)
00214 {
00215 mDataMutex->unlock();
00216 }
00217 llinfos << "Average usage of LODs " << avg << llendl;
00218 }
00219
00220 void LLVolumeMgr::useMutex()
00221 {
00222 if (!mDataMutex)
00223 {
00224 mDataMutex = new LLMutex(gAPRPoolp);
00225 }
00226 }
00227
00228 std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
00229 {
00230 s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
00231
00232 S32 total_refs = 0;
00233 if (volume_mgr.mDataMutex)
00234 {
00235 volume_mgr.mDataMutex->lock();
00236 }
00237
00238 for (LLVolumeMgr::volume_lod_group_map_t::const_iterator iter = volume_mgr.mVolumeLODGroups.begin();
00239 iter != volume_mgr.mVolumeLODGroups.end(); ++iter)
00240 {
00241 LLVolumeLODGroup *volgroupp = iter->second;
00242 total_refs += volgroupp->getNumRefs();
00243 s << ", " << (*volgroupp);
00244 }
00245
00246 if (volume_mgr.mDataMutex)
00247 {
00248 volume_mgr.mDataMutex->unlock();
00249 }
00250
00251 s << ", total_refs=" << total_refs << " }";
00252 return s;
00253 }
00254
00255 LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms)
00256 : mVolumeParams(params),
00257 mRefs(0)
00258 {
00259 for (S32 i = 0; i < NUM_LODS; i++)
00260 {
00261 mLODRefs[i] = 0;
00262 mAccessCount[i] = 0;
00263 }
00264 }
00265
00266 LLVolumeLODGroup::~LLVolumeLODGroup()
00267 {
00268 for (S32 i = 0; i < NUM_LODS; i++)
00269 {
00270 llassert_always(mLODRefs[i] == 0);
00271 }
00272 }
00273
00274
00275 bool LLVolumeLODGroup::cleanupRefs()
00276 {
00277 bool res = true;
00278 if (mRefs != 0)
00279 {
00280 llwarns << "Volume group has remaining refs:" << getNumRefs() << llendl;
00281 mRefs = 0;
00282 for (S32 i = 0; i < NUM_LODS; i++)
00283 {
00284 if (mLODRefs[i] > 0)
00285 {
00286 llwarns << " LOD " << i << " refs = " << mLODRefs[i] << llendl;
00287 mLODRefs[i] = 0;
00288 mVolumeLODs[i] = NULL;
00289 }
00290 }
00291 llwarns << *getVolumeParams() << llendl;
00292 res = false;
00293 }
00294 return res;
00295 }
00296
00297 LLVolume* LLVolumeLODGroup::getLODVolume(const S32 detail)
00298 {
00299 llassert(detail >=0 && detail < NUM_LODS);
00300 mAccessCount[detail]++;
00301
00302 mRefs++;
00303 if (mVolumeLODs[detail].isNull())
00304 {
00305 LLMemType m1(LLMemType::MTYPE_VOLUME);
00306 mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
00307 }
00308 mLODRefs[detail]++;
00309 return mVolumeLODs[detail];
00310 }
00311
00312 BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
00313 {
00314 llassert_always(mRefs > 0);
00315 mRefs--;
00316 for (S32 i = 0; i < NUM_LODS; i++)
00317 {
00318 if (mVolumeLODs[i] == volumep)
00319 {
00320 llassert_always(mLODRefs[i] > 0);
00321 mLODRefs[i]--;
00322 #if 1 // SJB: Possible opt: keep other lods around
00323 if (!mLODRefs[i])
00324 {
00325 mVolumeLODs[i] = NULL;
00326 }
00327 #endif
00328 return TRUE;
00329 }
00330 }
00331 llerrs << "Deref of non-matching LOD in volume LOD group" << llendl;
00332 return FALSE;
00333 }
00334
00335 S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
00336 {
00337 S32 i = 0;
00338 while (i < (NUM_LODS - 1))
00339 {
00340 if (tan_angle <= mDetailThresholds[i])
00341 {
00342 return i;
00343 }
00344 i++;
00345 }
00346 return NUM_LODS - 1;
00347 }
00348
00349 void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher)
00350 {
00351 S32 detail = getDetailFromTan(tan_angle);
00352
00353 if (detail > 0)
00354 {
00355 to_lower = tan_angle - mDetailThresholds[detail];
00356 }
00357 else
00358 {
00359 to_lower = 1024.f*1024.f;
00360 }
00361
00362 if (detail < NUM_LODS-1)
00363 {
00364 to_higher = mDetailThresholds[detail+1] - tan_angle;
00365 }
00366 else
00367 {
00368 to_higher = 1024.f*1024.f;
00369 }
00370 }
00371
00372 F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
00373 {
00374 return mDetailScales[detail];
00375 }
00376
00377 F32 LLVolumeLODGroup::dump()
00378 {
00379 char dump_str[255];
00380 F32 usage = 0.f;
00381 for (S32 i = 0; i < NUM_LODS; i++)
00382 {
00383 if (mAccessCount[i] > 0)
00384 {
00385 usage += 1.f;
00386 }
00387 }
00388 usage = usage / (F32)NUM_LODS;
00389
00390 snprintf(dump_str, sizeof(dump_str), "%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]);
00391
00392 llinfos << dump_str << llendl;
00393 return usage;
00394 }
00395
00396 std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
00397 {
00398 s << "{ numRefs=" << volgroup.getNumRefs();
00399 s << ", mParams=" << volgroup.getVolumeParams();
00400 s << " }";
00401
00402 return s;
00403 }
00404