PageRenderTime 416ms CodeModel.GetById 211ms app.highlight 72ms RepoModel.GetById 129ms app.codeStats 0ms

/indra/newview/lltextureatlasmanager.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 268 lines | 166 code | 24 blank | 78 comment | 32 complexity | 2ea71aa5b82bc072202ff1e70a157eac MD5 | raw file
  1/** 
  2 * @file lltextureatlasmanager.cpp
  3 * @brief LLTextureAtlasManager class implementation.
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26#include "llviewerprecompiledheaders.h"
 27#include "linden_common.h"
 28#include "llerror.h"
 29#include "llmath.h"
 30#include "lltextureatlas.h"
 31#include "lltextureatlasmanager.h"
 32#include "llspatialpartition.h"
 33
 34const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
 35const F32 MIN_ATLAS_FULLNESS = 0.6f ;
 36
 37//*********************************************************************************************
 38//implementation of class LLTextureAtlasInfo
 39//*********************************************************************************************
 40LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) : 
 41	mAtlasp(atlasp),
 42	mGroupp(groupp),
 43	mCol(col),
 44	mRow(row),
 45	mReservedSlotWidth(slot_width),
 46	mValid(FALSE),
 47	mUpdatedTime(0),
 48	mTexCoordOffset(xoffset, yoffset),
 49	mTexCoordScale(1.f, 1.f)
 50{
 51	llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
 52}
 53
 54LLTextureAtlasSlot::~LLTextureAtlasSlot()
 55{
 56	if(mAtlasp)
 57	{
 58		mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
 59		if(mAtlasp->isEmpty())
 60		{
 61			LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
 62		}
 63		mAtlasp = NULL ;
 64	}
 65}
 66
 67//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp) 
 68//{
 69//	mAtlasp = atlasp ;
 70//}
 71//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row) 
 72//{
 73//	mCol = col ;
 74//	mRow = row ;
 75//}
 76//void LLTextureAtlasSlot::setSlotWidth(S8 width) 
 77//{
 78//	//slot is a square with each edge length a power-of-two number
 79//	mReservedSlotWidth = width ;
 80//}
 81//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset) 
 82//{
 83//	mTexCoordOffset.mV[0] = xoffset ;
 84//	mTexCoordOffset.mV[1] = yoffset ;
 85//}
 86
 87void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) 
 88{
 89	mGroupp = groupp ;
 90}
 91void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale) 
 92{
 93	mTexCoordScale.mV[0] = xscale ;
 94	mTexCoordScale.mV[1] = yscale ;
 95}
 96//*********************************************************************************************
 97//END of implementation of class LLTextureAtlasInfo
 98//*********************************************************************************************
 99
100//*********************************************************************************************
101//implementation of class LLTextureAtlasManager
102//*********************************************************************************************
103LLTextureAtlasManager::LLTextureAtlasManager() :
104	mAtlasMap(4),
105	mEmptyAtlasMap(4) 
106{
107}
108
109LLTextureAtlasManager::~LLTextureAtlasManager()
110{
111	for(S32 i = 0 ; i < 4 ; i++)
112	{
113		for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
114		{
115			*j = NULL ;
116		}
117		for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
118		{
119			*j = NULL ;
120		}
121
122		mAtlasMap[i].clear() ;
123		mEmptyAtlasMap[i].clear() ;
124	}
125	mAtlasMap.clear() ;
126	mEmptyAtlasMap.clear() ;
127}
128
129//return TRUE if qualified
130BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) 
131{
132	if(ncomponents < 1 || ncomponents > 4)
133	{
134		return FALSE ;
135	}
136	//only support GL_TEXTURE_2D
137	if(GL_TEXTURE_2D != target)
138	{
139		return FALSE ;
140	}
141	//real image size overflows
142	if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
143	{
144		return FALSE ;
145	}
146
147	//if non-power-of-two number
148	if((w & (w - 1)) || (h & (h - 1)))
149	{
150		return FALSE ;
151	}
152
153	return TRUE ;
154}
155
156void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
157{	
158	LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
159	while(groupp)
160	{
161		groupp->removeAtlas(atlasp, FALSE) ;
162		atlasp->removeLastSpatialGroup() ;
163
164		groupp = atlasp->getLastSpatialGroup() ;
165	}
166
167	S8 type = atlasp->getComponents() - 1 ;	
168	//insert to the empty list
169	if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
170	{					
171		mEmptyAtlasMap[type].push_back(atlasp) ;
172	}
173		
174	//delete the atlasp
175	mAtlasMap[type].remove(atlasp) ;
176}
177
178//
179//this function reserves an appropriate slot from atlas pool for an image.
180//return non-NULL if succeeds.
181//Note:
182//1, this function does not check if the image this slot assigned for qualifies for atlas or not, 
183//       call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
184//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
185//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
186//
187LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
188																		  LLSpatialGroup* groupp, LLViewerTexture* imagep)
189{
190	if(!groupp)
191	{
192		//do not insert to atlas if does not have a group.
193		return NULL ;
194	}
195
196	//bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
197	if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
198	{
199		sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
200	}
201	S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
202	if(bits_len < 1)
203	{
204	   bits_len = 1 ;
205	}
206		
207	S16 col = -1, row = -1;
208	S8 total_bits = bits_len * bits_len ;
209
210	//insert to the atlas reserved by the same spatial group
211	LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
212	if(atlasp.notNull())
213	{
214		if(!atlasp->getNextAvailableSlot(bits_len, col, row))
215		{
216			//failed
217			atlasp = NULL ;
218		}		
219	}
220
221   //search an atlas to fit for 'size'
222	if(!atlasp)
223	{
224		S8 atlas_index = ncomponents - 1 ;
225		ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
226		for(; iter != mAtlasMap[atlas_index].end(); ++iter) 
227		{
228			LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
229			if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
230			{
231				if(cur->getNextAvailableSlot(bits_len, col, row))
232				{
233					atlasp = cur ;
234					groupp->addAtlas(atlasp) ;				
235					break ;
236				}
237			}
238		}
239	}
240
241	//create a new atlas if necessary
242	if(!atlasp)
243	{
244		if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
245		{
246			//there is an empty one
247			atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
248			mEmptyAtlasMap[ncomponents - 1].pop_back() ;
249		}
250		else
251		{
252			atlasp = new LLTextureAtlas(ncomponents, 16) ;
253		}
254		mAtlasMap[ncomponents - 1].push_back(atlasp) ;
255		atlasp->getNextAvailableSlot(bits_len, col, row) ;		
256		groupp->addAtlas(atlasp) ;
257	}
258
259	F32 xoffset, yoffset ;
260	atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
261	LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
262	
263	return slot_infop ;
264}
265
266//*********************************************************************************************
267//END of implementation of class LLTextureAtlasManager
268//*********************************************************************************************