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 33 namespace WebCore { 34 35 static 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 41 TextureManager::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 50 TextureToken TextureManager::getToken() 51 { 52 return m_nextToken++; 53 } 54 55 void 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 62 bool 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 73 bool TextureManager::isProtected(TextureToken token) 74 { 75 return token && hasTexture(token) && m_textures.get(token).isProtected; 76 } 77 78 void TextureManager::protectTexture(TextureToken token) 79 { 80 ASSERT(hasTexture(token)); 81 ASSERT(!m_textures.get(token).isProtected); 82 TextureInfo info = m_textures.take(token); 83 info.isProtected = true; 84 m_textures.add(token, info); 85 } 86 87 void TextureManager::unprotectAllTextures() 88 { 89 for (TextureMap::iterator it = m_textures.begin(); it != m_textures.end(); ++it) 90 it->second.isProtected = false; 91 } 92 93 bool TextureManager::reduceMemoryToLimit(size_t limit) 94 { 95 while (m_memoryUseBytes > limit) { 96 ASSERT(!m_textureLRUSet.isEmpty()); 97 bool foundCandidate = false; 98 for (ListHashSet<TextureToken>::iterator lruIt = m_textureLRUSet.begin(); lruIt != m_textureLRUSet.end(); ++lruIt) { 99 TextureToken token = *lruIt; 100 TextureInfo info = m_textures.get(token); 101 if (info.isProtected) 102 continue; 103 removeTexture(token, info); 104 foundCandidate = true; 105 break; 106 } 107 if (!foundCandidate) 108 return false; 109 } 110 return true; 111 } 112 113 void TextureManager::addTexture(TextureToken token, TextureInfo info) 114 { 115 ASSERT(!m_textureLRUSet.contains(token)); 116 ASSERT(!m_textures.contains(token)); 117 m_memoryUseBytes += memoryUseBytes(info.size, info.format); 118 m_textures.set(token, info); 119 m_textureLRUSet.add(token); 120 } 121 122 void TextureManager::removeTexture(TextureToken token, TextureInfo info) 123 { 124 ASSERT(m_textureLRUSet.contains(token)); 125 ASSERT(m_textures.contains(token)); 126 m_memoryUseBytes -= memoryUseBytes(info.size, info.format); 127 m_textures.remove(token); 128 ASSERT(m_textureLRUSet.contains(token)); 129 m_textureLRUSet.remove(token); 130 GLC(m_context.get(), m_context->deleteTexture(info.textureId)); 131 } 132 133 unsigned TextureManager::requestTexture(TextureToken token, IntSize size, unsigned format, bool* newTexture) 134 { 135 if (size.width() > m_maxTextureSize || size.height() > m_maxTextureSize) 136 return 0; 137 138 TextureMap::iterator it = m_textures.find(token); 139 if (it != m_textures.end()) { 140 ASSERT(it->second.size != size || it->second.format != format); 141 removeTexture(token, it->second); 142 } 143 144 size_t memoryRequiredBytes = memoryUseBytes(size, format); 145 if (memoryRequiredBytes > m_memoryLimitBytes || !reduceMemoryToLimit(m_memoryLimitBytes - memoryRequiredBytes)) 146 return 0; 147 148 unsigned textureId; 149 GLC(m_context.get(), textureId = m_context->createTexture()); 150 GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId)); 151 // Do basic linear filtering on resize. 152 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); 153 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); 154 // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE. 155 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); 156 GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); 157 GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, GraphicsContext3D::UNSIGNED_BYTE)); 158 TextureInfo info; 159 info.size = size; 160 info.format = format; 161 info.textureId = textureId; 162 info.isProtected = true; 163 addTexture(token, info); 164 return textureId; 165 } 166 167 } 168 169 #endif // USE(ACCELERATED_COMPOSITING) 170