diff options
author | John Reck <jreck@google.com> | 2012-03-20 10:01:59 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-03-20 10:01:59 -0700 |
commit | 92f133bc695b6812d789c6e71feab3b6a8557ad1 (patch) | |
tree | 9e567e7775afd37d3d214ee78f44ff46720480d6 | |
parent | 696cf3d1df6a07f13757e175b190aae7dc2d405c (diff) | |
parent | a144ac64329978c258faadf3bc484cf4ae6c5d0d (diff) | |
download | external_webkit-92f133bc695b6812d789c6e71feab3b6a8557ad1.zip external_webkit-92f133bc695b6812d789c6e71feab3b6a8557ad1.tar.gz external_webkit-92f133bc695b6812d789c6e71feab3b6a8557ad1.tar.bz2 |
Merge "Canvas on a texture"
-rw-r--r-- | Source/WebCore/Android.mk | 2 | ||||
-rw-r--r-- | Source/WebCore/html/HTMLCanvasElement.cpp | 6 | ||||
-rw-r--r-- | Source/WebCore/html/HTMLCanvasElement.h | 4 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/CanvasLayer.cpp | 188 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/CanvasLayer.h | 81 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/CanvasTexture.cpp | 214 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/CanvasTexture.h | 96 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/GLUtils.cpp | 37 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/GLUtils.h | 3 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp | 7 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/LayerAndroid.cpp | 10 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/LayerAndroid.h | 11 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/TransferQueue.cpp | 27 | ||||
-rw-r--r-- | Source/WebKit/android/AndroidLog.h | 25 | ||||
-rw-r--r-- | Source/WebKit/android/nav/WebView.cpp | 20 |
15 files changed, 697 insertions, 34 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index 816b163..710408f 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -639,6 +639,8 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/BaseTile.cpp \ platform/graphics/android/BaseTileTexture.cpp \ platform/graphics/android/BitmapAllocatorAndroid.cpp \ + platform/graphics/android/CanvasLayer.cpp \ + platform/graphics/android/CanvasTexture.cpp \ platform/graphics/android/ClassTracker.cpp \ platform/graphics/android/DumpLayer.cpp \ platform/graphics/android/FixedPositioning.cpp \ diff --git a/Source/WebCore/html/HTMLCanvasElement.cpp b/Source/WebCore/html/HTMLCanvasElement.cpp index 9f51f10..e67cbf9 100644 --- a/Source/WebCore/html/HTMLCanvasElement.cpp +++ b/Source/WebCore/html/HTMLCanvasElement.cpp @@ -45,6 +45,7 @@ #include "MIMETypeRegistry.h" #include "Page.h" #include "RenderHTMLCanvas.h" +#include "RenderLayer.h" #include "Settings.h" #include <math.h> #include <stdio.h> @@ -225,6 +226,11 @@ void HTMLCanvasElement::didDraw(const FloatRect& rect) return; m_dirtyRect.unite(r); +#if PLATFORM(ANDROID) + // We handle invals ourselves and don't want webkit to repaint if we + // have put the canvas on a layer + if (!ro->hasLayer()) +#endif ro->repaintRectangle(enclosingIntRect(m_dirtyRect)); } diff --git a/Source/WebCore/html/HTMLCanvasElement.h b/Source/WebCore/html/HTMLCanvasElement.h index 207c384..e485835 100644 --- a/Source/WebCore/html/HTMLCanvasElement.h +++ b/Source/WebCore/html/HTMLCanvasElement.h @@ -128,6 +128,10 @@ public: void makeRenderingResultsAvailable(); +#if PLATFORM(ANDROID) + void clearDirtyRect() { m_dirtyRect = FloatRect(); } +#endif + private: HTMLCanvasElement(const QualifiedName&, Document*); diff --git a/Source/WebCore/platform/graphics/android/CanvasLayer.cpp b/Source/WebCore/platform/graphics/android/CanvasLayer.cpp new file mode 100644 index 0000000..98cd5ee --- /dev/null +++ b/Source/WebCore/platform/graphics/android/CanvasLayer.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "CanvasLayer" +#define LOG_NDEBUG 1 + +#include "config.h" +#include "CanvasLayer.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "AndroidLog.h" +#include "CanvasTexture.h" +#include "Image.h" +#include "ImageBuffer.h" +#include "RenderLayerCompositor.h" +#include "SkBitmap.h" +#include "SkBitmapRef.h" +#include "SkCanvas.h" +#include "TilesManager.h" + +namespace WebCore { + +CanvasLayer::CanvasLayer(RenderLayer* owner, HTMLCanvasElement* canvas) + : LayerAndroid(owner) + , m_canvas(canvas) + , m_dirtyCanvas() + , m_bitmap(0) +{ + init(); + m_canvas->addObserver(this); +} + +CanvasLayer::CanvasLayer(const CanvasLayer& layer) + : LayerAndroid(layer) + , m_canvas(0) + , m_bitmap(0) +{ + init(); + // We are making a copy for the UI, sync the interesting bits + m_contentRect = layer.contentRect(); + m_offsetFromRenderer = layer.offsetFromRenderer(); + m_texture->setSize(m_contentRect.size()); + bool previousState = m_texture->hasValidTexture(); + // Attempt to upload to a surface texture + if (!m_texture->uploadImageBuffer(layer.m_canvas->buffer())) { + // Blargh, no surface texture - fall back to software + m_bitmap = layer.bitmap(); + SkSafeRef(m_bitmap); + // Merge the canvas invals with the layer's invals to repaint the needed + // tiles. + SkRegion::Iterator iter(layer.m_dirtyCanvas); + const IntPoint& offset = m_contentRect.location(); + for (; !iter.done(); iter.next()) { + SkIRect diff = iter.rect(); + diff.fLeft += offset.x(); + diff.fRight += offset.x(); + diff.fTop += offset.y(); + diff.fBottom += offset.y(); + m_dirtyRegion.op(diff, SkRegion::kUnion_Op); + } + } + if (previousState != m_texture->hasValidTexture()) { + // Need to do a full inval of the canvas content as we are mode switching + m_dirtyRegion.op(m_contentRect.x(), m_contentRect.y(), + m_contentRect.maxX(), m_contentRect.maxY(), SkRegion::kUnion_Op); + } +} + +CanvasLayer::~CanvasLayer() +{ + if (m_canvas) + m_canvas->removeObserver(this); + SkSafeUnref(m_bitmap); +} + +void CanvasLayer::init() +{ + m_texture = CanvasTexture::getCanvasTexture(this); +} + +void CanvasLayer::canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect) +{ + SkIRect irect = SkIRect::MakeXYWH(changedRect.x(), changedRect.y(), + changedRect.width(), changedRect.height()); + m_dirtyCanvas.op(irect, SkRegion::kUnion_Op); + owningLayer()->compositor()->scheduleLayerFlush(); +} + +void CanvasLayer::canvasResized(HTMLCanvasElement*) +{ + const IntSize& size = m_canvas->size(); + SkIRect irect = SkIRect::MakeWH(size.width(), size.height()); + m_dirtyCanvas.op(irect, SkRegion::kUnion_Op); +} + +void CanvasLayer::canvasDestroyed(HTMLCanvasElement*) +{ +} + +void CanvasLayer::clearDirtyRegion() +{ + LayerAndroid::clearDirtyRegion(); + m_dirtyCanvas.setEmpty(); + if (m_canvas) + m_canvas->clearDirtyRect(); +} + +SkBitmapRef* CanvasLayer::bitmap() const +{ + if (!m_canvas) + return 0; + return m_canvas->copiedImage()->nativeImageForCurrentFrame(); +} + +IntRect CanvasLayer::contentRect() const +{ + return m_canvas->renderBox()->contentBoxRect(); +} + +IntSize CanvasLayer::offsetFromRenderer() const +{ + return m_canvas->renderBox()->layer()->backing()->graphicsLayer()->offsetFromRenderer(); +} + +bool CanvasLayer::needsTexture() +{ + return m_bitmap || LayerAndroid::needsTexture(); +} + +void CanvasLayer::contentDraw(SkCanvas* canvas, PaintStyle style) +{ + LayerAndroid::contentDraw(canvas, style); + if (!m_bitmap) + return; + SkBitmap& bitmap = m_bitmap->bitmap(); + SkRect dst = SkRect::MakeXYWH(m_contentRect.x() - m_offsetFromRenderer.width(), + m_contentRect.y() - m_offsetFromRenderer.height(), + m_contentRect.width(), m_contentRect.height()); + canvas->drawBitmapRect(bitmap, 0, dst, 0); +} + +bool CanvasLayer::drawGL(bool layerTilesDisabled) +{ + bool ret = LayerAndroid::drawGL(layerTilesDisabled); + m_texture->requireTexture(); + if (!m_bitmap && m_texture->updateTexImage()) { + SkRect rect = SkRect::MakeXYWH(m_contentRect.x() - m_offsetFromRenderer.width(), + m_contentRect.y() - m_offsetFromRenderer.height(), + m_contentRect.width(), m_contentRect.height()); + TilesManager::instance()->shader()->drawLayerQuad(m_drawTransform, rect, + m_texture->texture(), 1, true, GL_TEXTURE_EXTERNAL_OES); + } + return ret; +} + +LayerAndroid::InvalidateFlags CanvasLayer::onSetHwAccelerated(bool hwAccelerated) +{ + if (m_texture->setHwAccelerated(hwAccelerated)) + return LayerAndroid::InvalidateLayers; + return LayerAndroid::InvalidateNone; +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/CanvasLayer.h b/Source/WebCore/platform/graphics/android/CanvasLayer.h new file mode 100644 index 0000000..532dbf2 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/CanvasLayer.h @@ -0,0 +1,81 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CanvasLayer_h +#define CanvasLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "HTMLCanvasElement.h" +#include "ImageData.h" +#include "LayerAndroid.h" +#include "RenderLayer.h" + +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CanvasTexture; + +class CanvasLayer : public LayerAndroid, private CanvasObserver { +public: + CanvasLayer(RenderLayer* owner, HTMLCanvasElement* canvas); + CanvasLayer(const CanvasLayer& layer); + virtual ~CanvasLayer(); + + virtual LayerAndroid* copy() const { return new CanvasLayer(*this); } + virtual SubclassType subclassType() { return LayerAndroid::CanvasLayer; } + virtual void clearDirtyRegion(); + + virtual bool drawGL(bool layerTilesDisabled); + virtual void contentDraw(SkCanvas* canvas, PaintStyle style); + virtual bool needsTexture(); + +protected: + virtual InvalidateFlags onSetHwAccelerated(bool hwAccelerated); + +private: + virtual void canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect); + virtual void canvasResized(HTMLCanvasElement*); + virtual void canvasDestroyed(HTMLCanvasElement*); + + void init(); + SkBitmapRef* bitmap() const; + IntRect contentRect() const; + IntSize offsetFromRenderer() const; + + HTMLCanvasElement* m_canvas; + IntRect m_contentRect; + IntSize m_offsetFromRenderer; + SkRegion m_dirtyCanvas; + SkBitmapRef* m_bitmap; + RefPtr<CanvasTexture> m_texture; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // CanvasLayer_h diff --git a/Source/WebCore/platform/graphics/android/CanvasTexture.cpp b/Source/WebCore/platform/graphics/android/CanvasTexture.cpp new file mode 100644 index 0000000..90a4798 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/CanvasTexture.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "CanvasTexture" +#define LOG_NDEBUG 1 + +#include "config.h" +#include "CanvasTexture.h" + +#if USE(ACCELERATED_COMPOSITING) + +#include "android_graphics.h" +#include "AndroidLog.h" +#include "GLUtils.h" +#include "Image.h" +#include "ImageBuffer.h" +#include "SkBitmap.h" +#include "SkBitmapRef.h" +#include "SkDevice.h" +#include "SkPixelRef.h" + +#include <android/native_window.h> +#include <gui/SurfaceTexture.h> +#include <gui/SurfaceTextureClient.h> + +namespace WebCore { + +static int s_maxTextureSize = 0; +static HashMap<int, CanvasTexture*> s_textures; +static android::Mutex s_texturesLock; + +/******************************************** + * Called by both threads + ********************************************/ + +PassRefPtr<CanvasTexture> CanvasTexture::getCanvasTexture(CanvasLayer* layer) +{ + android::Mutex::Autolock lock(s_texturesLock); + RefPtr<CanvasTexture> texture = s_textures.get(layer->uniqueId()); + if (texture.get()) + return texture.release(); + return adoptRef(new CanvasTexture(layer->uniqueId())); +} + +/******************************************** + * Called by WebKit thread + ********************************************/ + +void CanvasTexture::setSize(const IntSize& size) +{ + android::Mutex::Autolock lock(m_surfaceLock); + if (m_size == size) + return; + m_size = size; + if (m_ANW.get()) { + if (!useSurfaceTexture()) { + m_ANW.clear(); + m_surfaceTexture->abandon(); + m_surfaceTexture.clear(); + } else { + int result = native_window_set_buffers_dimensions(m_ANW.get(), + m_size.width(), m_size.height()); + GLUtils::checkSurfaceTextureError("native_window_set_buffers_dimensions", result); + } + } +} + +SurfaceTextureClient* CanvasTexture::nativeWindow() +{ + android::Mutex::Autolock lock(m_surfaceLock); + if (m_ANW.get()) + return m_ANW.get(); + if (!m_texture) + return 0; + if (!useSurfaceTexture()) + return 0; + m_surfaceTexture = new android::SurfaceTexture(m_texture, false); + m_ANW = new android::SurfaceTextureClient(m_surfaceTexture); + int result = native_window_set_buffers_format(m_ANW.get(), HAL_PIXEL_FORMAT_RGBA_8888); + GLUtils::checkSurfaceTextureError("native_window_set_buffers_format", result); + result = native_window_set_buffers_dimensions(m_ANW.get(), + m_size.width(), m_size.height()); + GLUtils::checkSurfaceTextureError("native_window_set_buffers_dimensions", result); + return m_ANW.get(); +} + +bool CanvasTexture::uploadImageBuffer(ImageBuffer* imageBuffer) +{ + m_hasValidTexture = false; + SurfaceTextureClient* anw = nativeWindow(); + if (!anw) + return false; + GraphicsContext* gc = imageBuffer ? imageBuffer->context() : 0; + if (!gc) + return false; + const SkBitmap& bitmap = android_gc2canvas(gc)->getDevice()->accessBitmap(false); + GLUtils::updateSharedSurfaceTextureWithBitmap(anw, bitmap); + m_hasValidTexture = true; + return true; +} + +/******************************************** + * Called by UI thread WITH GL context + ********************************************/ + +CanvasTexture::~CanvasTexture() +{ + if (m_layerId) { + s_texturesLock.lock(); + s_textures.remove(m_layerId); + s_texturesLock.unlock(); + } + if (m_texture) + GLUtils::deleteTexture(&m_texture); +} + +void CanvasTexture::requireTexture() +{ + android::Mutex::Autolock lock(m_surfaceLock); + if (!m_texture) + glGenTextures(1, &m_texture); + if (!s_maxTextureSize) + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_maxTextureSize); +} + +bool CanvasTexture::updateTexImage() +{ + android::Mutex::Autolock lock(m_surfaceLock); + if (!m_surfaceTexture.get()) + return false; + status_t result = m_surfaceTexture->updateTexImage(); + if (result != OK) { + ALOGE("unexpected error: updateTexImage return %d", result); + return false; + } + return true; +} + +/******************************************** + * Called by UI thread (with or without GL context) + ********************************************/ + +void CanvasTexture::destroySurfaceTexture() +{ + if (m_ANW.get()) { + m_ANW.clear(); + m_surfaceTexture->abandon(); + m_surfaceTexture.clear(); + } +} + +bool CanvasTexture::setHwAccelerated(bool hwAccelerated) +{ + android::Mutex::Autolock lock(m_surfaceLock); + if (m_useHwAcceleration == hwAccelerated) + return false; + m_useHwAcceleration = hwAccelerated; + if (!m_ANW.get()) + return false; + destroySurfaceTexture(); + return true; +} + +/******************************************** + * Called by WebKit thread + ********************************************/ + +CanvasTexture::CanvasTexture(int layerId) + : m_size() + , m_layerId(layerId) + , m_texture(0) + , m_surfaceTexture(0) + , m_ANW(0) + , m_hasValidTexture(false) + , m_useHwAcceleration(true) +{ + s_textures.add(m_layerId, this); +} + +// TODO: Have a global limit as well as a way to react to low memory situations +bool CanvasTexture::useSurfaceTexture() +{ + if (!m_useHwAcceleration) + return false; + if (m_size.isEmpty()) + return false; + return (m_size.width() < s_maxTextureSize) && (m_size.height() < s_maxTextureSize); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/CanvasTexture.h b/Source/WebCore/platform/graphics/android/CanvasTexture.h new file mode 100644 index 0000000..5e54c77 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/CanvasTexture.h @@ -0,0 +1,96 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CanvasTexture_h +#define CanvasTexture_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "CanvasLayer.h" + +#include <wtf/RefPtr.h> +#include <utils/Mutex.h> +#include <utils/StrongPointer.h> + +namespace android { +class SurfaceTexture; +class SurfaceTextureClient; +} + +namespace WebCore { + +class CanvasTexture : public ThreadSafeRefCounted<CanvasTexture> { + +public: + /******************************************** + * Called by both threads + ********************************************/ + static PassRefPtr<CanvasTexture> getCanvasTexture(CanvasLayer* layer); + + /******************************************** + * Called by WebKit thread + ********************************************/ + void setSize(const IntSize& size); + SurfaceTextureClient* nativeWindow(); + bool uploadImageBuffer(ImageBuffer* imageBuffer); + bool hasValidTexture() { return m_hasValidTexture; } + + /******************************************** + * Called by UI thread WITH GL context + ********************************************/ + virtual ~CanvasTexture(); + void requireTexture(); + GLuint texture() { requireTexture(); return m_texture; } + bool updateTexImage(); + + /******************************************** + * Called by UI thread (with or without GL context) + ********************************************/ + void destroySurfaceTexture(); + bool setHwAccelerated(bool hwAccelerated); + +private: + /******************************************** + * Called by WebKit thread + ********************************************/ + CanvasTexture(int layerId); + bool useSurfaceTexture(); + + IntSize m_size; + int m_layerId; + GLuint m_texture; + android::Mutex m_surfaceLock; + sp<android::SurfaceTexture> m_surfaceTexture; + sp<android::SurfaceTextureClient> m_ANW; + bool m_hasValidTexture; + bool m_useHwAcceleration; + +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // CanvasTexture_h diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index ecd6bce..55d986f 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -493,14 +493,14 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, return; if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height)) - GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap); + GLUtils::updateQueueWithBitmap(renderInfo, bitmap); else { if (!requiredSize.equals(bitmap.width(), bitmap.height())) { ALOGV("The bitmap size (%d,%d) does not equal the texture size (%d,%d)", bitmap.width(), bitmap.height(), requiredSize.width(), requiredSize.height()); } - GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap); + GLUtils::updateQueueWithBitmap(renderInfo, bitmap); textureInfo->m_width = bitmap.width(); textureInfo->m_height = bitmap.height(); @@ -508,7 +508,7 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, } } -void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) +void GLUtils::updateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) { if (!renderInfo || !renderInfo->textureInfo @@ -518,6 +518,37 @@ void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderI TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, bitmap); } +bool GLUtils::updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap) +{ + SkAutoLockPixels alp(bitmap); + if (!bitmap.getPixels()) + return false; + ANativeWindow_Buffer buffer; + if (ANativeWindow_lock(anw, &buffer, 0)) + return false; + if (buffer.width < bitmap.width() || buffer.height < bitmap.height()) + return false; + uint8_t* img = (uint8_t*)buffer.bits; + int row; + int bpp = 4; // Now we only deal with RGBA8888 format. + bitmap.lockPixels(); + uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels()); + + if (buffer.stride != bitmap.width()) + // Copied line by line since we need to handle the offsets and stride. + for (row = 0 ; row < bitmap.height(); row ++) { + uint8_t* dst = &(img[buffer.stride * row * bpp]); + uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]); + memcpy(dst, src, bpp * bitmap.width()); + } + else + memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height()); + + bitmap.unlockPixels(); + ANativeWindow_unlockAndPost(anw); + return true; +} + void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index e001aee..966f674 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -79,7 +79,8 @@ public: static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); - static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap); + static void updateQueueWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap); + static bool updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 2f9b379..fa620e0 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -25,6 +25,7 @@ #include "AndroidAnimation.h" #include "AndroidLog.h" #include "Animation.h" +#include "CanvasLayer.h" #include "FloatRect.h" #include "FixedPositioning.h" #include "GraphicsContext.h" @@ -119,7 +120,11 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_foregroundClipLayer(0) { RenderLayer* renderLayer = renderLayerFromClient(m_client); - m_contentLayer = new LayerAndroid(renderLayer); + if (renderLayer && renderLayer->renderer()->isCanvas()) { + m_contentLayer = new CanvasLayer(renderLayer, + static_cast<HTMLCanvasElement*>(renderLayer->renderer()->node())); + } else + m_contentLayer = new LayerAndroid(renderLayer); m_dirtyRegion.setEmpty(); gDebugGraphicsLayerAndroidInstances++; } diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 946d2a3..6d8dc34 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -791,6 +791,16 @@ void LayerAndroid::clearDirtyRegion() m_dirtyRegion.setEmpty(); } +int LayerAndroid::setHwAccelerated(bool hwAccelerated) +{ + int flags = InvalidateNone; + int count = this->countChildren(); + for (int i = 0; i < count; i++) + flags |= this->getChild(i)->setHwAccelerated(hwAccelerated); + + return flags | onSetHwAccelerated(hwAccelerated); +} + IntRect LayerAndroid::unclippedArea() { IntRect area; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 7436676..43b4ff9 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -93,7 +93,9 @@ class TEST_EXPORT LayerAndroid : public Layer { public: typedef enum { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer } LayerType; typedef enum { StandardLayer, ScrollableLayer, - IFrameLayer, IFrameContentLayer } SubclassType; + IFrameLayer, IFrameContentLayer, + CanvasLayer } SubclassType; + typedef enum { InvalidateNone = 0, InvalidateLayers } InvalidateFlags; String subclassName() { @@ -106,6 +108,8 @@ public: return "IFrameLayer"; case LayerAndroid::IFrameContentLayer: return "IFrameContentLayer"; + case LayerAndroid::CanvasLayer: + return "CanvasLayer"; } return "Undefined"; } @@ -230,7 +234,7 @@ public: virtual LayerAndroid* copy() const { return new LayerAndroid(*this); } - void clearDirtyRegion(); + virtual void clearDirtyRegion(); virtual void contentDraw(SkCanvas* canvas, PaintStyle style); @@ -277,8 +281,11 @@ public: void setIntrinsicallyComposited(bool intCom) { m_intrinsicallyComposited = intCom; } + int setHwAccelerated(bool hwAccelerated); + protected: virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra, PaintStyle style); + virtual InvalidateFlags onSetHwAccelerated(bool hwAccelerated) { return InvalidateNone; } IntPoint m_offset; TransformationMatrix m_drawTransform; diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index ac45112..8e41d15 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -463,33 +463,8 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, return false; } - ANativeWindow_Buffer buffer; - if (ANativeWindow_lock(m_ANW.get(), &buffer, 0)) + if (!GLUtils::updateSharedSurfaceTextureWithBitmap(m_ANW.get(), bitmap)) return false; - - uint8_t* img = (uint8_t*)buffer.bits; - int row; - int bpp = 4; // Now we only deal with RGBA8888 format. - int width = TilesManager::instance()->tileWidth(); - int height = TilesManager::instance()->tileHeight(); - if (bitmap.width() == width && bitmap.height() == height) { - bitmap.lockPixels(); - uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels()); - - if (buffer.stride != bitmap.width()) - // Copied line by line since we need to handle the offsets and stride. - for (row = 0 ; row < bitmap.height(); row ++) { - uint8_t* dst = &(img[buffer.stride * row * bpp]); - uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]); - memcpy(dst, src, bpp * bitmap.width()); - } - else - memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height()); - - bitmap.unlockPixels(); - } - - ANativeWindow_unlockAndPost(m_ANW.get()); } // b) After update the Surface Texture, now udpate the transfer queue info. diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h index 4090ab9..3ac210f 100644 --- a/Source/WebKit/android/AndroidLog.h +++ b/Source/WebKit/android/AndroidLog.h @@ -26,8 +26,14 @@ #ifndef AndroidLog_h #define AndroidLog_h +#ifndef LOG_TAG +#define LOG_TAG __FILE__ +#endif + +#include <cutils/log.h> +#include <wtf/CurrentTime.h> + #ifdef ANDROID_DOM_LOGGING -#include <utils/Log.h> #include <stdio.h> extern FILE* gDomTreeFile; #define DOM_TREE_LOG_FILE "/sdcard/domTree.txt" @@ -46,4 +52,21 @@ extern FILE* gRenderTreeFile; #define DISPLAY_TREE_LOG_FILE "/sdcard/displayTree.txt" #define LAYERS_TREE_LOG_FILE "/sdcard/layersTree.plist" +#define TIME_METHOD() MethodTimer __method_timer(__func__) +class MethodTimer { +public: + MethodTimer(const char* name) + : m_methodName(name) + { + m_startTime = currentTimeMS(); + } + virtual ~MethodTimer() { + double duration = currentTimeMS() - m_startTime; + ALOGD("%s took %.2fms", m_methodName, duration); + } +private: + const char* m_methodName; + double m_startTime; +}; + #endif // AndroidLog_h diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index eddf0ab..0b2eaf6 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -633,6 +633,17 @@ void mapLayerRect(int layerId, SkIRect& rect) { } } +// This is called when WebView switches rendering modes in a more permanent fashion +// such as when the layer type is set or the view is attached/detached from the window +int setHwAccelerated(bool hwAccelerated) { + if (!m_glWebViewState) + return 0; + LayerAndroid* root = compositeRoot(); + if (root) + return root->setHwAccelerated(hwAccelerated); + return 0; +} + bool m_isDrawingPaused; private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread @@ -1176,6 +1187,13 @@ static void nativeMapLayerRect(JNIEnv *env, jobject obj, jint nativeView, GraphicsJNI::irect_to_jrect(nativeRect, env, rect); } +static jint nativeSetHwAccelerated(JNIEnv *env, jobject obj, jint nativeView, + jboolean hwAccelerated) +{ + WebView* webview = reinterpret_cast<WebView*>(nativeView); + return webview->setHwAccelerated(hwAccelerated); +} + /* * JNI registration */ @@ -1254,6 +1272,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeIsBaseFirst }, { "nativeMapLayerRect", "(IILandroid/graphics/Rect;)V", (void*) nativeMapLayerRect }, + { "nativeSetHwAccelerated", "(IZ)I", + (void*) nativeSetHwAccelerated }, }; int registerWebView(JNIEnv* env) |