void CCPrioritizedTextureManager::reduceMemory(size_t limitBytes, CCResourceProvider* resourceProvider) { if (memoryUseBytes() <= limitBytes) return; // Destroy backings until we are below the limit, // or until all backings remaining are above the cutoff. while (memoryUseBytes() > limitBytes && m_backings.size() > 0) { BackingSet::iterator it = m_backings.begin(); if ((*it)->owner() && (*it)->owner()->isAbovePriorityCutoff()) break; destroyBacking((*it), resourceProvider); } }
unsigned TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format, bool* newTexture) { if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) return 0; TextureMap::iterator it = m_textures.find(token); if (it != m_textures.end()) { ASSERT(it->second.size != size || it->second.format != format); removeTexture(token, it->second); } size_t memoryRequiredBytes = memoryUseBytes(size, format); if (memoryRequiredBytes > m_memoryLimitBytes || !reduceMemoryToLimit(m_memoryLimitBytes - memoryRequiredBytes)) return 0; unsigned textureId = m_context->createTexture(); GLC(m_context.get(), textureId = m_context->createTexture()); GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); // Do basic linear filtering on resize. GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE. GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE)); TextureInfo info; info.size = size; info.format = format; info.textureId = textureId; info.isProtected = true; addTexture(token, info); return textureId; }
bool TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format) { if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) return false; TextureMap::iterator it = m_textures.find(token); if (it != m_textures.end()) { ASSERT(it->second.size != size || it->second.format != format); removeTexture(token, it->second); } size_t memoryRequiredBytes = memoryUseBytes(size, format); if (memoryRequiredBytes > m_maxMemoryLimitBytes) return false; reduceMemoryToLimit(m_maxMemoryLimitBytes - memoryRequiredBytes); if (m_memoryUseBytes + memoryRequiredBytes > m_maxMemoryLimitBytes) return false; TextureInfo info; info.size = size; info.format = format; info.textureId = 0; info.isProtected = true; #ifndef NDEBUG info.allocator = 0; #endif addTexture(token, info); return true; }
void TextureManager::addTexture(TextureToken token, TextureInfo info) { ASSERT(!m_textureLRUSet.contains(token)); ASSERT(!m_textures.contains(token)); m_memoryUseBytes += memoryUseBytes(info.size, info.format); m_textures.set(token, info); m_textureLRUSet.add(token); }
void TextureManager::removeTexture(TextureToken token, TextureInfo info) { ASSERT(m_textureLRUSet.contains(token)); ASSERT(m_textures.contains(token)); m_memoryUseBytes -= memoryUseBytes(info.size, info.format); m_textures.remove(token); ASSERT(m_textureLRUSet.contains(token)); m_textureLRUSet.remove(token); GLC(m_context.get(), m_context->deleteTexture(info.textureId)); }
void CCPrioritizedTextureManager::reduceMemory(CCResourceProvider* resourceProvider) { reduceMemory(m_memoryAvailableBytes, resourceProvider); ASSERT(memoryUseBytes() <= maxMemoryLimitBytes()); // We currently collect backings from deleted textures for later recycling. // However, if we do that forever we will always use the max limit even if // we really need very little memory. This should probably be solved by reducing the // limit externally, but until then this just does some "clean up" of unused // backing textures (any more than 10%). size_t wastedMemory = 0; for (BackingSet::iterator it = m_backings.begin(); it != m_backings.end(); ++it) { if ((*it)->owner()) break; wastedMemory += (*it)->bytes(); } size_t tenPercentOfMemory = m_memoryAvailableBytes / 10; if (wastedMemory <= tenPercentOfMemory) return; reduceMemory(memoryUseBytes() - (wastedMemory - tenPercentOfMemory), resourceProvider); }
void TextureManager::removeTexture(TextureToken token, TextureInfo info) { ASSERT(m_textureLRUSet.contains(token)); ASSERT(m_textures.contains(token)); m_memoryUseBytes -= memoryUseBytes(info.size, info.format); m_textures.remove(token); ASSERT(m_textureLRUSet.contains(token)); m_textureLRUSet.remove(token); EvictionEntry entry; entry.textureId = info.textureId; entry.size = info.size; entry.format = info.format; #ifndef NDEBUG entry.allocator = info.allocator; #endif m_evictedTextures.append(entry); }
bool TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format, unsigned& textureId) { textureId = 0; if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) return false; TextureMap::iterator it = m_textures.find(token); if (it != m_textures.end()) { ASSERT(it->second.size != size || it->second.format != format); removeTexture(token, it->second); } size_t memoryRequiredBytes = memoryUseBytes(size, format); if (memoryRequiredBytes > m_maxMemoryLimitBytes) return false; reduceMemoryToLimit(m_maxMemoryLimitBytes - memoryRequiredBytes); if (m_memoryUseBytes + memoryRequiredBytes > m_maxMemoryLimitBytes) return false; TextureInfo info; info.size = size; info.format = format; info.textureId = 0; info.isProtected = true; #ifndef NDEBUG info.allocator = 0; #endif // Avoid churning by reusing the texture if it is about to be reclaimed and // it has the same size and format as the requesting texture. if (m_memoryUseBytes + memoryRequiredBytes > m_preferredMemoryLimitBytes) { textureId = replaceTexture(token, info); if (textureId) return true; } addTexture(token, info); return true; }