diff options
Diffstat (limited to 'WebCore')
23 files changed, 402 insertions, 134 deletions
diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index 3154a67..5314a32 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -143,6 +143,9 @@ FrameView::FrameView(Frame* frame) , m_deferSetNeedsLayouts(0) , m_setNeedsLayoutWasDeferred(false) , m_scrollCorner(0) +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + , m_hasOverflowScroll(false) +#endif { init(); } @@ -553,11 +556,6 @@ void FrameView::updateCompositingLayers() RenderView* view = m_frame->contentRenderer(); if (!view) return; -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - // Enter compositing mode for child frames that have layout dimensions. - if (hasOverflowScroll()) - enterCompositingMode(); -#endif // This call will make sure the cached hasAcceleratedCompositing is updated from the pref view->compositor()->cacheAcceleratedCompositingFlags(); @@ -571,31 +569,6 @@ void FrameView::setNeedsOneShotDrawingSynchronization() page->chrome()->client()->setNeedsOneShotDrawingSynchronization(); } -#if ENABLE(ANDROID_OVERFLOW_SCROLL) -bool FrameView::hasOverflowScroll() const -{ -#ifndef ANDROID_FLATTEN_IFRAME - RenderObject* ownerRenderer = m_frame->ownerRenderer(); - if (!ownerRenderer || !ownerRenderer->isRenderIFrame()) - return false; - RenderLayer* layer = ownerRenderer->enclosingLayer(); - // Make sure the layer has visible content or descendants. - if (!layer->hasVisibleContent() && !layer->hasVisibleDescendant()) - return false; - // If either layout dimension is 0, return false. - if (!layoutWidth() || !layoutHeight()) - return false; - ScrollbarMode h, v; - scrollbarModes(h, v); - if (h == ScrollbarAlwaysOff || v == ScrollbarAlwaysOff) - return false; - if (contentsWidth() <= layoutWidth() && contentsHeight() <= layoutHeight()) - return false; - return true; -#endif - return false; -} -#endif #endif // USE(ACCELERATED_COMPOSITING) bool FrameView::hasCompositedContent() const @@ -955,6 +928,30 @@ void FrameView::layout(bool allowSubtree) InspectorInstrumentation::didLayout(cookie); m_nestedLayoutCount--; +#if ENABLE(ANDROID_OVERFLOW_SCROLL) && !defined(ANDROID_FLATTEN_IFRAME) + // Reset to false each time we layout in case the overflow status changed. + bool hasOverflowScroll = false; + RenderObject* ownerRenderer = m_frame->ownerRenderer(); + if (ownerRenderer && ownerRenderer->isRenderIFrame()) { + RenderLayer* layer = ownerRenderer->enclosingLayer(); + if (layer) { + // Some sites use tiny iframes for loading so don't composite those. + if (canHaveScrollbars() && layoutWidth() > 1 && layoutHeight() > 1) + hasOverflowScroll = layoutWidth() < contentsWidth() || layoutHeight() < contentsHeight(); + } + } + if (RenderView* view = m_frame->contentRenderer()) { + if (hasOverflowScroll != m_hasOverflowScroll) { + if (hasOverflowScroll) + enterCompositingMode(); + else + // We are leaving overflow mode so we need to update the layer + // tree in case that is the reason we were composited. + view->compositor()->scheduleCompositingLayerUpdate(); + } + } + m_hasOverflowScroll = hasOverflowScroll; +#endif } void FrameView::addWidgetToUpdate(RenderEmbeddedObject* object) diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index d56b1ef..1b5b322 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -103,9 +103,9 @@ public: // Called when changes to the GraphicsLayer hierarchy have to be synchronized with // content rendered via the normal painting path. void setNeedsOneShotDrawingSynchronization(); -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - bool hasOverflowScroll() const; #endif +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + bool hasOverflowScroll() const { return m_hasOverflowScroll; } #endif bool hasCompositedContent() const; @@ -390,6 +390,9 @@ private: static double s_initialDeferredRepaintDelayDuringLoading; static double s_maxDeferredRepaintDelayDuringLoading; static double s_deferredRepaintDelayIncrementDuringLoading; +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + bool m_hasOverflowScroll; +#endif }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp index 12e0436..3462975 100644 --- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp +++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp @@ -98,6 +98,12 @@ void BackedDoubleBufferedTexture::producerReleaseAndSwap() m_busy = false; } +bool BackedDoubleBufferedTexture::busy() +{ + android::Mutex::Autolock lock(m_busyLock); + return m_busy; +} + void BackedDoubleBufferedTexture::producerUpdate(TextureInfo* textureInfo) { // no need to upload a texture since the bitmap is empty @@ -132,7 +138,7 @@ bool BackedDoubleBufferedTexture::setOwner(TextureOwner* owner) android::Mutex::Autolock lock(m_busyLock); if (!m_busy) { if (m_owner) - m_owner->removeTexture(); + m_owner->removeTexture(this); m_owner = owner; return true; } diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h index 844715d..0b62224 100644 --- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h +++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h @@ -76,8 +76,7 @@ public: TextureOwner* owner() { return m_owner; } // only used by the consumer thread SkCanvas* canvas() { return m_canvas; } // only used by the producer thread - // This is to be only used for debugging on the producer thread - bool busy() { return m_busy; } + bool busy(); const SkSize& getSize() const { return m_size; } diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index b84831d..9ed967f 100644 --- a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -272,11 +272,23 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect, #ifdef DEBUG TilesManager::instance()->printLayersTextures("reserve"); #endif + // Get the current scale; if we are zooming, we don't change the scale + // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but + // we change the scaleRequestState. When the state is kReceivedNewScale + // we can use the future scale instead of the current scale to request + // new textures. After a transition time, the scaleRequestState will be + // reset and the current scale will be set to the future scale. + float scale = m_glWebViewState->currentScale(); + if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) { + scale = m_glWebViewState->futureScale(); + } + compositedRoot->setScale(scale); compositedRoot->reserveGLTextures(); - // Now that we marked the textures being used, we delete the unnecessary - // ones to make space... - TilesManager::instance()->cleanupLayersTextures(); - // Finally do another pass to create new textures if needed + // Now that we marked the textures being used, we delete + // the unnecessary ones to make space... + TilesManager::instance()->cleanupLayersTextures(compositedRoot); + // Finally do another pass to create new textures and schedule + // repaints if needed compositedRoot->createGLTextures(); if (compositedRoot->drawGL(matrix)) diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp index a506ac9..35de698 100644 --- a/WebCore/platform/graphics/android/BaseTile.cpp +++ b/WebCore/platform/graphics/android/BaseTile.cpp @@ -115,12 +115,13 @@ void BaseTile::reserveTexture() m_texture = texture; } -void BaseTile::removeTexture() +void BaseTile::removeTexture(BackedDoubleBufferedTexture* texture) { XLOG("%x removeTexture res: %x...", this, m_texture); // We update atomically, so paintBitmap() can see the correct value android::AutoMutex lock(m_atomicSync); - m_texture = 0; + if (m_texture == texture) + m_texture = 0; } void BaseTile::setScale(float scale) diff --git a/WebCore/platform/graphics/android/BaseTile.h b/WebCore/platform/graphics/android/BaseTile.h index f6ffe38..a7eae23 100644 --- a/WebCore/platform/graphics/android/BaseTile.h +++ b/WebCore/platform/graphics/android/BaseTile.h @@ -90,7 +90,7 @@ public: BackedDoubleBufferedTexture* texture() { return m_texture; } // TextureOwner implementation - virtual void removeTexture(); + virtual void removeTexture(BackedDoubleBufferedTexture* texture); virtual TiledPage* page() { return m_page; } private: diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp index 1c32848..45915e5 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -63,7 +63,7 @@ int GLWebViewState::count() } #endif -GLWebViewState::GLWebViewState() +GLWebViewState::GLWebViewState(android::Mutex* buttonMutex) : m_scaleRequestState(kNoScaleRequest) , m_currentScale(1) , m_futureScale(1) @@ -72,6 +72,7 @@ GLWebViewState::GLWebViewState() , m_baseLayer(0) , m_currentPictureCounter(0) , m_usePageA(true) + , m_globalButtonMutex(buttonMutex) { m_viewport.setEmpty(); m_futureViewportTileBounds.setEmpty(); @@ -135,8 +136,11 @@ void GLWebViewState::inval(const IntRect& rect) unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas) { android::Mutex::Autolock lock(m_baseLayerLock); - if (m_baseLayer) + if (m_baseLayer) { + m_globalButtonMutex->lock(); m_baseLayer->drawCanvas(canvas); + m_globalButtonMutex->unlock(); + } return m_currentPictureCounter; } diff --git a/WebCore/platform/graphics/android/GLWebViewState.h b/WebCore/platform/graphics/android/GLWebViewState.h index c627a6e..8d2216e 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.h +++ b/WebCore/platform/graphics/android/GLWebViewState.h @@ -152,7 +152,7 @@ public: }; typedef int32_t GLScaleState; - GLWebViewState(); + GLWebViewState(android::Mutex* globalButtonMutex); ~GLWebViewState(); GLScaleState scaleRequestState() const { return m_scaleRequestState; } void setScaleRequestState(GLScaleState state) { m_scaleRequestState = state; } @@ -222,6 +222,7 @@ private: TiledPage* m_tiledPageA; TiledPage* m_tiledPageB; SkIRect m_lastInval; + android::Mutex* m_globalButtonMutex; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index aec039d..95d4ff4 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -75,8 +75,10 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_contentsImage(0), m_extra(0), m_uniqueId(++gUniqueId), - m_texture(0), - m_pictureUsed(0) + m_drawingTexture(0), + m_reservedTexture(0), + m_pictureUsed(0), + m_scale(1) { m_backgroundColor = 0; @@ -91,7 +93,8 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_haveClip(layer.m_haveClip), m_extra(0), // deliberately not copied m_uniqueId(layer.m_uniqueId), - m_texture(0) + m_drawingTexture(0), + m_reservedTexture(0) { m_isFixed = layer.m_isFixed; m_contentsImage = layer.m_contentsImage; @@ -119,6 +122,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_childrenTransform = layer.m_childrenTransform; m_dirty = layer.m_dirty; m_pictureUsed = layer.m_pictureUsed; + m_scale = layer.m_scale; for (int i = 0; i < layer.countChildren(); i++) addChild(layer.getChild(i)->copy())->unref(); @@ -138,7 +142,9 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), m_contentsImage(0), m_extra(0), m_uniqueId(-1), - m_texture(0) + m_drawingTexture(0), + m_reservedTexture(0), + m_scale(1) { m_backgroundColor = 0; m_dirty = false; @@ -146,10 +152,33 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), gDebugLayerAndroidInstances++; } +void LayerAndroid::removeTexture(BackedDoubleBufferedTexture* aTexture) +{ + LayerTexture* texture = static_cast<LayerTexture*>(aTexture); + android::AutoMutex lock(m_atomicSync); + if (!texture) { // remove ourself from both textures + if (m_drawingTexture) + m_drawingTexture->release(this); + if (m_reservedTexture && + m_reservedTexture != m_drawingTexture) + m_reservedTexture->release(this); + } else { + if (m_drawingTexture && m_drawingTexture == texture) + m_drawingTexture->release(this); + if (m_reservedTexture && + m_reservedTexture == texture && + m_reservedTexture != m_drawingTexture) + m_reservedTexture->release(this); + } + if (m_drawingTexture && m_drawingTexture->owner() != this) + m_drawingTexture = 0; + if (m_reservedTexture && m_reservedTexture->owner() != this) + m_reservedTexture = 0; +} + LayerAndroid::~LayerAndroid() { - if (m_texture) - m_texture->release(this); + removeTexture(0); removeChildren(); m_contentsImage->safeUnref(); m_recordingPicture->safeUnref(); @@ -521,6 +550,7 @@ void LayerAndroid::updateGLPositions(const TransformationMatrix& parentMatrix, localMatrix.setM34(0); localMatrix.setM43(0); } + // now apply it to our children if (!m_childrenTransform.isIdentity()) { @@ -549,12 +579,31 @@ void LayerAndroid::reserveGLTextures() for (int i = 0; i < count; i++) this->getChild(i)->reserveGLTextures(); + LayerTexture* reservedTexture = 0; if (needsTexture()) { - LayerTexture* texture; - texture = TilesManager::instance()->getExistingTextureForLayer(this); - // SMP flush - android::AutoMutex lock(m_atomicSync); - m_texture = texture; + // Compute the layer size & position we need (clipped to the viewport) + IntRect r(0, 0, getWidth(), getHeight()); + IntRect tr = drawTransform().mapRect(r); + IntRect cr = TilesManager::instance()->shader()->clippedRectWithViewport(tr); + m_layerTextureRect = drawTransform().inverse().mapRect(cr); + + reservedTexture = TilesManager::instance()->getExistingTextureForLayer(this, m_layerTextureRect); + + // If we do not have a drawing texture (i.e. new LayerAndroid tree), + // we get any one available. + if (!m_drawingTexture) + m_drawingTexture = TilesManager::instance()->getExistingTextureForLayer(this, m_layerTextureRect, true); + } + + // SMP flush + android::AutoMutex lock(m_atomicSync); + // we set the reservedTexture if it's different from the drawing texture + if (m_reservedTexture != reservedTexture && + ((m_reservedTexture != m_drawingTexture) || + (m_reservedTexture == 0 && m_drawingTexture == 0))) { + if (m_reservedTexture) + m_reservedTexture->release(this); + m_reservedTexture = reservedTexture; } } @@ -564,46 +613,56 @@ void LayerAndroid::createGLTextures() for (int i = 0; i < count; i++) this->getChild(i)->createGLTextures(); - if (needsTexture() && !m_texture) { - LayerTexture* texture; - texture = TilesManager::instance()->createTextureForLayer(this); - // SMP flush + keep dirty bit in sync - android::AutoMutex lock(m_atomicSync); - m_texture = texture; - m_dirty = true; + if (!needsTexture()) + return; + + LayerTexture* reservedTexture = m_reservedTexture; + if (!reservedTexture) + reservedTexture = TilesManager::instance()->createTextureForLayer(this, m_layerTextureRect); + + if (!reservedTexture) + return; + + // SMP flush + m_atomicSync.lock(); + m_reservedTexture = reservedTexture; + m_atomicSync.unlock(); + + if (reservedTexture && + (reservedTexture != m_drawingTexture) && + reservedTexture->isReady()) { + if (m_drawingTexture) { + TilesManager::instance()->removeOperationsForTexture(m_drawingTexture); + m_drawingTexture->release(this); + } + m_drawingTexture = reservedTexture; } - checkForObsolescence(); + if (!needsScheduleRepaint(reservedTexture)) + return; + + XLOG("We schedule a paint for layer %d, because isReady %d or m_dirty %d, using texture %x", + uniqueId(), m_reservedTexture->isReady(), m_dirty, m_reservedTexture); + PaintLayerOperation* operation = new PaintLayerOperation(this); + TilesManager::instance()->scheduleOperation(operation); } -void LayerAndroid::checkForObsolescence() +bool LayerAndroid::needsScheduleRepaint(LayerTexture* texture) { - m_atomicSync.lock(); - if (!m_texture) { - m_atomicSync.unlock(); - return; - } + if (!texture) + return false; - if (!m_pictureUsed || m_texture->pictureUsed() != m_pictureUsed) { + if (!m_pictureUsed || texture->pictureUsed() != m_pictureUsed) { XLOG("We mark layer %d as dirty because: m_pictureUsed(%d == 0?), texture picture used %x", - uniqueId(), m_pictureUsed, m_texture->pictureUsed()); - m_texture->setPictureUsed(m_pictureUsed); + uniqueId(), m_pictureUsed, texture->pictureUsed()); + texture->setPictureUsed(m_pictureUsed); m_dirty = true; } - if (!m_texture->isReady()) + if (!texture->isReady()) m_dirty = true; - bool dirty = m_dirty; - m_atomicSync.unlock(); - - if (!dirty) - return; - - XLOG("We schedule a paint for layer %d, because isReady %d or m_dirty %d", - uniqueId(), m_texture->isReady(), m_dirty); - PaintLayerOperation* operation = new PaintLayerOperation(this); - TilesManager::instance()->scheduleOperation(operation); + return m_dirty; } static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b) @@ -621,14 +680,20 @@ bool LayerAndroid::drawGL(SkMatrix& matrix) TilesManager::instance()->shader()->clip(m_clippingRect); - if (prepareContext() && m_texture) { - TextureInfo* textureInfo = m_texture->consumerLock(); - if (textureInfo && m_texture->isReady()) { - TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), rect, + if (prepareContext() && m_drawingTexture) { + TextureInfo* textureInfo = m_drawingTexture->consumerLock(); + if (textureInfo && m_drawingTexture->isReady()) { + SkRect bounds; + IntRect textureRect = m_drawingTexture->rect(); + bounds.set(0, 0, textureRect.width(), textureRect.height()); + // move the drawing depending on where the texture is on the layer + TransformationMatrix m = drawTransform(); + m.translate(textureRect.x(), textureRect.y()); + TilesManager::instance()->shader()->drawLayerQuad(m, bounds, textureInfo->m_textureId, m_drawOpacity); } - m_texture->consumerRelease(); + m_drawingTexture->consumerRelease(); } // When the layer is dirty, the UI thread should be notified to redraw. @@ -660,24 +725,43 @@ bool LayerAndroid::drawChildrenGL(SkMatrix& matrix) return askPaint; } +void LayerAndroid::setScale(float scale) +{ + int count = this->countChildren(); + for (int i = 0; i < count; i++) + this->getChild(i)->setScale(scale); + + android::AutoMutex lock(m_atomicSync); + m_scale = scale; +} + // This is called from the texture generation thread void LayerAndroid::paintBitmapGL() { - XLOG("LayerAndroid paintBitmapGL (layer %d)", uniqueId()); // We acquire the values below atomically. This ensures that we are reading // values correctly across cores. Further, once we have these values they // can be updated by other threads without consequence. m_atomicSync.lock(); - LayerTexture* texture = m_texture; - m_atomicSync.unlock(); + LayerTexture* texture = m_reservedTexture; if (!texture) { + m_atomicSync.unlock(); XLOG("Layer %d doesn't have a texture!", uniqueId()); return; } + XLOG("LayerAndroid paintBitmapGL (layer %d), texture used %x", uniqueId(), texture); + + // We need to mark the texture as busy before relinquishing the lock + // -- so that TilesManager::cleanupLayersTextures() can check if the texture + // is used before trying to destroy it + // If LayerAndroid::removeTexture() is called before us, we'd have bailed + // out early as texture would have been null; if it is called after us, we'd + // have marked the texture has being busy, and the texture will not be + // destroy immediately. texture->producerAcquireContext(); TextureInfo* textureInfo = texture->producerLock(); + m_atomicSync.unlock(); // at this point we can safely check the ownership (if the texture got // transferred to another BaseTile under us) @@ -688,9 +772,16 @@ void LayerAndroid::paintBitmapGL() XLOG("LayerAndroid %d paintBitmapGL WE ARE PAINTING", uniqueId()); SkCanvas* canvas = texture->canvas(); + float scale = texture->scale(); + + IntRect textureRect = texture->rect(); + canvas->save(); canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); + canvas->scale(scale, scale); + canvas->translate(-textureRect.x(), -textureRect.y()); contentDraw(canvas); + canvas->restore(); XLOG("LayerAndroid %d paintBitmapGL PAINTING DONE, updating the texture", uniqueId()); m_atomicSync.lock(); diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h index 76b4cb8..95f8547 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.h +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -94,11 +94,9 @@ public: virtual ~LayerAndroid(); // TextureOwner methods - virtual void removeTexture() - { - android::AutoMutex lock(m_atomicSync); - m_texture = 0; - } + virtual void removeTexture(BackedDoubleBufferedTexture* texture); + + LayerTexture* texture() { return m_reservedTexture; } virtual TiledPage* page() { return 0; } static int instancesCount(); @@ -111,8 +109,10 @@ public: void createGLTextures(); virtual bool needsTexture(); - void checkForObsolescence(); + bool needsScheduleRepaint(LayerTexture* texture); + void setScale(float scale); + float getScale() { return m_scale; } virtual bool drawGL(SkMatrix&); bool drawChildrenGL(SkMatrix&); virtual void paintBitmapGL(); @@ -285,12 +285,24 @@ private: DrawExtra* m_extra; int m_uniqueId; - // GL textures management - LayerTexture* m_texture; + // We have two textures pointers -- one if the texture we are currently + // using to draw (m_drawingTexture), the other one is the one we get + // from trying to reserve a texture from the TilesManager. Usually, they + // are identical, but in some cases they are not (different scaling + // resulting in the need for different geometry, at initilisation, and + // if the texture asked does not fit in memory) + LayerTexture* m_drawingTexture; + LayerTexture* m_reservedTexture; + + // rect used to query TilesManager for the right texture + IntRect m_layerTextureRect; + // used to signal that the tile is out-of-date and needs to be redrawn bool m_dirty; unsigned int m_pictureUsed; + float m_scale; + // This mutex serves two purposes. (1) It ensures that certain operations // happen atomically and (2) it makes sure those operations are synchronized // across all threads and cores. diff --git a/WebCore/platform/graphics/android/LayerTexture.h b/WebCore/platform/graphics/android/LayerTexture.h index 959978f..3654476 100644 --- a/WebCore/platform/graphics/android/LayerTexture.h +++ b/WebCore/platform/graphics/android/LayerTexture.h @@ -27,6 +27,7 @@ #define LayerTexture_h #include "BackedDoubleBufferedTexture.h" +#include "IntRect.h" namespace WebCore { @@ -36,9 +37,11 @@ class LayerTexture : public BackedDoubleBufferedTexture { SkBitmap::Config config = SkBitmap::kARGB_8888_Config) : BackedDoubleBufferedTexture(w, h, config) , m_id(0) + , m_scale(1) , m_pictureUsed(0) , m_textureUpdates(0) {} + virtual ~LayerTexture() {}; int id() { return m_id; } void setId(int id) { m_id = id; } @@ -47,11 +50,17 @@ class LayerTexture : public BackedDoubleBufferedTexture { void setPictureUsed(unsigned pictureUsed) { m_pictureUsed = pictureUsed; } bool isReady(); virtual void producerUpdate(TextureInfo* textureInfo); + void setRect(const IntRect& r) { m_rect = r; } + IntRect& rect() { return m_rect; } + float scale() { return m_scale; } + void setScale(float scale) { m_scale = scale; } private: void update(); int m_id; + IntRect m_rect; + float m_scale; unsigned int m_pictureUsed; unsigned int m_textureUpdates; }; diff --git a/WebCore/platform/graphics/android/PaintLayerOperation.cpp b/WebCore/platform/graphics/android/PaintLayerOperation.cpp index a3ef148..dd81d9a 100644 --- a/WebCore/platform/graphics/android/PaintLayerOperation.cpp +++ b/WebCore/platform/graphics/android/PaintLayerOperation.cpp @@ -50,7 +50,14 @@ SkLayer* PaintLayerOperation::baseLayer() return m_layer->getRootLayer(); } -bool PaintLayerFilter::check(QueuedOperation* operation) +LayerTexture* PaintLayerOperation::texture() +{ + if (!m_layer) + return 0; + return m_layer->texture(); +} + +bool PaintLayerBaseFilter::check(QueuedOperation* operation) { if (operation->type() == QueuedOperation::PaintLayer) { PaintLayerOperation* op = static_cast<PaintLayerOperation*>(operation); @@ -59,3 +66,13 @@ bool PaintLayerFilter::check(QueuedOperation* operation) } return false; } + +bool PaintLayerTextureFilter::check(QueuedOperation* operation) +{ + if (operation->type() == QueuedOperation::PaintLayer) { + PaintLayerOperation* op = static_cast<PaintLayerOperation*>(operation); + if (op->texture() == m_texture) + return true; + } + return false; +} diff --git a/WebCore/platform/graphics/android/PaintLayerOperation.h b/WebCore/platform/graphics/android/PaintLayerOperation.h index d393ac5..74e87af 100644 --- a/WebCore/platform/graphics/android/PaintLayerOperation.h +++ b/WebCore/platform/graphics/android/PaintLayerOperation.h @@ -33,6 +33,7 @@ class SkLayer; namespace WebCore { class LayerAndroid; +class LayerTexture; class PaintLayerOperation : public QueuedOperation { public: @@ -43,20 +44,31 @@ class PaintLayerOperation : public QueuedOperation { virtual bool operator==(const QueuedOperation* operation); virtual void run(); SkLayer* baseLayer(); + LayerAndroid* layer() { return m_layer; } + LayerTexture* texture(); private: LayerAndroid* m_layer; }; -class PaintLayerFilter : public OperationFilter { +class PaintLayerBaseFilter : public OperationFilter { public: - PaintLayerFilter(SkLayer* layer) : m_baseLayer(layer) {} + PaintLayerBaseFilter(SkLayer* layer) : m_baseLayer(layer) {} virtual bool check(QueuedOperation* operation); private: SkLayer* m_baseLayer; }; +class PaintLayerTextureFilter : public OperationFilter { + public: + PaintLayerTextureFilter(LayerTexture* texture) : m_texture(texture) {} + virtual bool check(QueuedOperation* operation); + + private: + LayerTexture* m_texture; +}; + } #endif // PaintLayerOperation_h diff --git a/WebCore/platform/graphics/android/ShaderProgram.cpp b/WebCore/platform/graphics/android/ShaderProgram.cpp index f61186a..dc6577c 100644 --- a/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -231,6 +231,14 @@ void ShaderProgram::clip(const FloatRect& clip) m_clipRect = clip; } +IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect) +{ + IntRect viewport(m_viewport.fLeft, m_viewport.fTop, + m_viewport.width(), m_viewport.height()); + viewport.intersect(rect); + return viewport; +} + void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, SkRect& geometry, int textureId, float opacity) { diff --git a/WebCore/platform/graphics/android/ShaderProgram.h b/WebCore/platform/graphics/android/ShaderProgram.h index 6508fdb..68cc560 100644 --- a/WebCore/platform/graphics/android/ShaderProgram.h +++ b/WebCore/platform/graphics/android/ShaderProgram.h @@ -44,6 +44,7 @@ class ShaderProgram { FloatRect clipRectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size); void clip(const FloatRect& rect); + IntRect clippedRectWithViewport(const IntRect& rect); private: GLuint loadShader(GLenum shaderType, const char* pSource); diff --git a/WebCore/platform/graphics/android/TextureOwner.h b/WebCore/platform/graphics/android/TextureOwner.h index 959b2bd..7b0673d 100644 --- a/WebCore/platform/graphics/android/TextureOwner.h +++ b/WebCore/platform/graphics/android/TextureOwner.h @@ -29,11 +29,12 @@ namespace WebCore { class TiledPage; +class BackedDoubleBufferedTexture; class TextureOwner { public: virtual ~TextureOwner() {} - virtual void removeTexture() = 0; + virtual void removeTexture(BackedDoubleBufferedTexture* texture) = 0; virtual TiledPage* page() = 0; }; diff --git a/WebCore/platform/graphics/android/TexturesGenerator.cpp b/WebCore/platform/graphics/android/TexturesGenerator.cpp index 289665d..62cadc3 100644 --- a/WebCore/platform/graphics/android/TexturesGenerator.cpp +++ b/WebCore/platform/graphics/android/TexturesGenerator.cpp @@ -80,7 +80,12 @@ void TexturesGenerator::removeOperationsForPage(TiledPage* page) void TexturesGenerator::removeOperationsForBaseLayer(BaseLayerAndroid* layer) { - removeOperationsForFilter(new PaintLayerFilter(layer)); + removeOperationsForFilter(new PaintLayerBaseFilter(layer)); +} + +void TexturesGenerator::removeOperationsForTexture(LayerTexture* texture) +{ + removeOperationsForFilter(new PaintLayerTextureFilter(texture)); } void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) @@ -106,11 +111,15 @@ void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) if (!m_waitForCompletion) return; - // At this point, it means that we are currently painting a operation that - // we want to be removed -- we should wait until it is painted, so that - // when we return our caller can be sure that there is no more TileSet - // in the queue for that TiledPage and can safely deallocate the BaseTiles. + // At this point, it means that we are currently executing an operation that + // we want to be removed -- we should wait until it is done, so that + // when we return our caller can be sure that there is no more operations + // in the queue matching the given filter. mRequestedOperationsLock.lock(); + if (!m_waitForCompletion) { + mRequestedOperationsLock.unlock(); + return; // operation treated + } mRequestedOperationsCond.wait(mRequestedOperationsLock); m_waitForCompletion = false; mRequestedOperationsLock.unlock(); diff --git a/WebCore/platform/graphics/android/TexturesGenerator.h b/WebCore/platform/graphics/android/TexturesGenerator.h index 0e40e4a..d98eb5b 100644 --- a/WebCore/platform/graphics/android/TexturesGenerator.h +++ b/WebCore/platform/graphics/android/TexturesGenerator.h @@ -28,6 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "LayerTexture.h" #include "QueuedOperation.h" #include "TileSet.h" #include "TiledPage.h" @@ -50,6 +51,7 @@ public: void removeOperationsForPage(TiledPage* page); void removeOperationsForBaseLayer(BaseLayerAndroid* layer); + void removeOperationsForTexture(LayerTexture* texture); void removeOperationsForFilter(OperationFilter* filter); void scheduleOperation(QueuedOperation* operation); diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp index 3e174d1..1655016 100644 --- a/WebCore/platform/graphics/android/TilesManager.cpp +++ b/WebCore/platform/graphics/android/TilesManager.cpp @@ -84,6 +84,10 @@ TilesManager::TilesManager() m_pixmapsGenerationThread = new TexturesGenerator(); m_pixmapsGenerationThread->run("TexturesGenerator"); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); + m_totalMaxTextureSize = m_maxTextureSize * m_maxTextureSize * BYTES_PER_PIXEL; + XLOG("Max texture size %d", m_maxTextureSize); } // Has to be run on the texture generation threads @@ -226,13 +230,17 @@ BackedDoubleBufferedTexture* TilesManager::getAvailableTexture(BaseTile* owner) return 0; } -LayerTexture* TilesManager::getExistingTextureForLayer(LayerAndroid* layer) +LayerTexture* TilesManager::getExistingTextureForLayer(LayerAndroid* layer, + const IntRect& rect, + bool any) { android::Mutex::Autolock lock(m_texturesLock); for (unsigned int i = 0; i< m_layersTextures.size(); i++) { if (m_layersTextures[i]->id() != layer->uniqueId()) continue; - if (layer->getSize() != m_layersTextures[i]->getSize()) + if (!any && rect != m_layersTextures[i]->rect()) + continue; + if (!any && layer->getScale() != m_layersTextures[i]->scale()) continue; XLOG("return layer %d (%x) for tile %d (%x)", @@ -248,46 +256,105 @@ LayerTexture* TilesManager::getExistingTextureForLayer(LayerAndroid* layer) void TilesManager::printLayersTextures(const char* s) { #ifdef DEBUG + XLOG(">>> print layers textures (%s)", s); for (unsigned int i = 0; i< m_layersTextures.size(); i++) { - XLOG("[%d] %s, texture %x for layer %d, owner: %x", i, s, m_layersTextures[i], - m_layersTextures[i]->id(), m_layersTextures[i]->owner()); + XLOG("[%d] %s, texture %x for layer %d (w: %.2f, h: %.2f), owner: %x", + i, s, m_layersTextures[i], + m_layersTextures[i]->id(), + m_layersTextures[i]->getSize().fWidth, + m_layersTextures[i]->getSize().fHeight, + m_layersTextures[i]->owner()); } + XLOG("<<< print layers textures (%s)", s); #endif } -void TilesManager::cleanupLayersTextures(bool forceCleanup) +void TilesManager::cleanupLayersTextures(LayerAndroid* layer, bool forceCleanup) { android::Mutex::Autolock lock(m_texturesLock); + SkLayer* rootLayer = layer->getRootLayer(); #ifdef DEBUG - printLayersTextures("cleanup"); + if (forceCleanup) + XLOG("FORCE cleanup"); + XLOG("before cleanup, memory %d", m_layersMemoryUsage); + printLayersTextures("before cleanup"); #endif - for (unsigned int i = 0; i< m_layersTextures.size(); i++) { + for (unsigned int i = 0; i< m_layersTextures.size();) { LayerTexture* texture = m_layersTextures[i]; - if (forceCleanup) - texture->setOwner(0); + if (forceCleanup && texture->owner()) { + LayerAndroid* textureLayer = + static_cast<LayerAndroid*>(texture->owner()); + if (textureLayer->getRootLayer() != rootLayer) { + // We only want to force destroy layers + // that are not used by the current page + XLOG("force removing texture %x for layer %d", + texture, textureLayer->uniqueId()); + textureLayer->removeTexture(texture); + } + } - if (!texture->owner()) { + // We only try to destroy textures that have no owners. + // This could be due to: + // 1) - the LayerAndroid dtor has been called (i.e. when swapping + // a LayerAndroid tree with a new one) + // 2) - or due to the above code, forcing a destroy. + // If the texture has been forced to be released (case #2), it + // could still be in use (in the middle of being painted). So we + // need to check that's not the case by checking busy(). See + // LayerAndroid::paintBitmapGL(). + if (!texture->owner() && !texture->busy()) { m_layersMemoryUsage -= (int) texture->getSize().fWidth * (int) texture->getSize().fHeight * BYTES_PER_PIXEL; m_layersTextures.remove(i); + // We can destroy the texture. We first remove it from the textures + // list, and then remove any queued drawing. At this point we know + // the texture has been removed from the layer, and that it's not + // busy, so it's safe to delete. + m_pixmapsGenerationThread->removeOperationsForTexture(texture); + XLOG("delete texture %x", texture); delete texture; + } else { + // only iterate if we don't delete (if we delete, no need to as we + // remove the element from the array) + i++; } } + printLayersTextures("after cleanup"); + XLOG("after cleanup, memory %d", m_layersMemoryUsage); } -LayerTexture* TilesManager::createTextureForLayer(LayerAndroid* layer) +LayerTexture* TilesManager::createTextureForLayer(LayerAndroid* layer, const IntRect& rect) { - int w = layer->getWidth(); - int h = layer->getHeight(); - int size = w * h * BYTES_PER_PIXEL; + int w = rect.width() * layer->getScale(); + int h = rect.height() * layer->getScale(); + unsigned int size = w * h * BYTES_PER_PIXEL; + + // We will not allocate textures that: + // 1) cannot be handled by the graphic card (m_maxTextureSize & + // m_totalMaxTextureSize) + // 2) will make us go past our texture limit (MAX_LAYERS_ALLOCATION) + + bool large = w > m_maxTextureSize || h > m_maxTextureSize || size > m_totalMaxTextureSize; + XLOG("createTextureForLayer(%d) @scale %.2f => %d, %d (too large? %x)", layer->uniqueId(), + layer->getScale(), w, h, large); + + // For now just return 0 if too large + if (large) + return 0; + + if (w == 0 || h == 0) // empty layer + return 0; if (m_layersMemoryUsage + size > MAX_LAYERS_ALLOCATION) - cleanupLayersTextures(true); + cleanupLayersTextures(layer, true); - android::Mutex::Autolock lock(m_texturesLock); LayerTexture* texture = new LayerTexture(w, h); texture->setId(layer->uniqueId()); + texture->setRect(rect); + texture->setScale(layer->getScale()); + + android::Mutex::Autolock lock(m_texturesLock); m_layersTextures.append(texture); texture->acquire(layer); m_layersMemoryUsage += size; diff --git a/WebCore/platform/graphics/android/TilesManager.h b/WebCore/platform/graphics/android/TilesManager.h index e69db4c..c09a388 100644 --- a/WebCore/platform/graphics/android/TilesManager.h +++ b/WebCore/platform/graphics/android/TilesManager.h @@ -55,6 +55,11 @@ public: m_pixmapsGenerationThread->removeOperationsForBaseLayer(layer); } + void removeOperationsForTexture(LayerTexture* texture) + { + m_pixmapsGenerationThread->removeOperationsForTexture(texture); + } + void scheduleOperation(QueuedOperation* operation) { m_pixmapsGenerationThread->scheduleOperation(operation); @@ -65,14 +70,16 @@ public: BackedDoubleBufferedTexture* getAvailableTexture(BaseTile* owner); void printLayersTextures(const char* s); - void cleanupLayersTextures(bool forceCleanup = false); - LayerTexture* getExistingTextureForLayer(LayerAndroid* layer); - LayerTexture* createTextureForLayer(LayerAndroid* layer); + void cleanupLayersTextures(LayerAndroid* layer, bool forceCleanup = false); + LayerTexture* getExistingTextureForLayer(LayerAndroid* layer, const IntRect& rect, + bool any = false); + LayerTexture* createTextureForLayer(LayerAndroid* layer, const IntRect& rect); void markGeneratorAsReady() { android::Mutex::Autolock lock(m_generatorLock); m_generatorReadyCond.signal(); + m_generatorReady = true; } void printTextures(); @@ -92,13 +99,16 @@ private: void waitForGenerator() { android::Mutex::Autolock lock(m_generatorLock); - m_generatorReadyCond.wait(m_generatorLock); + if (!m_generatorReady) + m_generatorReadyCond.wait(m_generatorLock); } Vector<BackedDoubleBufferedTexture*> m_textures; Vector<LayerTexture*> m_layersTextures; unsigned int m_layersMemoryUsage; + GLint m_maxTextureSize; + unsigned int m_totalMaxTextureSize; bool m_generatorReady; diff --git a/WebCore/rendering/RenderIFrame.cpp b/WebCore/rendering/RenderIFrame.cpp index a2cf66c..36d2449 100644 --- a/WebCore/rendering/RenderIFrame.cpp +++ b/WebCore/rendering/RenderIFrame.cpp @@ -266,6 +266,13 @@ bool RenderIFrame::requiresAcceleratedCompositing() const if (!node() || !node()->hasTagName(iframeTag)) return false; +#if PLATFORM(ANDROID) + // XXX: Bug submitted to webkit.org + // https://bugs.webkit.org/show_bug.cgi?id=52655 + if (style()->visibility() != VISIBLE) + return false; +#endif + // If the contents of the iframe are composited, then we have to be as well. HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(node()); if (Document* contentDocument = element->contentDocument()) { diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index 654f6e6..0877468 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -591,13 +591,12 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O if (layer->isFixed()) compositingState.m_fixedSibling = true; - if (!willBeComposited && compositingState.m_fixedSibling) + if (!willBeComposited && compositingState.m_fixedSibling) { layer->setMustOverlapCompositedLayers(true); - - if (willBeComposited || compositingState.m_fixedSibling) { -#else - if (willBeComposited) { + willBeComposited = true; + } #endif + if (willBeComposited) { // Tell the parent it has compositing descendants. compositingState.m_subtreeIsCompositing = true; // This layer now acts as the ancestor for kids. |