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 53namespace WebCore { 54 55BaseTileTexture::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 72BaseTileTexture::~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 83void BaseTileTexture::requireGLTexture() 84{ 85 if (!m_ownTextureId) 86 m_ownTextureId = GLUtils::createBaseTileGLTexture(m_size.width(), m_size.height()); 87} 88 89void 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 101void 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 118TextureInfo* BaseTileTexture::producerLock() 119{ 120 m_busyLock.lock(); 121 m_busy = true; 122 m_busyLock.unlock(); 123 return DoubleBufferedTexture::producerLock(); 124} 125 126void BaseTileTexture::producerRelease() 127{ 128 DoubleBufferedTexture::producerRelease(); 129 setNotBusy(); 130} 131 132void BaseTileTexture::producerReleaseAndSwap() 133{ 134 DoubleBufferedTexture::producerReleaseAndSwap(); 135 setNotBusy(); 136} 137 138void BaseTileTexture::setNotBusy() 139{ 140 android::Mutex::Autolock lock(m_busyLock); 141 m_busy = false; 142 m_busyCond.signal(); 143} 144 145bool BaseTileTexture::busy() 146{ 147 android::Mutex::Autolock lock(m_busyLock); 148 return m_busy; 149} 150 151void 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 166bool BaseTileTexture::acquire(TextureOwner* owner, bool force) 167{ 168 if (m_owner == owner) 169 return true; 170 171 return setOwner(owner, force); 172} 173 174bool 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 205bool 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 216void 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 232float 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(). 240void 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 255bool 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