PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmath/llvolumemgr.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 411 lines | 326 code | 45 blank | 40 comment | 52 complexity | 3adb576bdab0b3a3991581f5ee888933 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llvolumemgr.cpp
  3. *
  4. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "linden_common.h"
  26. #include "llvolumemgr.h"
  27. #include "llmemtype.h"
  28. #include "llvolume.h"
  29. const F32 BASE_THRESHOLD = 0.03f;
  30. //static
  31. F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
  32. 2*BASE_THRESHOLD,
  33. 8*BASE_THRESHOLD,
  34. 100*BASE_THRESHOLD};
  35. //static
  36. F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
  37. //============================================================================
  38. LLVolumeMgr::LLVolumeMgr()
  39. : mDataMutex(NULL)
  40. {
  41. // the LLMutex magic interferes with easy unit testing,
  42. // so you now must manually call useMutex() to use it
  43. //mDataMutex = new LLMutex(gAPRPoolp);
  44. }
  45. LLVolumeMgr::~LLVolumeMgr()
  46. {
  47. cleanup();
  48. delete mDataMutex;
  49. mDataMutex = NULL;
  50. }
  51. BOOL LLVolumeMgr::cleanup()
  52. {
  53. BOOL no_refs = TRUE;
  54. if (mDataMutex)
  55. {
  56. mDataMutex->lock();
  57. }
  58. for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
  59. end = mVolumeLODGroups.end();
  60. iter != end; iter++)
  61. {
  62. LLVolumeLODGroup *volgroupp = iter->second;
  63. if (volgroupp->cleanupRefs() == false)
  64. {
  65. no_refs = FALSE;
  66. }
  67. delete volgroupp;
  68. }
  69. mVolumeLODGroups.clear();
  70. if (mDataMutex)
  71. {
  72. mDataMutex->unlock();
  73. }
  74. return no_refs;
  75. }
  76. // Always only ever store the results of refVolume in a LLPointer
  77. // Note however that LLVolumeLODGroup that contains the volume
  78. // also holds a LLPointer so the volume will only go away after
  79. // anything holding the volume and the LODGroup are destroyed
  80. LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
  81. {
  82. LLVolumeLODGroup* volgroupp;
  83. if (mDataMutex)
  84. {
  85. mDataMutex->lock();
  86. }
  87. volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
  88. if( iter == mVolumeLODGroups.end() )
  89. {
  90. volgroupp = createNewGroup(volume_params);
  91. }
  92. else
  93. {
  94. volgroupp = iter->second;
  95. }
  96. if (mDataMutex)
  97. {
  98. mDataMutex->unlock();
  99. }
  100. return volgroupp->refLOD(detail);
  101. }
  102. // virtual
  103. LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const
  104. {
  105. LLVolumeLODGroup* volgroupp = NULL;
  106. if (mDataMutex)
  107. {
  108. mDataMutex->lock();
  109. }
  110. volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
  111. if( iter != mVolumeLODGroups.end() )
  112. {
  113. volgroupp = iter->second;
  114. }
  115. if (mDataMutex)
  116. {
  117. mDataMutex->unlock();
  118. }
  119. return volgroupp;
  120. }
  121. void LLVolumeMgr::unrefVolume(LLVolume *volumep)
  122. {
  123. if (volumep->isUnique())
  124. {
  125. // TomY: Don't need to manage this volume. It is a unique instance.
  126. return;
  127. }
  128. const LLVolumeParams* params = &(volumep->getParams());
  129. if (mDataMutex)
  130. {
  131. mDataMutex->lock();
  132. }
  133. volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
  134. if( iter == mVolumeLODGroups.end() )
  135. {
  136. llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
  137. if (mDataMutex)
  138. {
  139. mDataMutex->unlock();
  140. }
  141. return;
  142. }
  143. else
  144. {
  145. LLVolumeLODGroup* volgroupp = iter->second;
  146. volgroupp->derefLOD(volumep);
  147. if (volgroupp->getNumRefs() == 0)
  148. {
  149. mVolumeLODGroups.erase(params);
  150. delete volgroupp;
  151. }
  152. }
  153. if (mDataMutex)
  154. {
  155. mDataMutex->unlock();
  156. }
  157. }
  158. // protected
  159. void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup)
  160. {
  161. mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup;
  162. }
  163. // protected
  164. LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
  165. {
  166. LLMemType m1(LLMemType::MTYPE_VOLUME);
  167. LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params);
  168. insertGroup(volgroup);
  169. return volgroup;
  170. }
  171. // virtual
  172. void LLVolumeMgr::dump()
  173. {
  174. F32 avg = 0.f;
  175. if (mDataMutex)
  176. {
  177. mDataMutex->lock();
  178. }
  179. for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
  180. end = mVolumeLODGroups.end();
  181. iter != end; iter++)
  182. {
  183. LLVolumeLODGroup *volgroupp = iter->second;
  184. avg += volgroupp->dump();
  185. }
  186. int count = (int)mVolumeLODGroups.size();
  187. avg = count ? avg / (F32)count : 0.0f;
  188. if (mDataMutex)
  189. {
  190. mDataMutex->unlock();
  191. }
  192. llinfos << "Average usage of LODs " << avg << llendl;
  193. }
  194. void LLVolumeMgr::useMutex()
  195. {
  196. if (!mDataMutex)
  197. {
  198. mDataMutex = new LLMutex(gAPRPoolp);
  199. }
  200. }
  201. std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
  202. {
  203. s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
  204. S32 total_refs = 0;
  205. if (volume_mgr.mDataMutex)
  206. {
  207. volume_mgr.mDataMutex->lock();
  208. }
  209. for (LLVolumeMgr::volume_lod_group_map_t::const_iterator iter = volume_mgr.mVolumeLODGroups.begin();
  210. iter != volume_mgr.mVolumeLODGroups.end(); ++iter)
  211. {
  212. LLVolumeLODGroup *volgroupp = iter->second;
  213. total_refs += volgroupp->getNumRefs();
  214. s << ", " << (*volgroupp);
  215. }
  216. if (volume_mgr.mDataMutex)
  217. {
  218. volume_mgr.mDataMutex->unlock();
  219. }
  220. s << ", total_refs=" << total_refs << " }";
  221. return s;
  222. }
  223. LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams &params)
  224. : mVolumeParams(params),
  225. mRefs(0)
  226. {
  227. for (S32 i = 0; i < NUM_LODS; i++)
  228. {
  229. mLODRefs[i] = 0;
  230. mAccessCount[i] = 0;
  231. }
  232. }
  233. LLVolumeLODGroup::~LLVolumeLODGroup()
  234. {
  235. for (S32 i = 0; i < NUM_LODS; i++)
  236. {
  237. llassert_always(mLODRefs[i] == 0);
  238. }
  239. }
  240. // Called from LLVolumeMgr::cleanup
  241. bool LLVolumeLODGroup::cleanupRefs()
  242. {
  243. bool res = true;
  244. if (mRefs != 0)
  245. {
  246. llwarns << "Volume group has remaining refs:" << getNumRefs() << llendl;
  247. mRefs = 0;
  248. for (S32 i = 0; i < NUM_LODS; i++)
  249. {
  250. if (mLODRefs[i] > 0)
  251. {
  252. llwarns << " LOD " << i << " refs = " << mLODRefs[i] << llendl;
  253. mLODRefs[i] = 0;
  254. mVolumeLODs[i] = NULL;
  255. }
  256. }
  257. llwarns << *getVolumeParams() << llendl;
  258. res = false;
  259. }
  260. return res;
  261. }
  262. LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
  263. {
  264. llassert(detail >=0 && detail < NUM_LODS);
  265. mAccessCount[detail]++;
  266. mRefs++;
  267. if (mVolumeLODs[detail].isNull())
  268. {
  269. LLMemType m1(LLMemType::MTYPE_VOLUME);
  270. mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
  271. }
  272. mLODRefs[detail]++;
  273. return mVolumeLODs[detail];
  274. }
  275. BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
  276. {
  277. llassert_always(mRefs > 0);
  278. mRefs--;
  279. for (S32 i = 0; i < NUM_LODS; i++)
  280. {
  281. if (mVolumeLODs[i] == volumep)
  282. {
  283. llassert_always(mLODRefs[i] > 0);
  284. mLODRefs[i]--;
  285. #if 0 // SJB: Possible opt: keep other lods around
  286. if (!mLODRefs[i])
  287. {
  288. mVolumeLODs[i] = NULL;
  289. }
  290. #endif
  291. return TRUE;
  292. }
  293. }
  294. llerrs << "Deref of non-matching LOD in volume LOD group" << llendl;
  295. return FALSE;
  296. }
  297. S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
  298. {
  299. S32 i = 0;
  300. while (i < (NUM_LODS - 1))
  301. {
  302. if (tan_angle <= mDetailThresholds[i])
  303. {
  304. return i;
  305. }
  306. i++;
  307. }
  308. return NUM_LODS - 1;
  309. }
  310. void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher)
  311. {
  312. S32 detail = getDetailFromTan(tan_angle);
  313. if (detail > 0)
  314. {
  315. to_lower = tan_angle - mDetailThresholds[detail];
  316. }
  317. else
  318. {
  319. to_lower = 1024.f*1024.f;
  320. }
  321. if (detail < NUM_LODS-1)
  322. {
  323. to_higher = mDetailThresholds[detail+1] - tan_angle;
  324. }
  325. else
  326. {
  327. to_higher = 1024.f*1024.f;
  328. }
  329. }
  330. F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
  331. {
  332. return mDetailScales[detail];
  333. }
  334. S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
  335. {
  336. for (S32 i = 1; i < 4; i++)
  337. {
  338. if (mDetailScales[i] > detail)
  339. {
  340. return i-1;
  341. }
  342. }
  343. return 3;
  344. }
  345. F32 LLVolumeLODGroup::dump()
  346. {
  347. F32 usage = 0.f;
  348. for (S32 i = 0; i < NUM_LODS; i++)
  349. {
  350. if (mAccessCount[i] > 0)
  351. {
  352. usage += 1.f;
  353. }
  354. }
  355. usage = usage / (F32)NUM_LODS;
  356. std::string dump_str = llformat("%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]);
  357. llinfos << dump_str << llendl;
  358. return usage;
  359. }
  360. std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
  361. {
  362. s << "{ numRefs=" << volgroup.getNumRefs();
  363. s << ", mParams=" << volgroup.getVolumeParams();
  364. s << " }";
  365. return s;
  366. }