PageRenderTime 27ms CodeModel.GetById 16ms RepoModel.GetById 0ms 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
Possible License(s): LGPL-2.1
  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. const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
  34. const F32 MIN_ATLAS_FULLNESS = 0.6f ;
  35. //*********************************************************************************************
  36. //implementation of class LLTextureAtlasInfo
  37. //*********************************************************************************************
  38. LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) :
  39. mAtlasp(atlasp),
  40. mGroupp(groupp),
  41. mCol(col),
  42. mRow(row),
  43. mReservedSlotWidth(slot_width),
  44. mValid(FALSE),
  45. mUpdatedTime(0),
  46. mTexCoordOffset(xoffset, yoffset),
  47. mTexCoordScale(1.f, 1.f)
  48. {
  49. llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
  50. }
  51. LLTextureAtlasSlot::~LLTextureAtlasSlot()
  52. {
  53. if(mAtlasp)
  54. {
  55. mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
  56. if(mAtlasp->isEmpty())
  57. {
  58. LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
  59. }
  60. mAtlasp = NULL ;
  61. }
  62. }
  63. //void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp)
  64. //{
  65. // mAtlasp = atlasp ;
  66. //}
  67. //void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row)
  68. //{
  69. // mCol = col ;
  70. // mRow = row ;
  71. //}
  72. //void LLTextureAtlasSlot::setSlotWidth(S8 width)
  73. //{
  74. // //slot is a square with each edge length a power-of-two number
  75. // mReservedSlotWidth = width ;
  76. //}
  77. //void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset)
  78. //{
  79. // mTexCoordOffset.mV[0] = xoffset ;
  80. // mTexCoordOffset.mV[1] = yoffset ;
  81. //}
  82. void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp)
  83. {
  84. mGroupp = groupp ;
  85. }
  86. void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale)
  87. {
  88. mTexCoordScale.mV[0] = xscale ;
  89. mTexCoordScale.mV[1] = yscale ;
  90. }
  91. //*********************************************************************************************
  92. //END of implementation of class LLTextureAtlasInfo
  93. //*********************************************************************************************
  94. //*********************************************************************************************
  95. //implementation of class LLTextureAtlasManager
  96. //*********************************************************************************************
  97. LLTextureAtlasManager::LLTextureAtlasManager() :
  98. mAtlasMap(4),
  99. mEmptyAtlasMap(4)
  100. {
  101. }
  102. LLTextureAtlasManager::~LLTextureAtlasManager()
  103. {
  104. for(S32 i = 0 ; i < 4 ; i++)
  105. {
  106. for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
  107. {
  108. *j = NULL ;
  109. }
  110. for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
  111. {
  112. *j = NULL ;
  113. }
  114. mAtlasMap[i].clear() ;
  115. mEmptyAtlasMap[i].clear() ;
  116. }
  117. mAtlasMap.clear() ;
  118. mEmptyAtlasMap.clear() ;
  119. }
  120. //return TRUE if qualified
  121. BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target)
  122. {
  123. if(ncomponents < 1 || ncomponents > 4)
  124. {
  125. return FALSE ;
  126. }
  127. //only support GL_TEXTURE_2D
  128. if(GL_TEXTURE_2D != target)
  129. {
  130. return FALSE ;
  131. }
  132. //real image size overflows
  133. if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
  134. {
  135. return FALSE ;
  136. }
  137. //if non-power-of-two number
  138. if((w & (w - 1)) || (h & (h - 1)))
  139. {
  140. return FALSE ;
  141. }
  142. return TRUE ;
  143. }
  144. void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
  145. {
  146. LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
  147. while(groupp)
  148. {
  149. groupp->removeAtlas(atlasp, FALSE) ;
  150. atlasp->removeLastSpatialGroup() ;
  151. groupp = atlasp->getLastSpatialGroup() ;
  152. }
  153. S8 type = atlasp->getComponents() - 1 ;
  154. //insert to the empty list
  155. if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
  156. {
  157. mEmptyAtlasMap[type].push_back(atlasp) ;
  158. }
  159. //delete the atlasp
  160. mAtlasMap[type].remove(atlasp) ;
  161. }
  162. //
  163. //this function reserves an appropriate slot from atlas pool for an image.
  164. //return non-NULL if succeeds.
  165. //Note:
  166. //1, this function does not check if the image this slot assigned for qualifies for atlas or not,
  167. // call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
  168. //2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
  169. //3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
  170. //
  171. LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents,
  172. LLSpatialGroup* groupp, LLViewerTexture* imagep)
  173. {
  174. if(!groupp)
  175. {
  176. //do not insert to atlas if does not have a group.
  177. return NULL ;
  178. }
  179. //bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
  180. if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
  181. {
  182. sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
  183. }
  184. S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
  185. if(bits_len < 1)
  186. {
  187. bits_len = 1 ;
  188. }
  189. S16 col = -1, row = -1;
  190. S8 total_bits = bits_len * bits_len ;
  191. //insert to the atlas reserved by the same spatial group
  192. LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
  193. if(atlasp.notNull())
  194. {
  195. if(!atlasp->getNextAvailableSlot(bits_len, col, row))
  196. {
  197. //failed
  198. atlasp = NULL ;
  199. }
  200. }
  201. //search an atlas to fit for 'size'
  202. if(!atlasp)
  203. {
  204. S8 atlas_index = ncomponents - 1 ;
  205. ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
  206. for(; iter != mAtlasMap[atlas_index].end(); ++iter)
  207. {
  208. LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
  209. if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
  210. {
  211. if(cur->getNextAvailableSlot(bits_len, col, row))
  212. {
  213. atlasp = cur ;
  214. groupp->addAtlas(atlasp) ;
  215. break ;
  216. }
  217. }
  218. }
  219. }
  220. //create a new atlas if necessary
  221. if(!atlasp)
  222. {
  223. if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
  224. {
  225. //there is an empty one
  226. atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
  227. mEmptyAtlasMap[ncomponents - 1].pop_back() ;
  228. }
  229. else
  230. {
  231. atlasp = new LLTextureAtlas(ncomponents, 16) ;
  232. }
  233. mAtlasMap[ncomponents - 1].push_back(atlasp) ;
  234. atlasp->getNextAvailableSlot(bits_len, col, row) ;
  235. groupp->addAtlas(atlasp) ;
  236. }
  237. F32 xoffset, yoffset ;
  238. atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
  239. LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
  240. return slot_infop ;
  241. }
  242. //*********************************************************************************************
  243. //END of implementation of class LLTextureAtlasManager
  244. //*********************************************************************************************