TextureManager.cpp revision cad810f21b803229eb11403f9209855525a25d57
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 ANY 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 ANY 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 ON 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 "LayerRendererChromium.h" 32 33namespace WebCore { 34 35static size_t memoryUseBytes(IntSize size, unsigned textureFormat) 36{ 37 // FIXME: This assumes all textures are 4 bytes/pixel, like RGBA. 38 return size.width() * size.height() * 4; 39} 40 41TextureManager::TextureManager(GraphicsContext3D* context, size_t memoryLimitBytes, int maxTextureSize) 42 : m_context(context) 43 , m_memoryLimitBytes(memoryLimitBytes) 44 , m_memoryUseBytes(0) 45 , m_maxTextureSize(maxTextureSize) 46 , m_nextToken(1) 47{ 48} 49 50TextureToken TextureManager::getToken() 51{ 52 return m_nextToken++; 53} 54 55void TextureManager::releaseToken(TextureToken token) 56{ 57 TextureMap::iterator it = m_textures.find(token); 58 if (it != m_textures.end()) 59 removeTexture(token, it->second); 60} 61 62bool TextureManager::hasTexture(TextureToken token) 63{ 64 if (m_textures.contains(token)) { 65 // If someone asks about a texture put it at the end of the LRU list. 66 m_textureLRUSet.remove(token); 67 m_textureLRUSet.add(token); 68 return true; 69 } 70 return false; 71} 72 73void TextureManager::protectTexture(TextureToken token) 74{ 75 ASSERT(hasTexture(token)); 76 ASSERT(!m_textures.get(token).isProtected); 77 TextureInfo info = m_textures.take(token); 78 info.isProtected = true; 79 m_textures.add(token, info); 80} 81 82void TextureManager::unprotectTexture(TextureToken token) 83{ 84 TextureMap::iterator it = m_textures.find(token); 85 if (it != m_textures.end()) { 86 TextureInfo info = it->second; 87 if (info.isProtected) { 88 info.isProtected = false; 89 m_textures.remove(it); 90 m_textures.add(token, info); 91 } 92 } 93} 94 95bool TextureManager::reduceMemoryToLimit(size_t limit) 96{ 97 while (m_memoryUseBytes > limit) { 98 ASSERT(!m_textureLRUSet.isEmpty()); 99 bool foundCandidate = false; 100 for (ListHashSet<TextureToken>::iterator lruIt = m_textureLRUSet.begin(); lruIt != m_textureLRUSet.end(); ++lruIt) { 101 TextureToken token = *lruIt; 102 TextureInfo info = m_textures.get(token); 103 if (info.isProtected) 104 continue; 105 removeTexture(token, info); 106 foundCandidate = true; 107 break; 108 } 109 if (!foundCandidate) 110 return false; 111 } 112 return true; 113} 114 115void TextureManager::addTexture(TextureToken token, TextureInfo info) 116{ 117 ASSERT(!m_textureLRUSet.contains(token)); 118 ASSERT(!m_textures.contains(token)); 119 m_memoryUseBytes += memoryUseBytes(info.size, info.format); 120 m_textures.set(token, info); 121 m_textureLRUSet.add(token); 122} 123 124void TextureManager::removeTexture(TextureToken token, TextureInfo info) 125{ 126 ASSERT(m_textureLRUSet.contains(token)); 127 ASSERT(m_textures.contains(token)); 128 m_memoryUseBytes -= memoryUseBytes(info.size, info.format); 129 m_textures.remove(token); 130 ASSERT(m_textureLRUSet.contains(token)); 131 m_textureLRUSet.remove(token); 132 GLC(m_context.get(), m_context->deleteTexture(info.textureId)); 133} 134 135unsigned TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format, bool* newTexture) 136{ 137 if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) 138 return 0; 139 140 TextureMap::iterator it = m_textures.find(token); 141 if (it != m_textures.end()) { 142 ASSERT(it->second.size != size || it->second.format != format); 143 removeTexture(token, it->second); 144 } 145 146 size_t memoryRequiredBytes = memoryUseBytes(size, format); 147 if (memoryRequiredBytes > m_memoryLimitBytes || !reduceMemoryToLimit(m_memoryLimitBytes - memoryRequiredBytes)) 148 return 0; 149 150 unsigned textureId = m_context->createTexture(); 151 GLC(m_context.get(), textureId = m_context->createTexture()); 152 GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); 153 // Do basic linear filtering on resize. 154 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); 155 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); 156 // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE. 157 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); 158 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); 159 GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE)); 160 TextureInfo info; 161 info.size = size; 162 info.format = format; 163 info.textureId = textureId; 164 info.isProtected = true; 165 addTexture(token, info); 166 return textureId; 167} 168 169} 170 171#endif // USE(ACCELERATED_COMPOSITING) 172