llvolumemgr.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /**
  2. * @file llvolumemgr.cpp
  3. *
  4. * $LicenseInfo:firstyear=2002&license=viewergpl$
  5. *
  6. * Copyright (c) 2002-2009, Linden Research, Inc.
  7. *
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab. Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. *
  16. * There are special exceptions to the terms and conditions of the GPL as
  17. * it is applied to this Source Code. View the full text of the exception
  18. * in the file doc/FLOSS-exception.txt in this software distribution, or
  19. * online at
  20. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. *
  22. * By copying, modifying or distributing this software, you acknowledge
  23. * that you have read and understood your obligations described above,
  24. * and agree to abide by those obligations.
  25. *
  26. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28. * COMPLETENESS OR PERFORMANCE.
  29. * $/LicenseInfo$
  30. */
  31. #include "linden_common.h"
  32. #include "llvolumemgr.h"
  33. #include "llvolume.h"
  34. constexpr F32 BASE_THRESHOLD = 0.03f;
  35. LLVolumeMgr* gVolumeMgrp = NULL;
  36. // Static members
  37. F32 LLVolumeLODGroup::sDetailThresholds[NUM_LODS] = { BASE_THRESHOLD,
  38. 2 * BASE_THRESHOLD,
  39. 8 * BASE_THRESHOLD,
  40. 100 * BASE_THRESHOLD };
  41. F32 LLVolumeLODGroup::sDetailScales[NUM_LODS] = { 1.f, 1.5f, 2.5f, 4.f };
  42. //static
  43. void LLVolumeMgr::initClass()
  44. {
  45. if (gVolumeMgrp)
  46. {
  47. llerrs << "A volume manager already exists !" << llendl;
  48. }
  49. gVolumeMgrp = new LLVolumeMgr;
  50. }
  51. //static
  52. void LLVolumeMgr::cleanupClass()
  53. {
  54. if (gVolumeMgrp)
  55. {
  56. delete gVolumeMgrp;
  57. gVolumeMgrp = NULL;
  58. llinfos << "Volume manager destroyed." << llendl;
  59. }
  60. }
  61. LLVolumeMgr::~LLVolumeMgr()
  62. {
  63. U32 remaining = 0;
  64. mDataMutex.lock();
  65. for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
  66. end = mVolumeLODGroups.end();
  67. iter != end; ++iter)
  68. {
  69. LLVolumeLODGroup* volgroupp = iter->second;
  70. if (volgroupp->cleanupRefs() == false)
  71. {
  72. ++remaining;
  73. }
  74. delete volgroupp;
  75. }
  76. mVolumeLODGroups.clear();
  77. mDataMutex.unlock();
  78. if (remaining)
  79. {
  80. llwarns << "There were " << remaining
  81. << " remaining references in the volume manager." << llendl;
  82. }
  83. }
  84. // Always only ever store the results of refVolume in a LLPointer. Note however
  85. // that LLVolumeLODGroup which contains the volume also holds a LLPointer so
  86. // the volume will only go away after anything holding the volume and the
  87. // LODGroup are destroyed
  88. LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams& volume_params,
  89. S32 detail)
  90. {
  91. if (detail < 0 || detail >= LLVolumeLODGroup::NUM_LODS)
  92. {
  93. llwarns << "Attempt to reference a volume for out of range LOD: "
  94. << detail << llendl;
  95. return NULL;
  96. }
  97. mDataMutex.lock();
  98. volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
  99. LLVolumeLODGroup* volgroupp;
  100. if (iter == mVolumeLODGroups.end())
  101. {
  102. volgroupp = createNewGroup(volume_params);
  103. }
  104. else
  105. {
  106. volgroupp = iter->second;
  107. }
  108. mDataMutex.unlock();
  109. return volgroupp->refLOD(detail);
  110. }
  111. LLVolumeLODGroup* LLVolumeMgr::getGroup(const LLVolumeParams& volume_params)
  112. {
  113. LLVolumeLODGroup* volgroupp = NULL;
  114. mDataMutex.lock();
  115. volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
  116. if (iter != mVolumeLODGroups.end())
  117. {
  118. volgroupp = iter->second;
  119. }
  120. mDataMutex.unlock();
  121. return volgroupp;
  122. }
  123. void LLVolumeMgr::unrefVolume(LLVolume* volumep)
  124. {
  125. if (volumep->isUnique())
  126. {
  127. // TomY: Don't need to manage this volume. It is a unique instance.
  128. return;
  129. }
  130. const LLVolumeParams* params = &(volumep->getParams());
  131. mDataMutex.lock();
  132. volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
  133. if (iter == mVolumeLODGroups.end())
  134. {
  135. mDataMutex.unlock();
  136. llwarns << "Tried to cleanup unknown volume type ! " << *params
  137. << llendl;
  138. llassert(false);
  139. return;
  140. }
  141. else
  142. {
  143. LLVolumeLODGroup* volgroupp = iter->second;
  144. if (volgroupp)
  145. {
  146. volgroupp->derefLOD(volumep);
  147. if (volgroupp->getNumRefs() == 0)
  148. {
  149. mVolumeLODGroups.erase(params);
  150. delete volgroupp;
  151. }
  152. }
  153. else
  154. {
  155. llwarns << "Found a NULL volume LOD group !" << llendl;
  156. }
  157. }
  158. mDataMutex.unlock();
  159. }
  160. void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup)
  161. {
  162. mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup;
  163. }
  164. LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
  165. {
  166. LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params);
  167. insertGroup(volgroup);
  168. return volgroup;
  169. }
  170. void LLVolumeMgr::dump()
  171. {
  172. F32 avg = 0.f;
  173. mDataMutex.lock();
  174. for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
  175. end = mVolumeLODGroups.end();
  176. iter != end; ++iter)
  177. {
  178. LLVolumeLODGroup* volgroupp = iter->second;
  179. avg += volgroupp->dump();
  180. }
  181. S32 count = mVolumeLODGroups.size();
  182. avg = count ? avg / (F32)count : 0.0f;
  183. mDataMutex.unlock();
  184. llinfos << "Average usage of LODs " << avg << llendl;
  185. }
  186. std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
  187. {
  188. s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
  189. S32 total_refs = 0;
  190. // Cheating out const-ness...
  191. LLMutex* mutex = &const_cast<LLVolumeMgr&>(volume_mgr).mDataMutex;
  192. mutex->lock();
  193. for (LLVolumeMgr::volume_lod_group_map_t::const_iterator
  194. iter = volume_mgr.mVolumeLODGroups.begin(),
  195. end = volume_mgr.mVolumeLODGroups.end();
  196. iter != end; ++iter)
  197. {
  198. LLVolumeLODGroup* volgroupp = iter->second;
  199. total_refs += volgroupp->getNumRefs();
  200. s << ", " << (*volgroupp);
  201. }
  202. mutex->unlock();
  203. s << ", total_refs=" << total_refs << " }";
  204. return s;
  205. }
  206. LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams& params)
  207. : mVolumeParams(params),
  208. mRefs(0)
  209. {
  210. for (S32 i = 0; i < NUM_LODS; ++i)
  211. {
  212. mLODRefs[i] = 0;
  213. mAccessCount[i] = 0;
  214. }
  215. }
  216. LLVolumeLODGroup::~LLVolumeLODGroup()
  217. {
  218. for (S32 i = 0; i < NUM_LODS; ++i)
  219. {
  220. llassert_always(mLODRefs[i] == 0);
  221. }
  222. }
  223. // Called from LLVolumeMgr::cleanup
  224. bool LLVolumeLODGroup::cleanupRefs()
  225. {
  226. bool res = true;
  227. if (mRefs != 0)
  228. {
  229. llwarns << "Volume group has remaining refs:" << getNumRefs()
  230. << llendl;
  231. mRefs = 0;
  232. for (S32 i = 0; i < NUM_LODS; ++i)
  233. {
  234. if (mLODRefs[i] > 0)
  235. {
  236. llwarns << " LOD " << i << " refs = " << mLODRefs[i] << llendl;
  237. mLODRefs[i] = 0;
  238. mVolumeLODs[i] = NULL;
  239. }
  240. }
  241. llwarns << *getVolumeParams() << llendl;
  242. res = false;
  243. }
  244. return res;
  245. }
  246. LLVolume* LLVolumeLODGroup::refLOD(S32 detail)
  247. {
  248. if (detail < 0 || detail >= NUM_LODS)
  249. {
  250. llwarns << "Attempt to reference out of range LOD " << detail
  251. << " in volume group " << std::hex << this << std::dec
  252. << llendl;
  253. llassert(false);
  254. return NULL;
  255. }
  256. ++mAccessCount[detail];
  257. ++mRefs;
  258. if (mVolumeLODs[detail].isNull())
  259. {
  260. mVolumeLODs[detail] = new LLVolume(mVolumeParams,
  261. sDetailScales[detail]);
  262. }
  263. ++mLODRefs[detail];
  264. return mVolumeLODs[detail];
  265. }
  266. bool LLVolumeLODGroup::derefLOD(LLVolume* volumep)
  267. {
  268. if (mRefs > 0)
  269. {
  270. --mRefs;
  271. }
  272. else
  273. {
  274. llwarns << "Attempt to dereference a zero count volume: "
  275. << std::hex << volumep << std::dec << llendl;
  276. llassert(false);
  277. return false;
  278. }
  279. for (S32 i = 0; i < NUM_LODS; ++i)
  280. {
  281. if (mVolumeLODs[i] == volumep)
  282. {
  283. #if 0 // SJB: Possible opt: keep other LODs around
  284. if (!mLODRefs[i])
  285. {
  286. mVolumeLODs[i] = NULL;
  287. }
  288. else
  289. #endif
  290. if (mLODRefs[i] > 0)
  291. {
  292. --mLODRefs[i];
  293. }
  294. else
  295. {
  296. llwarns << "Unreferenced LOD (" << i << ") for volume: "
  297. << std::hex << volumep << std::dec << llendl;
  298. }
  299. return true;
  300. }
  301. }
  302. llwarns << "Attempt to dereference a non-matching LOD in volume LOD group for volume: "
  303. << std::hex << volumep << std::dec << llendl;
  304. return false;
  305. }
  306. S32 LLVolumeLODGroup::getDetailFromTan(F32 tan_angle)
  307. {
  308. for (S32 i = 0; i < NUM_LODS - 1; ++i)
  309. {
  310. if (tan_angle <= sDetailThresholds[i])
  311. {
  312. return i;
  313. }
  314. }
  315. return NUM_LODS - 1;
  316. }
  317. void LLVolumeLODGroup::getDetailProximity(F32 tan_angle, F32& to_lower,
  318. F32& to_higher)
  319. {
  320. S32 detail = getDetailFromTan(tan_angle);
  321. if (detail > 0)
  322. {
  323. to_lower = tan_angle - sDetailThresholds[detail];
  324. }
  325. else
  326. {
  327. to_lower = 1024.f * 1024.f;
  328. }
  329. if (detail < NUM_LODS - 1)
  330. {
  331. to_higher = sDetailThresholds[detail + 1] - tan_angle;
  332. }
  333. else
  334. {
  335. to_higher = 1024.f * 1024.f;
  336. }
  337. }
  338. F32 LLVolumeLODGroup::getVolumeScaleFromDetail(S32 detail)
  339. {
  340. return sDetailScales[detail];
  341. }
  342. S32 LLVolumeLODGroup::getVolumeDetailFromScale(F32 scale)
  343. {
  344. for (S32 i = 1; i < 4; ++i)
  345. {
  346. if (sDetailScales[i] > scale)
  347. {
  348. return i - 1;
  349. }
  350. }
  351. return 3;
  352. }
  353. F32 LLVolumeLODGroup::dump()
  354. {
  355. F32 usage = 0.f;
  356. for (S32 i = 0; i < NUM_LODS; ++i)
  357. {
  358. if (mAccessCount[i] > 0)
  359. {
  360. usage += 1.f;
  361. }
  362. }
  363. usage = usage / (F32)NUM_LODS;
  364. std::string dump_str = llformat("%.3f %d %d %d %d", usage,
  365. mAccessCount[0], mAccessCount[1],
  366. mAccessCount[2], mAccessCount[3]);
  367. llinfos << dump_str << llendl;
  368. return usage;
  369. }
  370. std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
  371. {
  372. s << "{ numRefs=" << volgroup.getNumRefs();
  373. s << ", mParams=" << volgroup.getVolumeParams();
  374. s << " }";
  375. return s;
  376. }