From: The Android Automerger Date: Mon, 5 Sep 2011 13:33:55 +0000 (-0700) Subject: merge in ics-release history after reset to master X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=02595c8646903e8fa907c057109a18375ba81630;hp=c9cbe93eb083bb20030a15d974d2558e78749ab9;p=android-x86%2Fexternal-webkit.git merge in ics-release history after reset to master --- diff --git a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp index a731fe152..42efaaca5 100644 --- a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp +++ b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp @@ -353,6 +353,13 @@ void convertJavaValueToNPVariant(JavaValue value, NPVariant* result) case JavaTypeString: { +#if PLATFORM(ANDROID) + // This entire file will likely be removed usptream soon. + if (value.m_stringValue.isNull()) { + VOID_TO_NPVARIANT(*result); + break; + } +#endif const char* utf8String = strdup(value.m_stringValue.utf8().data()); // The copied string is freed in NPN_ReleaseVariantValue (see npruntime.cpp) STRINGZ_TO_NPVARIANT(utf8String, *result); @@ -430,6 +437,10 @@ JavaValue jvalueToJavaValue(const jvalue& value, const JavaType& type) case JavaTypeString: { jstring javaString = static_cast(value.l); + if (!javaString) { + // result.m_stringValue is null by default + break; + } const UChar* characters = getUCharactersFromJStringInEnv(getJNIEnv(), javaString); // We take a copy to allow the Java String to be released. result.m_stringValue = String(characters, getJNIEnv()->GetStringLength(javaString)); @@ -488,6 +499,10 @@ jvalue javaValueToJvalue(const JavaValue& value) // be released when the call stack returns to Java. Note that this // may cause leaks if invoked from a native message loop, as is the // case in workers. + if (value.m_stringValue.isNull()) { + // result.l is null by default. + break; + } result.l = getJNIEnv()->NewString(value.m_stringValue.characters(), value.m_stringValue.length()); break; case JavaTypeBoolean: diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index ca679fb92..573ad6be2 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -36,11 +36,14 @@ #include #endif // USE(ACCELERATED_COMPOSITING) -#ifdef DEBUG - #include #include +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__) + +#ifdef DEBUG + #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__) @@ -57,8 +60,9 @@ using namespace android; BaseLayerAndroid::BaseLayerAndroid() #if USE(ACCELERATED_COMPOSITING) - : m_glWebViewState(0), - m_color(Color::white) + : m_glWebViewState(0) + , m_color(Color::white) + , m_scrollState(NotScrolling) #endif { #ifdef DEBUG_COUNT @@ -113,7 +117,7 @@ void BaseLayerAndroid::drawCanvas(SkCanvas* canvas) #if USE(ACCELERATED_COMPOSITING) bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, - double currentTime, bool* pagesSwapped) + double currentTime, bool* buffersSwappedPtr) { ZoomManager* zoomManager = m_glWebViewState->zoomManager(); @@ -126,94 +130,109 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, // Query the resulting state from the zoom manager bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage(); - bool zooming = zoomManager->zooming(); // Display the current page TiledPage* tiledPage = m_glWebViewState->frontPage(); TiledPage* nextTiledPage = m_glWebViewState->backPage(); tiledPage->setScale(zoomManager->currentScale()); - // Let's prepare the page if needed + // Let's prepare the page if needed so that it will start painting if (prepareNextTiledPage) { nextTiledPage->setScale(scale); m_glWebViewState->setFutureViewport(viewportTileBounds); m_glWebViewState->lockBaseLayerUpdate(); - nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds, TiledPage::kVisibleBounds); + nextTiledPage->updateTileState(viewportTileBounds); + nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds, + TiledPage::VisibleBounds); // Cancel pending paints for the foreground page TilesManager::instance()->removePaintOperationsForPage(tiledPage, false); } // If we fired a request, let's check if it's ready to use if (zoomManager->didFireRequest()) { - if (nextTiledPage->ready(viewportTileBounds, zoomManager->futureScale())) + if (nextTiledPage->swapBuffersIfReady(viewportTileBounds, + zoomManager->futureScale(), + TiledPage::SwapWholePage)) zoomManager->setReceivedRequest(); // transition to received request state } float transparency = 1; - bool doSwap = false; + bool doZoomPageSwap = false; // If the page is ready, display it. We do a short transition between // the two pages (current one and future one with the new scale factor) if (zoomManager->didReceivedRequest()) { float nextTiledPageTransparency = 1; - zoomManager->processTransition(currentTime, scale, &doSwap, + zoomManager->processTransition(currentTime, scale, &doZoomPageSwap, &nextTiledPageTransparency, &transparency); nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds); } const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds(); - bool needsRedraw = false; - - static bool waitOnScrollFinish = false; - - if (m_glWebViewState->isScrolling()) { - if (!waitOnScrollFinish) { - waitOnScrollFinish = true; - - //started scrolling, lock updates - m_glWebViewState->lockBaseLayerUpdate(); - } - } else { - // wait until all tiles are rendered before anything else - if (waitOnScrollFinish) { - //wait for the page to finish rendering, then go into swap mode - if (tiledPage->ready(preZoomBounds, zoomManager->currentScale())) { - m_glWebViewState->resetFrameworkInval(); - m_glWebViewState->unlockBaseLayerUpdate(); - waitOnScrollFinish = false; - } - //should be prepared, simply draw - } - - if (!waitOnScrollFinish) { - //completed page post-scroll - if (!tiledPage->ready(preZoomBounds, zoomManager->currentScale())) { - m_glWebViewState->lockBaseLayerUpdate(); + // update scrolling state machine by querying glwebviewstate - note that the + // NotScrolling state is only set below + if (m_glWebViewState->isScrolling()) + m_scrollState = Scrolling; + else if (m_scrollState == Scrolling) + m_scrollState = ScrollingFinishPaint; + + bool scrolling = m_scrollState != NotScrolling; + bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState(); + + // When we aren't zooming, we should TRY and swap tile buffers if they're + // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until + // the entire page is ready and then swap. + bool buffersSwapped = false; + if (!zooming) { + TiledPage::SwapMethod swapMethod; + if (scrolling) + swapMethod = TiledPage::SwapWhateverIsReady; + else + swapMethod = TiledPage::SwapWholePage; + + buffersSwapped = tiledPage->swapBuffersIfReady(preZoomBounds, + zoomManager->currentScale(), + swapMethod); + + if (buffersSwappedPtr && buffersSwapped) + *buffersSwappedPtr = true; + if (buffersSwapped) { + if (m_scrollState == ScrollingFinishPaint) { + m_scrollState = NotScrolling; + scrolling = false; } } } - if (!prepareNextTiledPage || tiledPage->ready(preZoomBounds, zoomManager->currentScale())) - tiledPage->prepare(goingDown, goingLeft, preZoomBounds, TiledPage::kExpandedBounds); - tiledPage->draw(transparency, preZoomBounds); - - if (zoomManager->scaleRequestState() != ZoomManager::kNoScaleRequest - || !tiledPage->ready(preZoomBounds, zoomManager->currentScale())) - needsRedraw = true; - - if (doSwap) { + if (doZoomPageSwap) { zoomManager->setCurrentScale(scale); m_glWebViewState->swapPages(); - if (pagesSwapped) - *pagesSwapped = true; + if (buffersSwappedPtr) + *buffersSwappedPtr = true; } - // if no longer trailing behind invalidates, unlock (so invalidates can - // go directly to the the TiledPages without deferral) - if (!needsRedraw && !waitOnScrollFinish) + // If stuff is happening such that we need a redraw, lock updates to the + // base layer, and only then start painting. + bool needsRedraw = scrolling || zooming || !buffersSwapped; + if (needsRedraw) + m_glWebViewState->lockBaseLayerUpdate(); + else m_glWebViewState->unlockBaseLayerUpdate(); + XLOG("scrolling %d, zooming %d, buffersSwapped %d, needsRedraw %d", + scrolling, zooming, buffersSwapped, needsRedraw); + + tiledPage->updateTileState(preZoomBounds); + + // Only paint new textures if the base layer has been locked, but not if + // we're zooming since the new tiles won't be relevant soon anyway + if (needsRedraw && !zooming) + tiledPage->prepare(goingDown, goingLeft, preZoomBounds, + TiledPage::ExpandedBounds); + + tiledPage->draw(transparency, preZoomBounds); + m_glWebViewState->paintExtras(); return needsRedraw; } @@ -221,13 +240,13 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& viewRect, SkRect& visibleRect, float scale, - bool* pagesSwapped) + bool* buffersSwappedPtr) { bool needsRedraw = false; #if USE(ACCELERATED_COMPOSITING) needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime, - pagesSwapped); + buffersSwappedPtr); if (!needsRedraw) m_glWebViewState->resetFrameworkInval(); diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h index 35ce24c0e..a42a3725b 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h @@ -38,6 +38,12 @@ namespace WebCore { class BaseLayerAndroid : public Layer { public: + enum ScrollState { + NotScrolling = 0, + Scrolling = 1, + ScrollingFinishPaint = 2 + }; + BaseLayerAndroid(); virtual ~BaseLayerAndroid(); @@ -56,12 +62,12 @@ public: void drawCanvas(SkCanvas* canvas); bool drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& rect, - SkRect& viewport, float scale, bool* pagesSwapped); + SkRect& viewport, float scale, bool* buffersSwappedPtr); void swapExtra(BaseLayerAndroid* base) { m_extra.swap(base->m_extra); } private: #if USE(ACCELERATED_COMPOSITING) bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime, - bool* pagesSwapped); + bool* buffersSwappedPtr); GLWebViewState* m_glWebViewState; android::Mutex m_drawLock; @@ -70,6 +76,8 @@ private: android::PictureSet m_content; SkPicture m_extra; SkRect m_previousVisible; + + ScrollState m_scrollState; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index 2963ca703..0a87ffe00 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -59,15 +59,16 @@ BaseTile::BaseTile(bool isLayerTile) , m_x(-1) , m_y(-1) , m_page(0) - , m_usedLevel(-1) - , m_texture(0) + , m_frontTexture(0) + , m_backTexture(0) , m_scale(1) , m_dirty(true) , m_repaintPending(false) - , m_usable(true) , m_lastDirtyPicture(0) , m_isTexturePainted(false) , m_isLayerTile(isLayerTile) + , m_isSwapNeeded(false) + , m_drawCount(0) { #ifdef DEBUG_COUNT ClassTracker::instance()->increment("BaseTile"); @@ -91,9 +92,10 @@ BaseTile::BaseTile(bool isLayerTile) BaseTile::~BaseTile() { - setUsedLevel(-1); - if (m_texture) - m_texture->release(this); + if (m_backTexture) + m_backTexture->release(this); + if (m_frontTexture) + m_frontTexture->release(this); delete m_renderer; delete[] m_dirtyArea; @@ -119,6 +121,7 @@ void BaseTile::setContents(TilePainter* painter, int x, int y, float scale) m_x = x; m_y = y; m_scale = scale; + m_drawCount = TilesManager::instance()->getDrawGLCount(); } void BaseTile::reserveTexture() @@ -126,22 +129,30 @@ void BaseTile::reserveTexture() BaseTileTexture* texture = TilesManager::instance()->getAvailableTexture(this); android::AutoMutex lock(m_atomicSync); - if (texture && m_texture != texture) { - m_isTexturePainted = false; - fullInval(); + if (texture && m_backTexture != texture) { + m_isSwapNeeded = false; // no longer ready to swap + m_backTexture = texture; + + // this is to catch when the front texture is stolen from beneath us. We + // should refine the stealing method to be simpler, and not require last + // moment checks like this + if (!m_frontTexture) + m_dirty = true; } - m_texture = texture; - if (m_texture) - m_texture->setUsedLevel(m_usedLevel); } bool BaseTile::removeTexture(BaseTileTexture* texture) { - XLOG("%x removeTexture res: %x... page %x", this, m_texture, m_page); + XLOG("%x removeTexture back %x front %x... page %x", + this, m_backTexture, m_frontTexture, m_page); // We update atomically, so paintBitmap() can see the correct value android::AutoMutex lock(m_atomicSync); - if (m_texture == texture) - m_texture = 0; + if (m_frontTexture == texture) { + m_frontTexture = 0; + m_dirty = true; + } + if (m_backTexture == texture) + m_backTexture = 0; return true; } @@ -166,13 +177,6 @@ void BaseTile::markAsDirty(int unsigned pictureCount, m_dirty = true; } -void BaseTile::setUsable(bool usable) -{ - android::AutoMutex lock(m_atomicSync); - m_usable = usable; -} - - bool BaseTile::isDirty() { android::AutoMutex lock(m_atomicSync); @@ -191,81 +195,62 @@ void BaseTile::setRepaintPending(bool pending) m_repaintPending = pending; } -void BaseTile::setUsedLevel(int usedLevel) -{ - if (m_texture) - m_texture->setUsedLevel(usedLevel); - m_usedLevel = usedLevel; -} - -int BaseTile::usedLevel() -{ - if (m_texture) - return m_texture->usedLevel(); - return m_usedLevel; -} - - void BaseTile::draw(float transparency, SkRect& rect, float scale) { if (m_x < 0 || m_y < 0 || m_scale != scale) return; - // No need to mutex protect reads of m_texture as it is only written to by + // No need to mutex protect reads of m_backTexture as it is only written to by // the consumer thread. - if (!m_texture) { - XLOG("%x on page %x (%d, %d) trying to draw, but no m_texture!", this, m_page, x(), y()); + if (!m_frontTexture) return; - } // Early return if set to un-usable in purpose! m_atomicSync.lock(); - bool usable = m_usable; bool isTexturePainted = m_isTexturePainted; m_atomicSync.unlock(); - if (!usable) { - XLOG("early return at BaseTile::draw b/c tile set to unusable !"); - return; - } - if (!isTexturePainted) { - XLOG("early return at BaseTile::draw b/c tile is not painted !"); + + if (!isTexturePainted) return; - } - TextureInfo* textureInfo = m_texture->consumerLock(); + TextureInfo* textureInfo = m_frontTexture->consumerLock(); if (!textureInfo) { - XLOG("%x (%d, %d) trying to draw, but no textureInfo!", this, x(), y()); - m_texture->consumerRelease(); + m_frontTexture->consumerRelease(); return; } - if (m_texture->readyFor(this)) { - XLOG("draw tile %x : %d, %d, %.2f with texture %x", this, x(), y(), m_scale, m_texture); + if (m_frontTexture->readyFor(this)) { if (isLayerTile()) TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), - rect, m_texture->m_ownTextureId, + rect, m_frontTexture->m_ownTextureId, transparency, true); else - TilesManager::instance()->shader()->drawQuad(rect, m_texture->m_ownTextureId, + TilesManager::instance()->shader()->drawQuad(rect, m_frontTexture->m_ownTextureId, transparency); - } - m_texture->consumerRelease(); + } else + m_dirty = true; + + m_frontTexture->consumerRelease(); } bool BaseTile::isTileReady() { - if (!m_texture) + // Return true if the tile's most recently drawn texture is up to date + android::AutoMutex lock(m_atomicSync); + BaseTileTexture * texture = m_isSwapNeeded ? m_backTexture : m_frontTexture; + + if (!texture) return false; - if (m_texture->owner() != this) + + if (texture->owner() != this) return false; - android::AutoMutex lock(m_atomicSync); if (m_dirty) return false; - m_texture->consumerLock(); - bool ready = m_texture->readyFor(this); - m_texture->consumerRelease(); + texture->consumerLock(); + bool ready = texture->readyFor(this); + texture->consumerRelease(); if (ready) return true; @@ -302,7 +287,7 @@ void BaseTile::paintBitmap() // can be updated by other threads without consequence. m_atomicSync.lock(); bool dirty = m_dirty; - BaseTileTexture* texture = m_texture; + BaseTileTexture* texture = m_backTexture; SkRegion dirtyArea = m_dirtyArea[m_currentDirtyAreaIndex]; float scale = m_scale; const int x = m_x; @@ -320,7 +305,7 @@ void BaseTile::paintBitmap() // at this point we can safely check the ownership (if the texture got // transferred to another BaseTile under us) - if (texture->owner() != this || texture->usedLevel() > 1) { + if (texture->owner() != this) { texture->producerRelease(); return; } @@ -412,16 +397,13 @@ void BaseTile::paintBitmap() pictureCount = m_renderer->renderTiledContent(renderInfo); } - XLOG("%x update texture %x for tile %d, %d scale %.2f (m_scale: %.2f)", this, textureInfo, x, y, scale, m_scale); - m_atomicSync.lock(); #if DEPRECATED_SURFACE_TEXTURE_MODE texture->setTile(textureInfo, x, y, scale, painter, pictureCount); #endif texture->producerReleaseAndSwap(); - - if (texture == m_texture) { + if (texture == m_backTexture) { m_isTexturePainted = true; // set the fullrepaint flags @@ -451,12 +433,43 @@ void BaseTile::paintBitmap() m_dirty = true; if (!m_dirty) - m_usable = true; + m_isSwapNeeded = true; } m_atomicSync.unlock(); } +void BaseTile::discardTextures() { + android::AutoMutex lock(m_atomicSync); + if (m_frontTexture) { + m_frontTexture->release(this); + m_frontTexture = 0; + } + if (m_backTexture) { + m_backTexture->release(this); + m_backTexture = 0; + } + m_dirty = true; +} + +bool BaseTile::swapTexturesIfNeeded() { + android::AutoMutex lock(m_atomicSync); + if (m_isSwapNeeded) { + // discard old texture and swap the new one in its place + if (m_frontTexture) + m_frontTexture->release(this); + + XLOG("%p's frontTexture was %p, now becoming %p", this, m_frontTexture, m_backTexture); + m_frontTexture = m_backTexture; + m_backTexture = 0; + m_isSwapNeeded = false; + XLOG("display texture for %d, %d front is now %p, texture is %p", + m_x, m_y, m_frontTexture, m_backTexture); + return true; + } + return false; +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/BaseTile.h b/Source/WebCore/platform/graphics/android/BaseTile.h index 0770b30a2..4c9650fd7 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.h +++ b/Source/WebCore/platform/graphics/android/BaseTile.h @@ -68,12 +68,11 @@ public: void setContents(TilePainter* painter, int x, int y, float scale); void setPage(TiledPage* page) { m_page = page; } - bool isAvailable() const { return !m_texture; } void reserveTexture(); - void setUsedLevel(int); - int usedLevel(); + bool isTileReady(); + void draw(float transparency, SkRect& rect, float scale); // the only thread-safe function called by the background thread @@ -88,13 +87,16 @@ public: bool isDirty(); bool isRepaintPending(); void setRepaintPending(bool pending); - void setUsable(bool usable); float scale() const { return m_scale; } void fullInval(); int x() const { return m_x; } int y() const { return m_y; } - BaseTileTexture* texture() { return m_texture; } + BaseTileTexture* frontTexture() { return m_frontTexture; } + BaseTileTexture* backTexture() { return m_backTexture; } + void discardTextures(); + bool swapTexturesIfNeeded(); + unsigned long long drawCount() { return m_drawCount; } void setGLWebViewState(GLWebViewState* state) { m_glWebViewState = state; } @@ -114,15 +116,16 @@ private: TiledPage* m_page; // The remaining variables can be updated throughout the lifetime of the object - int m_usedLevel; - BaseTileTexture* m_texture; + + BaseTileTexture* m_frontTexture; + BaseTileTexture* m_backTexture; float m_scale; - // used to signal that the that the tile is out-of-date and needs to be redrawn + + // used to signal that the that the tile is out-of-date and needs to be + // redrawn in the backTexture bool m_dirty; // used to signal that a repaint is pending bool m_repaintPending; - // used to signal whether or not the draw can use this tile. - bool m_usable; // stores the id of the latest picture from webkit that caused this tile to // become dirty. A tile is no longer dirty when it has been painted with a // picture that is newer than this value. @@ -145,6 +148,12 @@ private: BaseRenderer* m_renderer; bool m_isLayerTile; + bool m_isSwapNeeded; + + // the most recent GL draw before this tile was prepared. used for + // prioritization and caching. tiles with old drawcounts and textures they + // own are used for new tiles and rendering + unsigned long long m_drawCount; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp index 7c6fb7ac3..9db819cf0 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp @@ -52,7 +52,6 @@ namespace WebCore { BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h) : DoubleBufferedTexture(eglGetCurrentContext(), TilesManager::instance()->getSharedTextureMode()) - , m_usedLevel(-1) , m_owner(0) , m_delayedReleaseOwner(0) , m_delayedRelease(false) @@ -269,10 +268,10 @@ bool BaseTileTexture::readyFor(BaseTile* baseTile) (info->m_inverted == TilesManager::instance()->invertedScreen())) return true; - XLOG("readyFor return false for tile x, y (%d %d) texId %d ," - " BaseTileTexture %p, BaseTile is %p", - baseTile->x(), baseTile->y(), m_ownTextureId, this, baseTile); - + XLOG("texture %p readyFor return false for tile x, y (%d %d) texId %d ," + " BaseTileTexture %p, BaseTile is %p, SCALE %f, painter %p, inv %d", + this, baseTile->x(), baseTile->y(), m_ownTextureId, this, baseTile, + baseTile->scale(), baseTile->painter(), TilesManager::instance()->invertedScreen()); return false; } diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.h b/Source/WebCore/platform/graphics/android/BaseTileTexture.h index bc661955e..9c94a5313 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.h +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.h @@ -105,15 +105,6 @@ public: // swaps) the texture. virtual void producerUpdate(TextureInfo* textureInfo, const SkBitmap& bitmap); - // The level can be one of the following values: - // * -1 for an unused texture. - // * 0 for the tiles intersecting with the viewport. - // * n where n > 0 for the distance between the viewport and the tile. - // We use this to prioritize the order in which we reclaim textures, see - // TilesManager::getAvailableTexture() for more information. - int usedLevel() { return m_usedLevel; } - void setUsedLevel(int used) { m_usedLevel = used; } - // allows consumer thread to assign ownership of the texture to the tile. It // returns false if ownership cannot be transferred because the tile is busy bool acquire(TextureOwner* owner, bool force = false); @@ -149,7 +140,6 @@ private: TextureTileInfo m_ownTextureTileInfo; SkSize m_size; - int m_usedLevel; SkBitmap::Config m_config; TextureOwner* m_owner; diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index bc0792547..f030e5293 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -131,8 +131,8 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval { android::Mutex::Autolock lock(m_baseLayerLock); if (!layer || isPictureAfterFirstLayout) { - m_tiledPageA->setUsable(false); - m_tiledPageB->setUsable(false); + m_tiledPageA->discardTextures(); + m_tiledPageB->discardTextures(); } if (isPictureAfterFirstLayout) { m_baseLayerUpdate = true; @@ -355,9 +355,9 @@ void GLWebViewState::swapPages() { android::Mutex::Autolock lock(m_tiledPageLock); m_usePageA ^= true; - TiledPage* working = m_usePageA ? m_tiledPageB : m_tiledPageA; - if (zoomManager()->swapPages()) - TilesManager::instance()->resetTextureUsage(working); + TiledPage* oldPage = m_usePageA ? m_tiledPageB : m_tiledPageA; + zoomManager()->swapPages(); + oldPage->discardTextures(); } int GLWebViewState::baseContentWidth() @@ -489,15 +489,16 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect, bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, - IntRect& clip, float scale, bool* pagesSwapped) + IntRect& clip, float scale, bool* buffersSwappedPtr) { glFinish(); - TilesManager::instance()->registerGLWebViewState(this); + TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom, scale); + TilesManager::instance()->incDrawGLCount(); #ifdef DEBUG TilesManager::instance()->getTilesTracker()->clear(); @@ -552,7 +553,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // set up zoom manager, shaders, etc. m_backgroundColor = baseLayer->getBackgroundColor(); double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale); - bool ret = baseLayer->drawGL(currentTime, compositedRoot, rect, viewport, scale, pagesSwapped); + bool ret = baseLayer->drawGL(currentTime, compositedRoot, rect, + viewport, scale, buffersSwappedPtr); glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index 9bda481a9..a7803de04 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -212,7 +212,7 @@ public: bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, IntRect& webViewRect, int titleBarHeight, - IntRect& clip, float scale, bool* pagesSwapped); + IntRect& clip, float scale, bool* buffersSwappedPtr); #ifdef MEASURES_PERF void dumpMeasures(); diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp index 3aac9182f..4366ad64c 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -73,26 +73,32 @@ void PaintTileOperation::run() int PaintTileOperation::priority() { - if (!m_tile || m_tile->usedLevel() < 0) + if (!m_tile) return -1; - // for now, use a constant value for layers, - // lower than the base layer tiles (as layers - // will always be on top of the base surface) + int priority; if (m_tile->isLayerTile()) - return -2; + priority = -2; + else { + bool goingDown = m_tile->page()->scrollingDown(); + SkIRect *rect = m_tile->page()->expandedTileBounds(); + int firstTileX = rect->fLeft; + int nbTilesWidth = rect->width(); + priority = m_tile->x() - firstTileX; + if (goingDown) + priority += (rect->fBottom - m_tile->y()) * nbTilesWidth; + else + priority += (m_tile->y() - rect->fTop) * nbTilesWidth; + } + if (m_tile->frontTexture()) { + // de-prioritize old tiles that have something visible + unsigned long long currentDraw = TilesManager::instance()->getDrawGLCount(); + unsigned long long drawDelta = currentDraw - m_tile->drawCount(); + int cappedDrawDelta = (int)std::max(drawDelta, (unsigned long long)1000); + priority += cappedDrawDelta * 100000; + } - bool goingDown = m_tile->page()->scrollingDown(); - SkIRect *rect = m_tile->page()->expandedTileBounds(); - int firstTileX = rect->fLeft; - int nbTilesWidth = rect->width(); - int priority = m_tile->x() - firstTileX; - if (goingDown) - priority += (rect->fBottom - m_tile->y()) * nbTilesWidth; - else - priority += (m_tile->y() - rect->fTop) * nbTilesWidth; - priority += m_tile->usedLevel() * 100000; return priority; } diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h index 72a412538..57bbd8be1 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h @@ -39,6 +39,7 @@ public: virtual ~PaintTileOperation(); virtual bool operator==(const QueuedOperation* operation); virtual void run(); + // returns a rendering priority for m_tile, lower values are processed faster virtual int priority(); TilePainter* painter() { return m_tile->painter(); } float scale() { return m_tile->scale(); } diff --git a/Source/WebCore/platform/graphics/android/TextureOwner.h b/Source/WebCore/platform/graphics/android/TextureOwner.h index d0c60fb96..5434dbf31 100644 --- a/Source/WebCore/platform/graphics/android/TextureOwner.h +++ b/Source/WebCore/platform/graphics/android/TextureOwner.h @@ -43,6 +43,7 @@ public: virtual GLWebViewState* state() = 0; virtual bool samePageAs(Layer* root) { return false; } virtual bool isRepaintPending() = 0; + virtual unsigned long long drawCount() = 0; }; } diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index 95603afe5..b6a0c4784 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -100,19 +100,20 @@ TiledPage::~TiledPage() BaseTile* TiledPage::getBaseTile(int x, int y) const { + // TODO: replace loop over array with HashMap indexing for (int j = 0; j < m_baseTileSize; j++) { BaseTile& tile = m_baseTiles[j]; - if (tile.x() == x && tile.y() == y && !tile.isAvailable()) + if (tile.x() == x && tile.y() == y) return &tile; } return 0; } -void TiledPage::setUsable(bool usable) +void TiledPage::discardTextures() { for (int j = 0; j < m_baseTileSize; j++) { BaseTile& tile = m_baseTiles[j]; - tile.setUsable(usable); + tile.discardTextures(); } return; } @@ -163,57 +164,44 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y currentTile = &tile; break; } - if (!availableTile && tile.isAvailable()) + + if (!availableTile || (tile.drawCount() < availableTile->drawCount())) availableTile = &tile; } if (!currentTile && availableTile) { + XLOG("STEALING tile %d, %d (draw count %llu) for tile %d, %d", + availableTile->x(), availableTile->y(), availableTile->drawCount(), x, y); currentTile = availableTile; } + if (!currentTile) { + XLOG("ERROR: No tile available for tile %d %d", x, y); + } + if (currentTile) { currentTile->setGLWebViewState(m_glWebViewState); - currentTile->setContents(this, x, y, m_scale); currentTile->setPage(this); + currentTile->setContents(this, x, y, m_scale); + + // TODO: move below (which is largely the same for layers / tiled + // page) into prepare() function + // ensure there is a texture associated with the tile and then check to // see if the texture is dirty and in need of repainting - currentTile->reserveTexture(); - updateTileUsedLevel(tileBounds, *currentTile); - if (currentTile->isDirty() && !currentTile->isRepaintPending()) { + if (currentTile->isDirty() || !currentTile->frontTexture()) + currentTile->reserveTexture(); + if (currentTile->backTexture() + && currentTile->isDirty() + && !currentTile->isRepaintPending()) { PaintTileOperation *operation = new PaintTileOperation(currentTile); TilesManager::instance()->scheduleOperation(operation); - } else if (currentTile->isDirty()) { - XLOG("Tile %dx%d is dirty, but awaiting repaint", currentTile->x(), currentTile->y()); } } } } -void TiledPage::updateTileUsedLevel(const SkIRect& tileBounds, BaseTile& tile) -{ - const int lastTileX = tileBounds.fRight - 1; - const int lastTileY = tileBounds.fBottom - 1; - - // set the used level of the tile (e.g. distance from the viewport) - int dx = 0; - int dy = 0; - - if (tileBounds.fLeft > tile.x()) - dx = tileBounds.fLeft - tile.x(); - else if (lastTileX < tile.x()) - dx = tile.x() - lastTileX; - - if (tileBounds.fTop > tile.y()) - dy = tileBounds.fTop - tile.y(); - else if (lastTileY < tile.y()) - dy = tile.y() - lastTileY; - - int d = std::max(dx, dy); - - tile.setUsedLevel(d); -} - void TiledPage::updateTileState(const SkIRect& tileBounds) { if (!m_glWebViewState || tileBounds.isEmpty()) { @@ -226,15 +214,9 @@ void TiledPage::updateTileState(const SkIRect& tileBounds) BaseTile& tile = m_baseTiles[x]; - // if the tile no longer has a texture then proceed to the next tile - if (tile.isAvailable()) - continue; - // if the tile is in the dirty region then we must invalidate it if (m_invalRegion.contains(tile.x(), tile.y())) tile.markAsDirty(m_latestPictureInval, m_invalTilesRegion); - - updateTileUsedLevel(tileBounds, tile); } // clear the invalidated region as all tiles within that region have now @@ -266,7 +248,7 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound int nTilesToPrepare = nbTilesWidth * nbTilesHeight; int nMaxTilesPerPage = m_baseTileSize / 2; - if (bounds == kExpandedBounds) { + if (bounds == ExpandedBounds) { // prepare tiles outside of the visible bounds int expandX = m_glWebViewState->expandedTileBoundsX(); int expandY = m_glWebViewState->expandedTileBoundsY(); @@ -296,7 +278,7 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound m_prepare = true; } -bool TiledPage::ready(const SkIRect& tileBounds, float scale) +bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap) { if (!m_glWebViewState) return false; @@ -307,17 +289,43 @@ bool TiledPage::ready(const SkIRect& tileBounds, float scale) if (m_scale != scale) return false; - for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { - for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { - BaseTile* t = getBaseTile(x, y); - if (!t || !t->isTileReady()) - return false; + int swaps = 0; + if (swap == SwapWholePage) { + for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { + for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { + BaseTile* t = getBaseTile(x, y); + if (!t || !t->isTileReady()) + return false; + } + } + for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { + for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { + BaseTile* t = getBaseTile(x, y); + if (t->swapTexturesIfNeeded()) + swaps++; + } } + XLOG("%p whole page swapped %d textures, returning true", this, swaps); + return true; + } else { // SwapWhateveryIsReady + bool fullSwap = true; + for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) { + for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) { + BaseTile* t = getBaseTile(x, y); + if (!t || !t->isTileReady()) + fullSwap = false; + else { + if (t->swapTexturesIfNeeded()) + swaps++; + } + } + } + XLOG("%p greedy swap swapped %d tiles, returning %d", this, swaps, fullSwap); + return fullSwap; } - m_prepare = false; - return true; } + void TiledPage::draw(float transparency, const SkIRect& tileBounds) { if (!m_glWebViewState) @@ -332,11 +340,13 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) actualTileBounds.fLeft -= m_glWebViewState->expandedTileBoundsX(); actualTileBounds.fRight += m_glWebViewState->expandedTileBoundsX(); + actualTileBounds.fTop = std::max(0, actualTileBounds.fTop); + actualTileBounds.fLeft = std::max(0, actualTileBounds.fLeft); + for (int j = 0; j < m_baseTileSize; j++) { BaseTile& tile = m_baseTiles[j]; bool tileInView = actualTileBounds.contains(tile.x(), tile.y()); if (tileInView) { - SkRect rect; rect.fLeft = tile.x() * tileWidth; rect.fTop = tile.y() * tileHeight; diff --git a/Source/WebCore/platform/graphics/android/TiledPage.h b/Source/WebCore/platform/graphics/android/TiledPage.h index 56a34f475..14306ebc0 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.h +++ b/Source/WebCore/platform/graphics/android/TiledPage.h @@ -52,8 +52,12 @@ class IntRect; class TiledPage : public TilePainter { public: enum PrepareBounds { - kExpandedBounds = 0, - kVisibleBounds = 1 + ExpandedBounds = 0, + VisibleBounds = 1 + }; + enum SwapMethod { + SwapWhateverIsReady = 0, + SwapWholePage = 1 }; TiledPage(int id, GLWebViewState* state); @@ -64,8 +68,12 @@ public: // prepare the page for display on the screen void prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds, PrepareBounds bounds); + void updateTileState(const SkIRect& tileBounds); + // check to see if the page is ready for display - bool ready(const SkIRect& tileBounds, float scale); + + // swap 'buffers' by swapping each modified texture + bool swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap); // draw the page on the screen void draw(float transparency, const SkIRect& tileBounds); @@ -83,15 +91,13 @@ public: void setScale(float scale) { m_scale = scale; m_invScale = 1 / scale; } void invalidateRect(const IntRect& invalRect, const unsigned int pictureCount); - void setUsable(bool usable); + void discardTextures(); void updateBaseTileSize(); bool scrollingDown() { return m_scrollingDown; } SkIRect* expandedTileBounds() { return &m_expandedTileBounds; } private: - void updateTileState(const SkIRect& tileBounds); void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, const SkIRect& tileBounds); - void updateTileUsedLevel(const SkIRect& tileBounds, BaseTile& tile); BaseTile* getBaseTile(int x, int y) const; diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index 1aac44d2a..c1fb4d115 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -68,7 +68,6 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint) for (unsigned int i = 0; i < m_tiles.size(); i++) { BaseTile* tile = m_tiles[i]; - tile->setUsedLevel(-1); if (!m_dirtyRegion.isEmpty()) tile->markAsDirty(1, m_dirtyRegion); } @@ -130,19 +129,16 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) tile = new BaseTile(true); m_tiles.append(tile); } - tile->reserveTexture(); - if (!tile->texture()) - return; tile->setContents(this, x, y, m_surface->scale()); - tile->setUsedLevel(0); - bool schedule = false; - if (tile->isDirty()) - schedule = true; + // TODO: move below (which is largely the same for layers / tiled page) into + // prepare() function + if (tile->isDirty() || !tile->frontTexture()) + tile->reserveTexture(); LayerAndroid* layer = m_surface->layer(); - if (schedule && layer && !tile->isRepaintPending()) { + if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) { PaintTileOperation *operation = new PaintTileOperation(tile, m_surface); TilesManager::instance()->scheduleOperation(operation); } @@ -187,11 +183,13 @@ bool TiledTexture::draw() rect.fTop = tile->y() * tileHeight; rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; - XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f [ready: %d] dirty: %d", i, this, tile->painter(), tile, tile->x(), tile->y(), tile->scale(), tile->isTileReady(), tile->isDirty()); + XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f [ready: %d] dirty: %d", + i, this, tile->painter(), tile, tile->x(), tile->y(), tile->scale(), tile->isTileReady(), tile->isDirty()); askRedraw |= !tile->isTileReady(); + tile->swapTexturesIfNeeded(); tile->draw(m_surface->opacity(), rect, m_surface->scale()); #ifdef DEBUG - TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->texture()); + TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture()); #endif } } @@ -241,7 +239,9 @@ bool TiledTexture::owns(BaseTileTexture* texture) { for (unsigned int i = 0; i < m_tiles.size(); i++) { BaseTile* tile = m_tiles[i]; - if (tile->texture() == texture) + if (tile->frontTexture() == texture) + return true; + if (tile->backTexture() == texture) return true; } return false; diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index 57c38cf86..2c263e396 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -100,7 +100,7 @@ TilesManager::TilesManager() , m_showVisualIndicator(false) , m_invertedScreen(false) , m_invertedScreenSwitch(false) - , m_drawRegistrationCount(0) + , m_drawGLCount(0) { XLOG("TilesManager ctor"); m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION); @@ -164,27 +164,14 @@ void TilesManager::printTextures() x = o->x(); y = o->y(); } - XLOG("[%d] texture %x usedLevel: %d busy: %d owner: %x (%d, %d) page: %x scale: %.2f", - i, texture, texture->usedLevel(), + XLOG("[%d] texture %x busy: %d owner: %x (%d, %d) page: %x scale: %.2f", + i, texture, texture->busy(), o, x, y, o ? o->page() : 0, o ? o->scale() : 0); } XLOG("------"); #endif // DEBUG } -void TilesManager::resetTextureUsage(TiledPage* page) -{ - android::Mutex::Autolock lock(m_texturesLock); - for (unsigned int i = 0; i < m_textures.size(); i++) { - BaseTileTexture* texture = m_textures[i]; - TextureOwner* owner = texture->owner(); - if (owner) { - if (owner->page() == page) - texture->setUsedLevel(-1); - } - } -} - void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree) { if (oldTree) @@ -227,81 +214,69 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) android::Mutex::Autolock lock(m_texturesLock); // Sanity check that the tile does not already own a texture - if (owner->texture() && owner->texture()->owner() == owner) { - owner->texture()->setUsedLevel(0); - XLOG("same owner (%d, %d), getAvailableTexture(%x) => texture %x", - owner->x(), owner->y(), owner, owner->texture()); + if (owner->backTexture() && owner->backTexture()->owner() == owner) { + XLOG("same owner (%d, %d), getAvailableBackTexture(%x) => texture %x", + owner->x(), owner->y(), owner, owner->backTexture()); if (owner->isLayerTile()) - m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->texture())); + m_availableTilesTextures.remove(m_availableTilesTextures.find(owner->backTexture())); else - m_availableTextures.remove(m_availableTextures.find(owner->texture())); - return owner->texture(); + m_availableTextures.remove(m_availableTextures.find(owner->backTexture())); + return owner->backTexture(); } + WTF::Vector* availableTexturePool; if (owner->isLayerTile()) { - BaseTileTexture* layerTexture = 0; - unsigned int max = m_availableTilesTextures.size(); - for (unsigned int i = 0; i < max; i++) { - BaseTileTexture* texture = m_availableTilesTextures[i]; - if (texture->owner() && texture->owner()->isRepaintPending()) - continue; - if (!texture->owner() && texture->acquire(owner)) { - layerTexture = texture; - break; - } - if (texture->usedLevel() != 0 && texture->acquire(owner)) { - layerTexture = texture; - break; - } - if (texture->scale() != owner->scale() && texture->acquire(owner)) { - layerTexture = texture; - break; - } - } - if (layerTexture) - m_availableTilesTextures.remove(m_availableTilesTextures.find(layerTexture)); - return layerTexture; + availableTexturePool = &m_availableTilesTextures; + } else { + availableTexturePool = &m_availableTextures; } // The heuristic for selecting a texture is as follows: - // 1. If usedLevel == -1, break with that one - // 2. Otherwise, select the highest usedLevel available - // 3. Break ties with the lowest LRU(RecentLevel) valued GLWebViewState + // 1. If a tile isn't owned, break with that one + // 2. If we find a tile in the same page with a different scale, + // it's old and not visible. Break with that one + // 3. Otherwise, use the least recently prepared tile BaseTileTexture* farthestTexture = 0; - int farthestTextureLevel = 0; - unsigned int lowestDrawCount = ~0; //maximum uint - const unsigned int max = m_availableTextures.size(); + unsigned long long oldestDrawCount = ~0; //maximum u64 + const unsigned int max = availableTexturePool->size(); for (unsigned int i = 0; i < max; i++) { - BaseTileTexture* texture = m_availableTextures[i]; - - if (texture->usedLevel() == -1) { // found an unused texture, grab it + BaseTileTexture* texture = (*availableTexturePool)[i]; + TextureOwner* currentOwner = texture->owner(); + if (!currentOwner) { farthestTexture = texture; break; } - int textureLevel = texture->usedLevel(); - unsigned int textureDrawCount = getGLWebViewStateDrawCount(texture->owner()->state()); + if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) { + // if we render the back page with one scale, then another while + // still zooming, we recycle the tiles with the old scale instead of + // taking ones from the front page + farthestTexture = texture; + break; + } - // if (higher distance or equal distance but less recently rendered) - if (farthestTextureLevel < textureLevel - || ((farthestTextureLevel == textureLevel) && (lowestDrawCount > textureDrawCount))) { + unsigned long long textureDrawCount = currentOwner->drawCount(); + if (oldestDrawCount > textureDrawCount) { farthestTexture = texture; - farthestTextureLevel = textureLevel; - lowestDrawCount = textureDrawCount; + oldestDrawCount = textureDrawCount; } } + TextureOwner* previousOwner = farthestTexture->owner(); if (farthestTexture && farthestTexture->acquire(owner)) { - XLOG("farthest texture, getAvailableTexture(%x) => texture %x (level %d, drawCount %d)", - owner, farthestTexture, farthestTextureLevel, lowestDrawCount); - farthestTexture->setUsedLevel(0); - m_availableTextures.remove(m_availableTextures.find(farthestTexture)); + if (previousOwner) { + XLOG("%s texture %p stolen from tile %d, %d, drawCount was %llu", + owner->isLayerTile() ? "LAYER" : "BASE", + farthestTexture, owner->x(), owner->y(), oldestDrawCount); + } + + availableTexturePool->remove(availableTexturePool->find(farthestTexture)); return farthestTexture; } - XLOG("Couldn't find an available texture for BaseTile %x (%d, %d) !!!", - owner, owner->x(), owner->y()); + XLOG("Couldn't find an available texture for tile %x (%d, %d) out of %d available!!!", + owner, owner->x(), owner->y(), max); #ifdef DEBUG printTextures(); #endif // DEBUG @@ -362,27 +337,11 @@ float TilesManager::layerTileHeight() return LAYER_TILE_HEIGHT; } -void TilesManager::registerGLWebViewState(GLWebViewState* state) -{ - m_glWebViewStateMap.set(state, m_drawRegistrationCount); - m_drawRegistrationCount++; - XLOG("now state %p, total of %d states", state, m_glWebViewStateMap.size()); -} - void TilesManager::unregisterGLWebViewState(GLWebViewState* state) { // Discard the whole queue b/c we lost GL context already. // Note the real updateTexImage will still wait for the next draw. transferQueue()->discardQueue(); - - m_glWebViewStateMap.remove(state); - XLOG("state %p now removed, total of %d states", state, m_glWebViewStateMap.size()); -} - -unsigned int TilesManager::getGLWebViewStateDrawCount(GLWebViewState* state) -{ - XLOG("looking up state %p, contains=%s", state, m_glWebViewStateMap.contains(state) ? "TRUE" : "FALSE"); - return m_glWebViewStateMap.find(state)->second; } TilesManager* TilesManager::instance() diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index a383a2ef2..513494c5c 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -108,7 +108,6 @@ public: static float tileHeight(); static float layerTileWidth(); static float layerTileHeight(); - void registerGLWebViewState(GLWebViewState* state); void unregisterGLWebViewState(GLWebViewState* state); void allocateTiles(); @@ -165,6 +164,16 @@ public: m_shader.setContrast(contrast); } + void incDrawGLCount() + { + m_drawGLCount++; + } + + unsigned long long getDrawGLCount() + { + return m_drawGLCount; + } + private: TilesManager(); @@ -206,13 +215,9 @@ private: VideoLayerManager m_videoLayerManager; - HashMap m_glWebViewStateMap; - unsigned int m_drawRegistrationCount; - - unsigned int getGLWebViewStateDrawCount(GLWebViewState* state); - TilesProfiler m_profiler; TilesTracker m_tilesTracker; + unsigned long long m_drawGLCount; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TilesProfiler.cpp b/Source/WebCore/platform/graphics/android/TilesProfiler.cpp index 653d525db..0271ee3c6 100644 --- a/Source/WebCore/platform/graphics/android/TilesProfiler.cpp +++ b/Source/WebCore/platform/graphics/android/TilesProfiler.cpp @@ -122,7 +122,7 @@ void TilesProfiler::nextTile(BaseTile& tile, float scale, bool inView) } m_records.last().append(TileProfileRecord( left, top, right, bottom, - scale, isReady, tile.usedLevel())); + scale, isReady, (int)tile.drawCount())); XLOG("adding tile %d %d %d %d, scale %f", left, top, right, bottom, scale); } diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index 851d02c9b..b73f38870 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -113,7 +113,7 @@ bool TransferQueue::checkObsolete(int index) return true; } - BaseTileTexture* baseTileTexture = baseTilePtr->texture(); + BaseTileTexture* baseTileTexture = baseTilePtr->backTexture(); if (!baseTileTexture) { XLOG("Invalid baseTileTexture , such that the tile is obsolete"); return true; @@ -248,7 +248,7 @@ void TransferQueue::updateDirtyBaseTiles() // the queue. Then either move on to next item or copy the content. BaseTileTexture* destTexture = 0; if (!obsoleteBaseTile) - destTexture = m_transferQueue[index].savedBaseTilePtr->texture(); + destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture(); m_sharedSurfaceTexture->updateTexImage(); @@ -271,9 +271,10 @@ void TransferQueue::updateDirtyBaseTiles() // texturesTileInfo. destTexture->setOwnTextureTileInfoFromQueue(&m_transferQueue[index].tileInfo); - XLOG("Blit tile x, y %d %d to destTexture->m_ownTextureId %d", + XLOG("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d", m_transferQueue[index].tileInfo.m_x, m_transferQueue[index].tileInfo.m_y, + destTexture, destTexture->m_ownTextureId); } index = (index + 1) % ST_BUFFER_NUMBER; diff --git a/Source/WebCore/rendering/RenderRuby.cpp b/Source/WebCore/rendering/RenderRuby.cpp index 0b5138455..e0137dec3 100644 --- a/Source/WebCore/rendering/RenderRuby.cpp +++ b/Source/WebCore/rendering/RenderRuby.cpp @@ -40,33 +40,53 @@ namespace WebCore { //=== generic helper functions to avoid excessive code duplication === -static inline bool isAnonymousRubyInlineBlock(RenderObject* object) +static inline bool isAnonymousRubyInlineBlock(const RenderObject* object) { - ASSERT(!object->parent()->isRuby() + ASSERT(!object + || !object->parent()->isRuby() || object->isRubyRun() || (object->isInline() && (object->isBeforeContent() || object->isAfterContent())) || (object->isAnonymous() && object->isRenderBlock() && object->style()->display() == INLINE_BLOCK)); - return object->parent()->isRuby() && object->isRenderBlock() && !object->isRubyRun(); + + return object + && object->parent()->isRuby() + && object->isRenderBlock() + && !object->isRubyRun(); +} + +static inline bool isRubyBeforeBlock(const RenderObject* object) +{ + return isAnonymousRubyInlineBlock(object) + && !object->previousSibling() + && object->firstChild() + && object->firstChild()->style()->styleType() == BEFORE; +} + +static inline bool isRubyAfterBlock(const RenderObject* object) +{ + return isAnonymousRubyInlineBlock(object) + && !object->nextSibling() + && object->firstChild() + && object->firstChild()->style()->styleType() == AFTER; } static inline RenderBlock* rubyBeforeBlock(const RenderObject* ruby) { RenderObject* child = ruby->firstChild(); - return child && !child->isRubyRun() && child->isRenderBlock() && child->style()->styleType() == BEFORE ? static_cast(child) : 0; + return isRubyBeforeBlock(child) ? static_cast(child) : 0; } static inline RenderBlock* rubyAfterBlock(const RenderObject* ruby) { RenderObject* child = ruby->lastChild(); - return child && !child->isRubyRun() && child->isRenderBlock() && child->style()->styleType() == AFTER ? static_cast(child) : 0; + return isRubyAfterBlock(child) ? static_cast(child) : 0; } -static RenderBlock* createAnonymousRubyInlineBlock(RenderObject* ruby, PseudoId styleType) +static RenderBlock* createAnonymousRubyInlineBlock(RenderObject* ruby) { RefPtr newStyle = RenderStyle::createAnonymousStyle(ruby->style()); newStyle->setDisplay(INLINE_BLOCK); - newStyle->setStyleType(styleType); - + RenderBlock* newBlock = new (ruby->renderArena()) RenderBlock(ruby->document() /* anonymous box */); newBlock->setStyle(newStyle.release()); return newBlock; @@ -110,7 +130,7 @@ void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild // Wrap non-inline content with an anonymous inline-block. RenderBlock* beforeBlock = rubyBeforeBlock(this); if (!beforeBlock) { - beforeBlock = createAnonymousRubyInlineBlock(this, BEFORE); + beforeBlock = createAnonymousRubyInlineBlock(this); RenderInline::addChild(beforeBlock, firstChild()); } beforeBlock->addChild(child); @@ -125,7 +145,7 @@ void RenderRubyAsInline::addChild(RenderObject* child, RenderObject* beforeChild // Wrap non-inline content with an anonymous inline-block. RenderBlock* afterBlock = rubyAfterBlock(this); if (!afterBlock) { - afterBlock = createAnonymousRubyInlineBlock(this, AFTER); + afterBlock = createAnonymousRubyInlineBlock(this); RenderInline::addChild(afterBlock); } afterBlock->addChild(child); @@ -211,7 +231,7 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) // Wrap non-inline content with an anonymous inline-block. RenderBlock* beforeBlock = rubyBeforeBlock(this); if (!beforeBlock) { - beforeBlock = createAnonymousRubyInlineBlock(this, BEFORE); + beforeBlock = createAnonymousRubyInlineBlock(this); RenderBlock::addChild(beforeBlock, firstChild()); } beforeBlock->addChild(child); @@ -226,7 +246,7 @@ void RenderRubyAsBlock::addChild(RenderObject* child, RenderObject* beforeChild) // Wrap non-inline content with an anonymous inline-block. RenderBlock* afterBlock = rubyAfterBlock(this); if (!afterBlock) { - afterBlock = createAnonymousRubyInlineBlock(this, AFTER); + afterBlock = createAnonymousRubyInlineBlock(this); RenderBlock::addChild(afterBlock); } afterBlock->addChild(child); diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp index 3c62205f8..839a88708 100644 --- a/Source/WebKit/android/jni/PictureSet.cpp +++ b/Source/WebKit/android/jni/PictureSet.cpp @@ -155,6 +155,11 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture, Bucket* PictureSet::getBucket(int x, int y) { + // only create buckets for valid, positive coordinates, ignore and return + // NULL otherwise + if (x < 0 || y < 0) + return 0; + BucketPosition position(x+1, y+1); if (!mBuckets.contains(position)) { Bucket* bucket = new Bucket(); @@ -277,6 +282,10 @@ void PictureSet::gatherBucketsForArea(WTF::Vector& list, const SkIRect& { int maxSize = BUCKET_SIZE; + XLOG("\n--- gatherBucketsForArea for rect %d, %d, %d, %d (%d x %d)", + rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, + rect.width(), rect.height()); + int x = rect.fLeft; int y = rect.fTop; int firstTileX = rect.fLeft / maxSize; @@ -288,7 +297,8 @@ void PictureSet::gatherBucketsForArea(WTF::Vector& list, const SkIRect& for (int j = firstTileY; j <= lastTileY; j++) { Bucket* bucket = getBucket(i, j); XLOG("gather bucket %x for %d, %d", bucket, i+1, j+1); - list.append(bucket); + if (bucket) + list.append(bucket); } } } @@ -319,6 +329,9 @@ void PictureSet::splitAdd(const SkIRect& rect) for (int i = firstTileX; i <= lastTileX; i++) { for (int j = firstTileY; j <= lastTileY; j++) { Bucket* bucket = getBucket(i, j); + if (!bucket) + continue; + SkIRect newRect; int deltaX = i * maxSize; int deltaY = j * maxSize; @@ -442,8 +455,10 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture, Pictures pictureAndBounds = {collect, 0, collect.getBounds(), elapsed, split, false, false, empty}; +#ifdef FAST_PICTURESET if (mPictures.size() == 0) checkForNewBases = true; +#endif mPictures.append(pictureAndBounds); mAdditionalArea += totalArea.width() * totalArea.height();