OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
| 3 * |
| 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions |
| 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the |
| 11 * documentation and/or other materials provided with the distribution. |
| 12 * |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y |
| 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N |
| 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 23 */ |
| 24 |
| 25 #include "config.h" |
| 26 |
| 27 #if USE(ACCELERATED_COMPOSITING) |
| 28 |
| 29 #include "TextureManager.h" |
| 30 |
| 31 #include "ManagedTexture.h" |
| 32 #include "TraceEvent.h" |
| 33 |
| 34 using namespace std; |
| 35 |
| 36 namespace WebCore { |
| 37 |
| 38 |
| 39 namespace { |
| 40 size_t memoryLimitBytes(size_t viewportMultiplier, const IntSize& viewportSize,
size_t minMegabytes, size_t maxMegabytes) |
| 41 { |
| 42 if (!viewportMultiplier) |
| 43 return maxMegabytes * 1024 * 1024; |
| 44 if (viewportSize.isEmpty()) |
| 45 return minMegabytes * 1024 * 1024; |
| 46 return max(minMegabytes * 1024 * 1024, min(maxMegabytes * 1024 * 1024, viewp
ortMultiplier * TextureManager::memoryUseBytes(viewportSize, GL_RGBA))); |
| 47 } |
| 48 } |
| 49 |
| 50 size_t TextureManager::highLimitBytes(const IntSize& viewportSize) |
| 51 { |
| 52 size_t viewportMultiplier, minMegabytes, maxMegabytes; |
| 53 #if OS(ANDROID) |
| 54 viewportMultiplier = 16; |
| 55 minMegabytes = 32; |
| 56 maxMegabytes = 64; |
| 57 #else |
| 58 viewportMultiplier = 0; |
| 59 minMegabytes = 0; |
| 60 maxMegabytes = 128; |
| 61 #endif |
| 62 return memoryLimitBytes(viewportMultiplier, viewportSize, minMegabytes, maxM
egabytes); |
| 63 } |
| 64 |
| 65 size_t TextureManager::reclaimLimitBytes(const IntSize& viewportSize) |
| 66 { |
| 67 size_t viewportMultiplier, minMegabytes, maxMegabytes; |
| 68 #if OS(ANDROID) |
| 69 viewportMultiplier = 8; |
| 70 minMegabytes = 16; |
| 71 maxMegabytes = 32; |
| 72 #else |
| 73 viewportMultiplier = 0; |
| 74 minMegabytes = 0; |
| 75 maxMegabytes = 64; |
| 76 #endif |
| 77 return memoryLimitBytes(viewportMultiplier, viewportSize, minMegabytes, maxM
egabytes); |
| 78 } |
| 79 |
| 80 size_t TextureManager::memoryUseBytes(const IntSize& size, GC3Denum textureForma
t) |
| 81 { |
| 82 // FIXME: This assumes all textures are 1 byte/component. |
| 83 const GC3Denum type = GL_UNSIGNED_BYTE; |
| 84 unsigned int componentsPerPixel = 4; |
| 85 unsigned int bytesPerComponent = 1; |
| 86 |
| 87 return size.width() * size.height() * componentsPerPixel * bytesPerComponent
; |
| 88 } |
| 89 |
| 90 |
| 91 TextureManager::TextureManager(size_t maxMemoryLimitBytes, size_t preferredMemor
yLimitBytes, int maxTextureSize) |
| 92 : m_maxMemoryLimitBytes(maxMemoryLimitBytes) |
| 93 , m_preferredMemoryLimitBytes(preferredMemoryLimitBytes) |
| 94 , m_memoryUseBytes(0) |
| 95 , m_maxTextureSize(maxTextureSize) |
| 96 , m_nextToken(1) |
| 97 { |
| 98 } |
| 99 |
| 100 TextureManager::~TextureManager() |
| 101 { |
| 102 for (HashSet<ManagedTexture*>::iterator it = m_registeredTextures.begin(); i
t != m_registeredTextures.end(); ++it) |
| 103 (*it)->clearManager(); |
| 104 } |
| 105 |
| 106 void TextureManager::setMemoryAllocationLimitBytes(size_t memoryLimitBytes) |
| 107 { |
| 108 setMaxMemoryLimitBytes(memoryLimitBytes); |
| 109 #if defined(OS_ANDROID) |
| 110 // On android, we are setting the preferred memory limit to half of our |
| 111 // maximum allocation, because we would like to stay significantly below |
| 112 // the absolute memory limit whenever we can. Specifically, by limitting |
| 113 // prepainting only to the halfway memory mark. |
| 114 setPreferredMemoryLimitBytes(memoryLimitBytes / 2); |
| 115 #else |
| 116 setPreferredMemoryLimitBytes(memoryLimitBytes); |
| 117 #endif |
| 118 } |
| 119 |
| 120 void TextureManager::setMaxMemoryLimitBytes(size_t memoryLimitBytes) |
| 121 { |
| 122 reduceMemoryToLimit(memoryLimitBytes); |
| 123 ASSERT(currentMemoryUseBytes() <= memoryLimitBytes); |
| 124 m_maxMemoryLimitBytes = memoryLimitBytes; |
| 125 } |
| 126 |
| 127 void TextureManager::setPreferredMemoryLimitBytes(size_t memoryLimitBytes) |
| 128 { |
| 129 m_preferredMemoryLimitBytes = memoryLimitBytes; |
| 130 } |
| 131 |
| 132 void TextureManager::registerTexture(ManagedTexture* texture) |
| 133 { |
| 134 ASSERT(texture); |
| 135 ASSERT(!m_registeredTextures.contains(texture)); |
| 136 |
| 137 m_registeredTextures.add(texture); |
| 138 } |
| 139 |
| 140 void TextureManager::unregisterTexture(ManagedTexture* texture) |
| 141 { |
| 142 ASSERT(texture); |
| 143 ASSERT(m_registeredTextures.contains(texture)); |
| 144 |
| 145 m_registeredTextures.remove(texture); |
| 146 } |
| 147 |
| 148 TextureToken TextureManager::getToken() |
| 149 { |
| 150 return m_nextToken++; |
| 151 } |
| 152 |
| 153 void TextureManager::releaseToken(TextureToken token) |
| 154 { |
| 155 TextureMap::iterator it = m_textures.find(token); |
| 156 if (it != m_textures.end()) |
| 157 removeTexture(token, it->second); |
| 158 } |
| 159 |
| 160 bool TextureManager::hasTexture(TextureToken token) |
| 161 { |
| 162 return m_textures.contains(token); |
| 163 } |
| 164 |
| 165 bool TextureManager::isProtected(TextureToken token) |
| 166 { |
| 167 return token && hasTexture(token) && m_textures.get(token).isProtected; |
| 168 } |
| 169 |
| 170 void TextureManager::protectTexture(TextureToken token) |
| 171 { |
| 172 ASSERT(hasTexture(token)); |
| 173 TextureInfo info = m_textures.take(token); |
| 174 info.isProtected = true; |
| 175 m_textures.add(token, info); |
| 176 // If someone protects a texture, put it at the end of the LRU list. |
| 177 m_textureLRUSet.remove(token); |
| 178 m_textureLRUSet.add(token); |
| 179 } |
| 180 |
| 181 void TextureManager::unprotectTexture(TextureToken token) |
| 182 { |
| 183 TextureMap::iterator it = m_textures.find(token); |
| 184 if (it != m_textures.end()) |
| 185 it->second.isProtected = false; |
| 186 } |
| 187 |
| 188 void TextureManager::unprotectAllTextures() |
| 189 { |
| 190 for (TextureMap::iterator it = m_textures.begin(); it != m_textures.end(); +
+it) |
| 191 it->second.isProtected = false; |
| 192 } |
| 193 |
| 194 void TextureManager::evictTexture(TextureToken token, TextureInfo info) |
| 195 { |
| 196 TRACE_EVENT0("cc", "TextureManager::evictTexture"); |
| 197 removeTexture(token, info); |
| 198 } |
| 199 |
| 200 void TextureManager::reduceMemoryToLimit(size_t limit) |
| 201 { |
| 202 while (m_memoryUseBytes > limit) { |
| 203 ASSERT(!m_textureLRUSet.isEmpty()); |
| 204 bool foundCandidate = false; |
| 205 for (ListHashSet<TextureToken>::iterator lruIt = m_textureLRUSet.begin()
; lruIt != m_textureLRUSet.end(); ++lruIt) { |
| 206 TextureToken token = *lruIt; |
| 207 TextureInfo info = m_textures.get(token); |
| 208 if (info.isProtected) |
| 209 continue; |
| 210 evictTexture(token, info); |
| 211 foundCandidate = true; |
| 212 break; |
| 213 } |
| 214 if (!foundCandidate) |
| 215 return; |
| 216 } |
| 217 } |
| 218 |
| 219 void TextureManager::addTexture(TextureToken token, TextureInfo info) |
| 220 { |
| 221 ASSERT(!m_textureLRUSet.contains(token)); |
| 222 ASSERT(!m_textures.contains(token)); |
| 223 m_memoryUseBytes += memoryUseBytes(info.size, info.format); |
| 224 m_textures.set(token, info); |
| 225 m_textureLRUSet.add(token); |
| 226 } |
| 227 |
| 228 void TextureManager::deleteEvictedTextures(TextureAllocator* allocator) |
| 229 { |
| 230 if (allocator) { |
| 231 for (size_t i = 0; i < m_evictedTextures.size(); ++i) { |
| 232 if (m_evictedTextures[i].textureId) { |
| 233 #ifndef NDEBUG |
| 234 ASSERT(m_evictedTextures[i].allocator == allocator); |
| 235 #endif |
| 236 allocator->deleteTexture(m_evictedTextures[i].textureId, m_evict
edTextures[i].size, m_evictedTextures[i].format); |
| 237 } |
| 238 } |
| 239 } |
| 240 m_evictedTextures.clear(); |
| 241 } |
| 242 |
| 243 void TextureManager::evictAndRemoveAllDeletedTextures() |
| 244 { |
| 245 unprotectAllTextures(); |
| 246 reduceMemoryToLimit(0); |
| 247 m_evictedTextures.clear(); |
| 248 } |
| 249 |
| 250 void TextureManager::evictAndDeleteAllTextures(TextureAllocator* allocator) |
| 251 { |
| 252 unprotectAllTextures(); |
| 253 reduceMemoryToLimit(0); |
| 254 deleteEvictedTextures(allocator); |
| 255 } |
| 256 |
| 257 void TextureManager::removeTexture(TextureToken token, TextureInfo info) |
| 258 { |
| 259 ASSERT(m_textureLRUSet.contains(token)); |
| 260 ASSERT(m_textures.contains(token)); |
| 261 m_memoryUseBytes -= memoryUseBytes(info.size, info.format); |
| 262 m_textures.remove(token); |
| 263 ASSERT(m_textureLRUSet.contains(token)); |
| 264 m_textureLRUSet.remove(token); |
| 265 EvictionEntry entry; |
| 266 entry.textureId = info.textureId; |
| 267 entry.size = info.size; |
| 268 entry.format = info.format; |
| 269 #ifndef NDEBUG |
| 270 entry.allocator = info.allocator; |
| 271 #endif |
| 272 m_evictedTextures.append(entry); |
| 273 } |
| 274 |
| 275 unsigned TextureManager::allocateTexture(TextureAllocator* allocator, TextureTok
en token) |
| 276 { |
| 277 TextureMap::iterator it = m_textures.find(token); |
| 278 ASSERT(it != m_textures.end()); |
| 279 TextureInfo* info = &it.get()->second; |
| 280 ASSERT(info->isProtected); |
| 281 |
| 282 unsigned textureId = allocator->createTexture(info->size, info->format); |
| 283 info->textureId = textureId; |
| 284 #ifndef NDEBUG |
| 285 info->allocator = allocator; |
| 286 #endif |
| 287 return textureId; |
| 288 } |
| 289 |
| 290 bool TextureManager::requestTexture(TextureToken token, IntSize size, unsigned f
ormat) |
| 291 { |
| 292 if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) |
| 293 return false; |
| 294 |
| 295 TextureMap::iterator it = m_textures.find(token); |
| 296 if (it != m_textures.end()) { |
| 297 ASSERT(it->second.size != size || it->second.format != format); |
| 298 removeTexture(token, it->second); |
| 299 } |
| 300 |
| 301 size_t memoryRequiredBytes = memoryUseBytes(size, format); |
| 302 if (memoryRequiredBytes > m_maxMemoryLimitBytes) |
| 303 return false; |
| 304 |
| 305 reduceMemoryToLimit(m_maxMemoryLimitBytes - memoryRequiredBytes); |
| 306 if (m_memoryUseBytes + memoryRequiredBytes > m_maxMemoryLimitBytes) |
| 307 return false; |
| 308 |
| 309 TextureInfo info; |
| 310 info.size = size; |
| 311 info.format = format; |
| 312 info.textureId = 0; |
| 313 info.isProtected = true; |
| 314 #ifndef NDEBUG |
| 315 info.allocator = 0; |
| 316 #endif |
| 317 addTexture(token, info); |
| 318 return true; |
| 319 } |
| 320 |
| 321 } |
| 322 |
| 323 #endif // USE(ACCELERATED_COMPOSITING) |
OLD | NEW |