PageRenderTime 65ms CodeModel.GetById 19ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 1ms

/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
  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
 26#include "linden_common.h"
 27
 28#include "llvolumemgr.h"
 29#include "llmemtype.h"
 30#include "llvolume.h"
 31
 32
 33const F32 BASE_THRESHOLD = 0.03f;
 34
 35//static
 36F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
 37													 2*BASE_THRESHOLD,
 38													 8*BASE_THRESHOLD,
 39													 100*BASE_THRESHOLD};
 40
 41//static
 42F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
 43
 44
 45//============================================================================
 46
 47LLVolumeMgr::LLVolumeMgr()
 48:	mDataMutex(NULL)
 49{
 50	// the LLMutex magic interferes with easy unit testing,
 51	// so you now must manually call useMutex() to use it
 52	//mDataMutex = new LLMutex(gAPRPoolp);
 53}
 54
 55LLVolumeMgr::~LLVolumeMgr()
 56{
 57	cleanup();
 58
 59	delete mDataMutex;
 60	mDataMutex = NULL;
 61}
 62
 63BOOL LLVolumeMgr::cleanup()
 64{
 65	BOOL no_refs = TRUE;
 66	if (mDataMutex)
 67	{
 68		mDataMutex->lock();
 69	}
 70	for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
 71			 end = mVolumeLODGroups.end();
 72		 iter != end; iter++)
 73	{
 74		LLVolumeLODGroup *volgroupp = iter->second;
 75		if (volgroupp->cleanupRefs() == false)
 76		{
 77			no_refs = FALSE;
 78		}
 79 		delete volgroupp;
 80	}
 81	mVolumeLODGroups.clear();
 82	if (mDataMutex)
 83	{
 84		mDataMutex->unlock();
 85	}
 86	return no_refs;
 87}
 88
 89// Always only ever store the results of refVolume in a LLPointer
 90// Note however that LLVolumeLODGroup that contains the volume
 91//  also holds a LLPointer so the volume will only go away after
 92//  anything holding the volume and the LODGroup are destroyed
 93LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
 94{
 95	LLVolumeLODGroup* volgroupp;
 96	if (mDataMutex)
 97	{
 98		mDataMutex->lock();
 99	}
100	volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
101	if( iter == mVolumeLODGroups.end() )
102	{
103		volgroupp = createNewGroup(volume_params);
104	}
105	else
106	{
107		volgroupp = iter->second;
108	}
109	if (mDataMutex)
110	{
111		mDataMutex->unlock();
112	}
113	return volgroupp->refLOD(detail);
114}
115
116// virtual
117LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const
118{
119	LLVolumeLODGroup* volgroupp = NULL;
120	if (mDataMutex)
121	{
122		mDataMutex->lock();
123	}
124	volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
125	if( iter != mVolumeLODGroups.end() )
126	{
127		volgroupp = iter->second;
128	}
129	if (mDataMutex)
130	{
131		mDataMutex->unlock();
132	}
133	return volgroupp;
134}
135
136void LLVolumeMgr::unrefVolume(LLVolume *volumep)
137{
138	if (volumep->isUnique())
139	{
140		// TomY: Don't need to manage this volume. It is a unique instance.
141		return;
142	}
143	const LLVolumeParams* params = &(volumep->getParams());
144	if (mDataMutex)
145	{
146		mDataMutex->lock();
147	}
148	volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
149	if( iter == mVolumeLODGroups.end() )
150	{
151		llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
152		if (mDataMutex)
153		{
154			mDataMutex->unlock();
155		}
156		return;
157	}
158	else
159	{
160		LLVolumeLODGroup* volgroupp = iter->second;
161
162		volgroupp->derefLOD(volumep);
163		if (volgroupp->getNumRefs() == 0)
164		{
165			mVolumeLODGroups.erase(params);
166			delete volgroupp;
167		}
168	}
169	if (mDataMutex)
170	{
171		mDataMutex->unlock();
172	}
173
174}
175
176// protected
177void LLVolumeMgr::insertGroup(LLVolumeLODGroup* volgroup)
178{
179	mVolumeLODGroups[volgroup->getVolumeParams()] = volgroup;
180}
181
182// protected
183LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
184{
185	LLMemType m1(LLMemType::MTYPE_VOLUME);
186	LLVolumeLODGroup* volgroup = new LLVolumeLODGroup(volume_params);
187	insertGroup(volgroup);
188	return volgroup;
189}
190
191// virtual
192void LLVolumeMgr::dump()
193{
194	F32 avg = 0.f;
195	if (mDataMutex)
196	{
197		mDataMutex->lock();
198	}
199	for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
200			 end = mVolumeLODGroups.end();
201		 iter != end; iter++)
202	{
203		LLVolumeLODGroup *volgroupp = iter->second;
204		avg += volgroupp->dump();
205	}
206	int count = (int)mVolumeLODGroups.size();
207	avg = count ? avg / (F32)count : 0.0f;
208	if (mDataMutex)
209	{
210		mDataMutex->unlock();
211	}
212	llinfos << "Average usage of LODs " << avg << llendl;
213}
214
215void LLVolumeMgr::useMutex()
216{ 
217	if (!mDataMutex)
218	{
219		mDataMutex = new LLMutex(gAPRPoolp);
220	}
221}
222
223std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
224{
225	s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
226
227	S32 total_refs = 0;
228	if (volume_mgr.mDataMutex)
229	{
230		volume_mgr.mDataMutex->lock();
231	}
232
233	for (LLVolumeMgr::volume_lod_group_map_t::const_iterator iter = volume_mgr.mVolumeLODGroups.begin();
234		 iter != volume_mgr.mVolumeLODGroups.end(); ++iter)
235	{
236		LLVolumeLODGroup *volgroupp = iter->second;
237		total_refs += volgroupp->getNumRefs();
238		s << ", " << (*volgroupp);
239	}
240
241	if (volume_mgr.mDataMutex)
242	{
243		volume_mgr.mDataMutex->unlock();
244	}
245
246	s << ", total_refs=" << total_refs << " }";
247	return s;
248}
249
250LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams &params)
251	: mVolumeParams(params),
252	  mRefs(0)
253{
254	for (S32 i = 0; i < NUM_LODS; i++)
255	{
256		mLODRefs[i] = 0;
257		mAccessCount[i] = 0;
258	}
259}
260
261LLVolumeLODGroup::~LLVolumeLODGroup()
262{
263	for (S32 i = 0; i < NUM_LODS; i++)
264	{
265		llassert_always(mLODRefs[i] == 0);
266	}
267}
268
269// Called from LLVolumeMgr::cleanup
270bool LLVolumeLODGroup::cleanupRefs()
271{
272	bool res = true;
273	if (mRefs != 0)
274	{
275		llwarns << "Volume group has remaining refs:" << getNumRefs() << llendl;
276		mRefs = 0;
277		for (S32 i = 0; i < NUM_LODS; i++)
278		{
279			if (mLODRefs[i] > 0)
280			{
281				llwarns << " LOD " << i << " refs = " << mLODRefs[i] << llendl;
282				mLODRefs[i] = 0;
283				mVolumeLODs[i] = NULL;
284			}
285		}
286		llwarns << *getVolumeParams() << llendl;
287		res = false;
288	}
289	return res;
290}
291
292LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
293{
294	llassert(detail >=0 && detail < NUM_LODS);
295	mAccessCount[detail]++;
296	
297	mRefs++;
298	if (mVolumeLODs[detail].isNull())
299	{
300		LLMemType m1(LLMemType::MTYPE_VOLUME);
301		mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
302	}
303	mLODRefs[detail]++;
304	return mVolumeLODs[detail];
305}
306
307BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
308{
309	llassert_always(mRefs > 0);
310	mRefs--;
311	for (S32 i = 0; i < NUM_LODS; i++)
312	{
313		if (mVolumeLODs[i] == volumep)
314		{
315			llassert_always(mLODRefs[i] > 0);
316			mLODRefs[i]--;
317#if 0 // SJB: Possible opt: keep other lods around
318			if (!mLODRefs[i])
319			{
320				mVolumeLODs[i] = NULL;
321			}
322#endif
323			return TRUE;
324		}
325	}
326	llerrs << "Deref of non-matching LOD in volume LOD group" << llendl;
327	return FALSE;
328}
329
330S32 LLVolumeLODGroup::getDetailFromTan(const F32 tan_angle)
331{
332	S32 i = 0;
333	while (i < (NUM_LODS - 1))
334	{
335		if (tan_angle <= mDetailThresholds[i])
336		{
337			return i;
338		}
339		i++;
340	}
341	return NUM_LODS - 1;
342}
343
344void LLVolumeLODGroup::getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher)
345{
346	S32 detail = getDetailFromTan(tan_angle);
347	
348	if (detail > 0)
349	{
350		to_lower = tan_angle - mDetailThresholds[detail];
351	}
352	else
353	{
354		to_lower = 1024.f*1024.f;
355	}
356
357	if (detail < NUM_LODS-1)
358	{
359		to_higher = mDetailThresholds[detail+1] - tan_angle;
360	}
361	else
362	{
363		to_higher = 1024.f*1024.f;
364	}
365}
366
367F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
368{
369	return mDetailScales[detail];
370}
371
372S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
373{
374	for (S32 i = 1; i < 4; i++)
375	{
376		if (mDetailScales[i] > detail)
377		{
378			return i-1;
379		}
380	}
381
382	return 3;
383}
384
385F32 LLVolumeLODGroup::dump()
386{
387	F32 usage = 0.f;
388	for (S32 i = 0; i < NUM_LODS; i++)
389	{
390		if (mAccessCount[i] > 0)
391		{
392			usage += 1.f;
393		}
394	}
395	usage = usage / (F32)NUM_LODS;
396
397	std::string dump_str = llformat("%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]);
398
399	llinfos << dump_str << llendl;
400	return usage;
401}
402
403std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup)
404{
405	s << "{ numRefs=" << volgroup.getNumRefs();
406	s << ", mParams=" << volgroup.getVolumeParams();
407	s << " }";
408	 
409	return s;
410}
411