1 /* 2 * Copyright 2010, The Android Open Source Project 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 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * 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 THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "BaseTileTexture.h" 28 29 #include "BaseTile.h" 30 #include "ClassTracker.h" 31 #include "DeleteTextureOperation.h" 32 #include "GLUtils.h" 33 #include "TilesManager.h" 34 35 #include <cutils/log.h> 36 #include <wtf/text/CString.h> 37 38 #undef XLOGC 39 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "BaseTileTexture", __VA_ARGS__) 40 41 #ifdef DEBUG 42 43 #undef XLOG 44 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseTileTexture", __VA_ARGS__) 45 46 #else 47 48 #undef XLOG 49 #define XLOG(...) 50 51 #endif // DEBUG 52 53 namespace WebCore { 54 55 BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h) 56 : DoubleBufferedTexture(eglGetCurrentContext(), 57 TilesManager::instance()->getSharedTextureMode()) 58 , m_owner(0) 59 , m_busy(false) 60 { 61 m_size.set(w, h); 62 m_ownTextureId = 0; 63 64 // Make sure they are created on the UI thread. 65 TilesManager::instance()->transferQueue()->initSharedSurfaceTextures(w, h); 66 67 #ifdef DEBUG_COUNT 68 ClassTracker::instance()->increment("BaseTileTexture"); 69 #endif 70 } 71 72 BaseTileTexture::~BaseTileTexture() 73 { 74 if (m_sharedTextureMode == EglImageMode) { 75 SharedTexture* textures[3] = { m_textureA, m_textureB, 0 }; 76 destroyTextures(textures); 77 } 78 #ifdef DEBUG_COUNT 79 ClassTracker::instance()->decrement("BaseTileTexture"); 80 #endif 81 } 82 83 void BaseTileTexture::requireGLTexture() 84 { 85 if (!m_ownTextureId) 86 m_ownTextureId = GLUtils::createBaseTileGLTexture(m_size.width(), m_size.height()); 87 } 88 89 void BaseTileTexture::discardGLTexture() 90 { 91 if (m_ownTextureId) 92 GLUtils::deleteTexture(&m_ownTextureId); 93 94 if (m_owner) { 95 // clear both Tile->Texture and Texture->Tile links 96 m_owner->removeTexture(this); 97 release(m_owner); 98 } 99 } 100 101 void BaseTileTexture::destroyTextures(SharedTexture** textures) 102 { 103 int x = 0; 104 while (textures[x]) { 105 // We need to delete the source texture and EGLImage in the texture 106 // generation thread. In theory we should be able to delete the EGLImage 107 // from either thread, but it currently throws an error if not deleted 108 // in the same EGLContext from which it was created. 109 textures[x]->lock(); 110 DeleteTextureOperation* operation = new DeleteTextureOperation( 111 textures[x]->getSourceTextureId(), textures[x]->getEGLImage()); 112 textures[x]->unlock(); 113 TilesManager::instance()->scheduleOperation(operation); 114 x++; 115 } 116 } 117 118 TextureInfo* BaseTileTexture::producerLock() 119 { 120 m_busyLock.lock(); 121 m_busy = true; 122 m_busyLock.unlock(); 123 return DoubleBufferedTexture::producerLock(); 124 } 125 126 void BaseTileTexture::producerRelease() 127 { 128 DoubleBufferedTexture::producerRelease(); 129 setNotBusy(); 130 } 131 132 void BaseTileTexture::producerReleaseAndSwap() 133 { 134 DoubleBufferedTexture::producerReleaseAndSwap(); 135 setNotBusy(); 136 } 137 138 void BaseTileTexture::setNotBusy() 139 { 140 android::Mutex::Autolock lock(m_busyLock); 141 m_busy = false; 142 m_busyCond.signal(); 143 } 144 145 bool BaseTileTexture::busy() 146 { 147 android::Mutex::Autolock lock(m_busyLock); 148 return m_busy; 149 } 150 151 void BaseTileTexture::producerUpdate(TextureInfo* textureInfo, const SkBitmap& bitmap) 152 { 153 // no need to upload a texture since the bitmap is empty 154 if (!bitmap.width() && !bitmap.height()) { 155 producerRelease(); 156 return; 157 } 158 159 // After the tiled layer checked in, this is not called anyway. 160 // TODO: cleanup the old code path for layer painting 161 // GLUtils::paintTextureWithBitmap(info, m_size, bitmap, 0, 0); 162 163 producerReleaseAndSwap(); 164 } 165 166 bool BaseTileTexture::acquire(TextureOwner* owner, bool force) 167 { 168 if (m_owner == owner) 169 return true; 170 171 return setOwner(owner, force); 172 } 173 174 bool BaseTileTexture::setOwner(TextureOwner* owner, bool force) 175 { 176 // if the writable texture is busy (i.e. currently being written to) then we 177 // can't change the owner out from underneath that texture 178 m_busyLock.lock(); 179 while (m_busy && force) 180 m_busyCond.wait(m_busyLock); 181 bool busy = m_busy; 182 m_busyLock.unlock(); 183 184 if (!busy) { 185 // if we are not busy we can try to remove the texture from the layer; 186 // LayerAndroid::removeTexture() is protected by the same lock as 187 // LayerAndroid::paintBitmapGL(), so either we execute removeTexture() 188 // first and paintBitmapGL() will bail out, or we execute it after, 189 // and paintBitmapGL() will mark the texture as busy before 190 // relinquishing the lock. LayerAndroid::removeTexture() will call 191 // BaseTileTexture::release(), which will then do nothing 192 // if the texture is busy and we then don't return true. 193 bool proceed = true; 194 if (m_owner && m_owner != owner) 195 proceed = m_owner->removeTexture(this); 196 197 if (proceed) { 198 m_owner = owner; 199 return true; 200 } 201 } 202 return false; 203 } 204 205 bool BaseTileTexture::release(TextureOwner* owner) 206 { 207 android::Mutex::Autolock lock(m_busyLock); 208 XLOG("texture %p releasing tile %p, m_owner %p, m_busy %d", this, owner, m_owner, m_busy); 209 if (m_owner != owner) 210 return false; 211 212 m_owner = 0; 213 return true; 214 } 215 216 void BaseTileTexture::setTile(TextureInfo* info, int x, int y, 217 float scale, TilePainter* painter, 218 unsigned int pictureCount) 219 { 220 TextureTileInfo* textureInfo = m_texturesInfo.get(getWriteableTexture()); 221 if (!textureInfo) { 222 textureInfo = new TextureTileInfo(); 223 } 224 textureInfo->m_x = x; 225 textureInfo->m_y = y; 226 textureInfo->m_scale = scale; 227 textureInfo->m_painter = painter; 228 textureInfo->m_picture = pictureCount; 229 m_texturesInfo.set(getWriteableTexture(), textureInfo); 230 } 231 232 float BaseTileTexture::scale() 233 { 234 TextureTileInfo* textureInfo = &m_ownTextureTileInfo; 235 return textureInfo->m_scale; 236 } 237 238 // This function + TilesManager::addItemInTransferQueue() is replacing the 239 // setTile(). 240 void BaseTileTexture::setOwnTextureTileInfoFromQueue(const TextureTileInfo* info) 241 { 242 m_ownTextureTileInfo.m_x = info->m_x; 243 m_ownTextureTileInfo.m_y = info->m_y; 244 m_ownTextureTileInfo.m_scale = info->m_scale; 245 m_ownTextureTileInfo.m_painter = info->m_painter; 246 m_ownTextureTileInfo.m_picture = info->m_picture; 247 m_ownTextureTileInfo.m_inverted = TilesManager::instance()->invertedScreen(); 248 if (m_owner) { 249 BaseTile* owner = static_cast<BaseTile*>(m_owner); 250 owner->backTextureTransfer(); 251 } 252 253 } 254 255 bool BaseTileTexture::readyFor(BaseTile* baseTile) 256 { 257 const TextureTileInfo* info = &m_ownTextureTileInfo; 258 if (info && 259 (info->m_x == baseTile->x()) && 260 (info->m_y == baseTile->y()) && 261 (info->m_scale == baseTile->scale()) && 262 (info->m_painter == baseTile->painter()) && 263 (info->m_inverted == TilesManager::instance()->invertedScreen())) 264 return true; 265 266 XLOG("texture %p readyFor return false for tile x, y (%d %d) texId %d ," 267 " BaseTileTexture %p, BaseTile is %p, SCALE %f, painter %p, inv %d", 268 this, baseTile->x(), baseTile->y(), m_ownTextureId, this, baseTile, 269 baseTile->scale(), baseTile->painter(), TilesManager::instance()->invertedScreen()); 270 return false; 271 } 272 273 } // namespace WebCore 274