summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/android/rendering
diff options
context:
space:
mode:
authorNicolas Roard <nicolasroard@google.com>2012-04-06 11:35:50 -0700
committerNicolas Roard <nicolasroard@google.com>2012-04-06 14:03:59 -0700
commit2e510fd5b5a30f1315c272d44ae3aa4cba355498 (patch)
treedb3af5f32855d329856f190c3509ae11ae519851 /Source/WebCore/platform/graphics/android/rendering
parentc88c88907b618e468ec3928b06a3a31d4f99b9c6 (diff)
downloadexternal_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.zip
external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.tar.gz
external_webkit-2e510fd5b5a30f1315c272d44ae3aa4cba355498.tar.bz2
Reorganize platform/graphics/android
Change-Id: Idc67155cfa99784dcd931e705336bfa063ecae46
Diffstat (limited to 'Source/WebCore/platform/graphics/android/rendering')
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp165
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h107
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h172
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp139
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GLExtras.h60
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp669
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GLUtils.h98
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GaneshContext.cpp184
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GaneshContext.h63
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp113
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h61
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp256
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/ImageTexture.h110
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/ImagesManager.cpp134
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/ImagesManager.h64
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.cpp133
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.h102
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp117
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h88
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h47
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp115
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h62
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp730
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h234
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Surface.cpp346
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Surface.h115
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp171
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h86
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp218
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h76
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp258
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h74
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TextureInfo.cpp65
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TextureInfo.h65
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TextureOwner.h47
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp182
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h70
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Tile.cpp528
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Tile.h191
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp376
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TileGrid.h87
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilePainter.h58
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp147
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TileTexture.h99
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp449
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilesManager.h209
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilesProfiler.cpp133
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TilesProfiler.h90
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp644
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/TransferQueue.h234
50 files changed, 9041 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp
new file mode 100644
index 0000000..833aea9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2011, 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 "BaseRenderer"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "BaseRenderer.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "GaneshRenderer.h"
+#include "GLUtils.h"
+#include "RasterRenderer.h"
+#include "SkBitmap.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPicture.h"
+#include "SkTypeface.h"
+#include "Tile.h"
+#include "TilesManager.h"
+
+#include <wtf/text/CString.h>
+
+#define UPDATE_COUNT_MASK 0xFF // displayed count wraps at 256
+#define UPDATE_COUNT_ALPHA_MASK 0x1F // alpha wraps at 32
+
+namespace WebCore {
+
+BaseRenderer::RendererType BaseRenderer::g_currentType = BaseRenderer::Raster;
+
+BaseRenderer* BaseRenderer::createRenderer()
+{
+ if (g_currentType == Raster)
+ return new RasterRenderer();
+ else if (g_currentType == Ganesh)
+ return new GaneshRenderer();
+ return NULL;
+}
+
+void BaseRenderer::swapRendererIfNeeded(BaseRenderer*& renderer)
+{
+ if (renderer->getType() == g_currentType)
+ return;
+
+ delete renderer;
+ renderer = createRenderer();
+}
+
+void BaseRenderer::drawTileInfo(SkCanvas* canvas,
+ const TileRenderInfo& renderInfo, int updateCount, double renderDuration)
+{
+ static SkTypeface* s_typeface = 0;
+ if (!s_typeface)
+ s_typeface = SkTypeface::CreateFromName("", SkTypeface::kBold);
+ SkPaint paint;
+ paint.setTextSize(17);
+ char str[256];
+ snprintf(str, 256, " (%d,%d) %.2fx %d %.1fms", renderInfo.x, renderInfo.y,
+ renderInfo.scale, updateCount, renderDuration);
+ paint.setARGB(128, 255, 255, 255);
+ canvas->drawRectCoords(0, 0, renderInfo.tileSize.fWidth, 17, paint);
+ paint.setARGB(255, 255, 0, 0);
+ paint.setTypeface(s_typeface);
+ canvas->drawText(str, strlen(str), 20, 15, paint);
+}
+
+void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo)
+{
+ const bool visualIndicator = TilesManager::instance()->getShowVisualIndicator();
+ const SkSize& tileSize = renderInfo.tileSize;
+
+ SkCanvas canvas;
+ setupCanvas(renderInfo, &canvas);
+
+ if (!canvas.getDevice()) {
+ // TODO: consider ALOGE
+ ALOGV("Error: No Device");
+ return;
+ }
+
+ double before;
+ if (visualIndicator) {
+ canvas.save();
+ before = currentTimeMS();
+ }
+
+ setupPartialInval(renderInfo, &canvas);
+ canvas.translate(-renderInfo.x * tileSize.width(), -renderInfo.y * tileSize.height());
+ canvas.scale(renderInfo.scale, renderInfo.scale);
+ renderInfo.tilePainter->paint(renderInfo.baseTile, &canvas);
+ if (renderInfo.baseTile && renderInfo.baseTile->backTexture())
+ checkForPureColor(renderInfo, &canvas);
+ else
+ renderInfo.isPureColor = false;
+
+ if (visualIndicator) {
+ double after = currentTimeMS();
+ canvas.restore();
+ unsigned int updateCount = renderInfo.tilePainter->getUpdateCount() & UPDATE_COUNT_MASK;
+ const int color = updateCount & UPDATE_COUNT_ALPHA_MASK;
+
+ // only color the invalidated area
+ SkPaint paint;
+ paint.setARGB(color, 0, 255, 0);
+ if (renderInfo.invalRect)
+ canvas.drawIRect(*renderInfo.invalRect, paint);
+ else {
+ SkIRect rect;
+ rect.set(0, 0, tileSize.width(), tileSize.height());
+ canvas.drawIRect(rect, paint);
+ }
+
+ if (renderInfo.invalRect) {
+ // if partial inval...
+ int x = renderInfo.invalRect->fLeft;
+ int y = renderInfo.invalRect->fTop;
+ int w = renderInfo.invalRect->width();
+ int h = renderInfo.invalRect->height();
+
+ paint.setARGB(128, 255, 255, 0);
+ canvas.drawLine(x, y, x + w, y + h, paint);
+ canvas.drawLine(x, y + h, x + w, y, paint);
+ }
+ drawTileInfo(&canvas, renderInfo, updateCount, after - before);
+
+ // paint the tile boundaries
+ paint.setARGB(64, 255, 0, 0);
+ paint.setStrokeWidth(3);
+ canvas.drawLine(0, 0, tileSize.width(), tileSize.height(), paint);
+ paint.setARGB(64, 0, 255, 0);
+ canvas.drawLine(0, tileSize.height(), tileSize.width(), 0, paint);
+ paint.setARGB(128, 0, 0, 255);
+ canvas.drawLine(tileSize.width(), 0, tileSize.width(), tileSize.height(), paint);
+ }
+ renderingComplete(renderInfo, &canvas);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h
new file mode 100644
index 0000000..f225871
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2011, 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 BaseRenderer_h
+#define BaseRenderer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Color.h"
+#include "SkRect.h"
+#include <wtf/text/StringHash.h>
+
+class SkCanvas;
+class SkDevice;
+
+namespace WebCore {
+
+class TextureInfo;
+class TilePainter;
+class Tile;
+
+struct TileRenderInfo {
+ // coordinates of the tile
+ int x;
+ int y;
+
+ // current scale factor
+ float scale;
+
+ // inval rectangle with coordinates in the tile's coordinate space
+ SkIRect* invalRect;
+
+ // the expected size of the tile
+ SkSize tileSize;
+
+ // the painter object in charge of drawing our content
+ TilePainter* tilePainter;
+
+ // the base tile calling us
+ Tile* baseTile;
+
+ // info about the texture that we are to render into
+ TextureInfo* textureInfo;
+
+ bool isPureColor;
+ Color pureColor;
+};
+
+/**
+ *
+ */
+class BaseRenderer {
+public:
+ enum RendererType { Raster, Ganesh };
+ BaseRenderer(RendererType type) : m_type(type) {}
+ virtual ~BaseRenderer() {}
+
+ void renderTiledContent(TileRenderInfo& renderInfo);
+
+ RendererType getType() { return m_type; }
+
+ static BaseRenderer* createRenderer();
+ static void swapRendererIfNeeded(BaseRenderer*& renderer);
+ static RendererType getCurrentRendererType() { return g_currentType; }
+ static void setCurrentRendererType(RendererType type) { g_currentType = type; }
+
+protected:
+
+ virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0;
+ virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) {}
+ virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0;
+ virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) = 0;
+
+ void drawTileInfo(SkCanvas* canvas, const TileRenderInfo& renderInfo,
+ int updateCount, double renderDuration);
+
+private:
+ RendererType m_type;
+ static RendererType g_currentType;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // BaseRenderer_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h b/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h
new file mode 100644
index 0000000..687808d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/DrawQuadData.h
@@ -0,0 +1,172 @@
+/*
+ * 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 DrawQuadData_h
+#define DrawQuadData_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Color.h"
+#include "SkRect.h"
+#include <GLES2/gl2.h>
+
+namespace WebCore {
+
+class TransformationMatrix;
+
+enum DrawQuadType {
+ BaseQuad,
+ LayerQuad,
+ Blit // 1:1 straight pixel blit
+};
+
+// Both PureColorQuadData and TextureQuadData share the data from DrawQuadData.
+class DrawQuadData {
+public:
+ DrawQuadData(DrawQuadType type = BaseQuad,
+ const TransformationMatrix* drawMatrix = 0,
+ const SkRect* geometry = 0,
+ float opacity = 1.0f,
+ bool forceBlending = true)
+ : m_type(type)
+ , m_drawMatrix(drawMatrix)
+ , m_geometry(geometry)
+ , m_opacity(opacity)
+ , m_forceBlending(forceBlending)
+ {
+ }
+
+ DrawQuadData(const DrawQuadData& data)
+ : m_type(data.m_type)
+ , m_drawMatrix(data.m_drawMatrix)
+ , m_geometry(data.m_geometry)
+ , m_opacity(data.m_opacity)
+ , m_forceBlending(data.m_forceBlending)
+ {
+ }
+
+ virtual ~DrawQuadData() {};
+
+ DrawQuadType type() const { return m_type; }
+ const TransformationMatrix* drawMatrix() const { return m_drawMatrix; }
+ const SkRect* geometry() const { return m_geometry; }
+ float opacity() const { return m_opacity; }
+ bool forceBlending() const { return m_forceBlending; }
+
+ void updateDrawMatrix(TransformationMatrix* matrix) { m_drawMatrix = matrix; }
+ void updateGeometry(SkRect* rect) { m_geometry = rect; }
+ void updateOpacity(float opacity) { m_opacity = opacity; }
+
+ virtual bool pureColor() const { return false; }
+
+ virtual Color quadColor() const { return Color(); }
+
+ virtual int textureId() const { return 0; }
+ virtual GLint textureFilter() const { return 0; }
+ virtual GLenum textureTarget() const { return 0; }
+
+private:
+ DrawQuadType m_type;
+ const TransformationMatrix* m_drawMatrix;
+ const SkRect* m_geometry;
+ float m_opacity;
+ bool m_forceBlending;
+};
+
+class PureColorQuadData : public DrawQuadData {
+public:
+ PureColorQuadData(Color color,
+ DrawQuadType type = BaseQuad,
+ const TransformationMatrix* drawMatrix = 0,
+ const SkRect* geometry = 0,
+ float opacity = 1.0f,
+ bool forceBlending = true)
+ : DrawQuadData(type, drawMatrix, geometry, opacity, forceBlending)
+ {
+ m_quadColor = color;
+ }
+
+ PureColorQuadData(const DrawQuadData& data, Color color)
+ : DrawQuadData(data)
+ {
+ m_quadColor = color;
+ }
+
+ virtual ~PureColorQuadData() {};
+ virtual bool pureColor() const { return true; }
+ virtual Color quadColor() const { return m_quadColor; }
+ void updateColor(const Color& color) { m_quadColor = color; }
+
+private:
+ Color m_quadColor;
+};
+
+class TextureQuadData : public DrawQuadData {
+public:
+ TextureQuadData(int textureId,
+ GLenum textureTarget = GL_TEXTURE_2D,
+ GLint textureFilter = GL_LINEAR,
+ DrawQuadType type = BaseQuad,
+ const TransformationMatrix* drawMatrix = 0,
+ const SkRect* geometry = 0,
+ float opacity = 1.0f,
+ bool forceBlending = true)
+ : DrawQuadData(type, drawMatrix, geometry, opacity, forceBlending)
+ {
+ m_textureId = textureId;
+ m_textureTarget = textureTarget;
+ m_textureFilter = textureFilter;
+ }
+
+ TextureQuadData(const DrawQuadData& data,
+ int textureId,
+ GLenum textureTarget = GL_TEXTURE_2D,
+ GLint textureFilter = GL_LINEAR)
+ : DrawQuadData(data)
+ {
+ m_textureId = textureId;
+ m_textureTarget = textureTarget;
+ m_textureFilter = textureFilter;
+ }
+
+ virtual ~TextureQuadData() {};
+ virtual bool pureColor() const { return false; }
+
+ virtual int textureId() const { return m_textureId; }
+ virtual GLint textureFilter() const { return m_textureFilter; }
+ virtual GLenum textureTarget() const { return m_textureTarget; }
+
+ void updateTextureId(int newId) { m_textureId = newId; }
+
+private:
+ int m_textureId;
+ GLint m_textureFilter;
+ GLenum m_textureTarget;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // DrawQuadData_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp b/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp
new file mode 100644
index 0000000..6498ecf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011, 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 "GLExtras"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+
+#include "AndroidLog.h"
+#include "DrawExtra.h"
+#include "DrawQuadData.h"
+#include "GLExtras.h"
+#include "IntRect.h"
+#include "SkPath.h"
+#include "TilesManager.h"
+#include "android_graphics.h"
+
+// Touch ring border width. This is doubled if the ring is not pressed
+#define RING_BORDER_WIDTH 1
+
+GLExtras::GLExtras()
+ : m_drawExtra(0)
+ , m_viewport()
+{
+}
+
+GLExtras::~GLExtras()
+{
+}
+
+void GLExtras::drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat)
+{
+ if (srcRect.fRight <= srcRect.fLeft || srcRect.fBottom <= srcRect.fTop) {
+ // Invalid rect, reject it
+ return;
+ }
+ ALOGV("drawQuad [%fx%f, %f, %f]", srcRect.fLeft, srcRect.fTop,
+ srcRect.width(), srcRect.height());
+ // Pull the alpha out of the color so that the shader applies it correctly.
+ // Otherwise we either don't have blending enabled, or the alpha will get
+ // double applied
+ Color colorWithoutAlpha(0xFF000000 | color.rgb());
+ float alpha = color.alpha() / (float) 255;
+
+ PureColorQuadData data(colorWithoutAlpha, drawMat ? LayerQuad : BaseQuad,
+ drawMat, &srcRect, alpha, false);
+ TilesManager::instance()->shader()->drawQuad(&data);
+}
+
+void GLExtras::drawRegion(const SkRegion& region, bool fill, bool drawBorder,
+ const TransformationMatrix* drawMat, Color color)
+{
+ if (region.isEmpty())
+ return;
+ if (fill) {
+ SkRegion::Iterator rgnIter(region);
+ while (!rgnIter.done()) {
+ const SkIRect& ir = rgnIter.rect();
+ SkRect r;
+ r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
+ drawRing(r, color, drawMat);
+ rgnIter.next();
+ }
+ }
+ if (fill && !drawBorder)
+ return;
+ SkPath path;
+ if (!region.getBoundaryPath(&path))
+ return;
+ SkPath::Iter iter(path, true);
+ SkPath::Verb verb;
+ SkPoint pts[4];
+ SkRegion clip;
+ SkIRect startRect;
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ if (verb == SkPath::kLine_Verb) {
+ SkRect r;
+ r.set(pts, 2);
+ SkIRect line;
+ int borderWidth = RING_BORDER_WIDTH;
+ if (!fill)
+ borderWidth *= 2;
+ line.fLeft = r.fLeft - borderWidth;
+ line.fRight = r.fRight + borderWidth;
+ line.fTop = r.fTop - borderWidth;
+ line.fBottom = r.fBottom + borderWidth;
+ if (clip.intersects(line)) {
+ clip.op(line, SkRegion::kReverseDifference_Op);
+ if (clip.isEmpty())
+ continue; // Nothing to draw, continue
+ line = clip.getBounds();
+ if (SkIRect::Intersects(startRect, line)) {
+ clip.op(startRect, SkRegion::kDifference_Op);
+ if (clip.isEmpty())
+ continue; // Nothing to draw, continue
+ line = clip.getBounds();
+ }
+ } else {
+ clip.setRect(line);
+ }
+ r.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
+ drawRing(r, color, drawMat);
+ if (startRect.isEmpty()) {
+ startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
+ }
+ }
+ if (verb == SkPath::kMove_Verb) {
+ startRect.setEmpty();
+ }
+ }
+}
+
+void GLExtras::drawGL(const LayerAndroid* layer)
+{
+ if (m_drawExtra)
+ m_drawExtra->drawGL(this, layer);
+}
diff --git a/Source/WebCore/platform/graphics/android/rendering/GLExtras.h b/Source/WebCore/platform/graphics/android/rendering/GLExtras.h
new file mode 100644
index 0000000..59a7c3c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GLExtras.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011, 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 GLExtras_h
+#define GLExtras_h
+
+#include "Color.h"
+#include "DrawExtra.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+namespace WebCore {
+
+class LayerAndroid;
+class TransformationMatrix;
+
+class GLExtras {
+public:
+ GLExtras();
+ virtual ~GLExtras();
+
+ void drawGL(const LayerAndroid* layer);
+ void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; }
+ void setViewport(const SkRect & viewport) { m_viewport = viewport; }
+
+ void drawRegion(const SkRegion& region, bool fill, bool drawBorder,
+ const TransformationMatrix* drawMat, Color color = COLOR_HOLO_LIGHT);
+
+private:
+ void drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat);
+
+ android::DrawExtra* m_drawExtra;
+ SkRect m_viewport;
+};
+
+} // namespace WebCore
+
+#endif // GLExtras_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp
new file mode 100644
index 0000000..26bd55d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp
@@ -0,0 +1,669 @@
+/*
+ * Copyright 2010, 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 "GLUtils"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "GLUtils.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "BaseRenderer.h"
+#include "TextureInfo.h"
+#include "Tile.h"
+#include "TilesManager.h"
+#include "TransferQueue.h"
+
+#include <android/native_window.h>
+#include <gui/SurfaceTexture.h>
+#include <wtf/CurrentTime.h>
+
+// We will limit GL error logging for LOG_VOLUME_PER_CYCLE times every
+// LOG_VOLUME_PER_CYCLE seconds.
+#define LOG_CYCLE 30.0
+#define LOG_VOLUME_PER_CYCLE 20
+
+struct ANativeWindowBuffer;
+
+namespace WebCore {
+
+using namespace android;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Matrix utilities
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void GLUtils::toGLMatrix(GLfloat* flattened, const TransformationMatrix& m)
+{
+ flattened[0] = m.m11(); // scaleX
+ flattened[1] = m.m12(); // skewY
+ flattened[2] = m.m13();
+ flattened[3] = m.m14(); // persp0
+ flattened[4] = m.m21(); // skewX
+ flattened[5] = m.m22(); // scaleY
+ flattened[6] = m.m23();
+ flattened[7] = m.m24(); // persp1
+ flattened[8] = m.m31();
+ flattened[9] = m.m32();
+ flattened[10] = m.m33();
+ flattened[11] = m.m34();
+ flattened[12] = m.m41(); // transX
+ flattened[13] = m.m42(); // transY
+ flattened[14] = m.m43();
+ flattened[15] = m.m44(); // persp2
+}
+
+void GLUtils::toSkMatrix(SkMatrix& matrix, const TransformationMatrix& m)
+{
+ matrix[0] = m.m11(); // scaleX
+ matrix[1] = m.m21(); // skewX
+ matrix[2] = m.m41(); // transX
+ matrix[3] = m.m12(); // skewY
+ matrix[4] = m.m22(); // scaleY
+ matrix[5] = m.m42(); // transY
+ matrix[6] = m.m14(); // persp0
+ matrix[7] = m.m24(); // persp1
+ matrix[8] = m.m44(); // persp2
+}
+
+void GLUtils::setOrthographicMatrix(TransformationMatrix& ortho, float left, float top,
+ float right, float bottom, float nearZ, float farZ)
+{
+ float deltaX = right - left;
+ float deltaY = top - bottom;
+ float deltaZ = farZ - nearZ;
+ if (!deltaX || !deltaY || !deltaZ)
+ return;
+
+ ortho.setM11(2.0f / deltaX);
+ ortho.setM41(-(right + left) / deltaX);
+ ortho.setM22(2.0f / deltaY);
+ ortho.setM42(-(top + bottom) / deltaY);
+ ortho.setM33(-2.0f / deltaZ);
+ ortho.setM43(-(nearZ + farZ) / deltaZ);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// GL & EGL error checks
+/////////////////////////////////////////////////////////////////////////////////////////
+
+double GLUtils::m_previousLogTime = 0;
+int GLUtils::m_currentLogCounter = 0;
+
+bool GLUtils::allowGLLog()
+{
+ if (m_currentLogCounter < LOG_VOLUME_PER_CYCLE) {
+ m_currentLogCounter++;
+ return true;
+ }
+
+ // when we are in Log cycle and over the log limit, just return false
+ double currentTime = WTF::currentTime();
+ double delta = currentTime - m_previousLogTime;
+ bool inLogCycle = (delta <= LOG_CYCLE) && (delta > 0);
+ if (inLogCycle)
+ return false;
+
+ // When we are out of Log Cycle and over the log limit, we need to reset
+ // the counter and timer.
+ m_previousLogTime = currentTime;
+ m_currentLogCounter = 0;
+ return false;
+}
+
+static void crashIfOOM(GLint errorCode)
+{
+ const GLint OOM_ERROR_CODE = 0x505;
+ if (errorCode == OOM_ERROR_CODE) {
+ ALOGE("ERROR: Fatal OOM detected.");
+ CRASH();
+ }
+}
+
+void GLUtils::checkEglError(const char* op, EGLBoolean returnVal)
+{
+ if (returnVal != EGL_TRUE) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("EGL ERROR - %s() returned %d\n", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error = eglGetError()) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("after %s() eglError (0x%x)\n", op, error);
+ crashIfOOM(error);
+ }
+}
+
+bool GLUtils::checkGlError(const char* op)
+{
+ bool ret = false;
+ for (GLint error = glGetError(); error; error = glGetError()) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("GL ERROR - after %s() glError (0x%x)\n", op, error);
+ crashIfOOM(error);
+ ret = true;
+ }
+ return ret;
+}
+
+bool GLUtils::checkGlErrorOn(void* p, const char* op)
+{
+ bool ret = false;
+ for (GLint error = glGetError(); error; error = glGetError()) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("GL ERROR on %x - after %s() glError (0x%x)\n", p, op, error);
+ crashIfOOM(error);
+ ret = true;
+ }
+ return ret;
+}
+
+void GLUtils::checkSurfaceTextureError(const char* functionName, int status)
+{
+ if (status != NO_ERROR) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("ERROR at calling %s status is (%d)", functionName, status);
+ }
+}
+/////////////////////////////////////////////////////////////////////////////////////////
+// GL & EGL extension checks
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool GLUtils::isEGLImageSupported()
+{
+ const char* eglExtensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
+ const char* glExtensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+
+ return eglExtensions && glExtensions
+ && strstr(eglExtensions, "EGL_KHR_image_base")
+ && strstr(eglExtensions, "EGL_KHR_gl_texture_2D_image")
+ && strstr(glExtensions, "GL_OES_EGL_image");
+}
+
+bool GLUtils::isEGLFenceSyncSupported()
+{
+ const char* eglExtensions = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS);
+ return eglExtensions && strstr(eglExtensions, "EGL_KHR_fence_sync");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Textures utilities
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static GLenum getInternalFormat(SkBitmap::Config config)
+{
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ return GL_ALPHA;
+ case SkBitmap::kARGB_4444_Config:
+ return GL_RGBA;
+ case SkBitmap::kARGB_8888_Config:
+ return GL_RGBA;
+ case SkBitmap::kRGB_565_Config:
+ return GL_RGB;
+ default:
+ return -1;
+ }
+}
+
+static GLenum getType(SkBitmap::Config config)
+{
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ return GL_UNSIGNED_BYTE;
+ case SkBitmap::kARGB_4444_Config:
+ return GL_UNSIGNED_SHORT_4_4_4_4;
+ case SkBitmap::kARGB_8888_Config:
+ return GL_UNSIGNED_BYTE;
+ case SkBitmap::kIndex8_Config:
+ return -1; // No type for compressed data.
+ case SkBitmap::kRGB_565_Config:
+ return GL_UNSIGNED_SHORT_5_6_5;
+ default:
+ return -1;
+ }
+}
+
+static EGLConfig defaultPbufferConfig(EGLDisplay display)
+{
+ EGLConfig config;
+ EGLint numConfigs;
+
+ static const EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+
+ eglChooseConfig(display, configAttribs, &config, 1, &numConfigs);
+ GLUtils::checkEglError("eglPbufferConfig");
+ if (numConfigs != 1)
+ ALOGI("eglPbufferConfig failed (%d)\n", numConfigs);
+
+ return config;
+}
+
+static EGLSurface createPbufferSurface(EGLDisplay display, const EGLConfig& config,
+ EGLint* errorCode)
+{
+ const EGLint attribList[] = {
+ EGL_WIDTH, 1,
+ EGL_HEIGHT, 1,
+ EGL_NONE
+ };
+ EGLSurface surface = eglCreatePbufferSurface(display, config, attribList);
+
+ if (errorCode)
+ *errorCode = eglGetError();
+ else
+ GLUtils::checkEglError("eglCreatePbufferSurface");
+
+ if (surface == EGL_NO_SURFACE)
+ return EGL_NO_SURFACE;
+
+ return surface;
+}
+
+EGLContext GLUtils::createBackgroundContext(EGLContext sharedContext)
+{
+ checkEglError("<init>");
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (display == EGL_NO_DISPLAY) {
+ ALOGE("eglGetDisplay returned EGL_NO_DISPLAY");
+ return EGL_NO_CONTEXT;
+ }
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLBoolean returnValue = eglInitialize(display, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ if (returnValue != EGL_TRUE) {
+ ALOGE("eglInitialize failed\n");
+ return EGL_NO_CONTEXT;
+ }
+
+ EGLConfig config = defaultPbufferConfig(display);
+ EGLSurface surface = createPbufferSurface(display, config, 0);
+
+ EGLint surfaceConfigId;
+ EGLBoolean success = eglGetConfigAttrib(display, config, EGL_CONFIG_ID, &surfaceConfigId);
+
+ EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLContext context = eglCreateContext(display, config, sharedContext, contextAttribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ ALOGE("eglCreateContext failed\n");
+ return EGL_NO_CONTEXT;
+ }
+
+ returnValue = eglMakeCurrent(display, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ ALOGE("eglMakeCurrent failed\n");
+ return EGL_NO_CONTEXT;
+ }
+
+ return context;
+}
+
+void GLUtils::deleteTexture(GLuint* texture)
+{
+ glDeleteTextures(1, texture);
+ GLUtils::checkGlError("glDeleteTexture");
+ *texture = 0;
+}
+
+GLuint GLUtils::createSampleColorTexture(int r, int g, int b)
+{
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ GLubyte pixels[4 *3] = {
+ r, g, b,
+ r, g, b,
+ r, g, b,
+ r, g, b
+ };
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
+ GLUtils::checkGlError("glTexImage2D");
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ return texture;
+}
+
+GLuint GLUtils::createSampleTexture()
+{
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ GLubyte pixels[4 *3] = {
+ 255, 0, 0,
+ 0, 255, 0,
+ 0, 0, 255,
+ 255, 255, 0
+ };
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
+ GLUtils::checkGlError("glTexImage2D");
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ return texture;
+}
+
+GLuint GLUtils::createTileGLTexture(int width, int height)
+{
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ GLubyte* pixels = 0;
+#ifdef DEBUG
+ int length = width * height * 4;
+ pixels = new GLubyte[length];
+ for (int i = 0; i < length; i++)
+ pixels[i] = i % 256;
+#endif
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ GLUtils::checkGlError("glTexImage2D");
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+#ifdef DEBUG
+ delete pixels;
+#endif
+ return texture;
+}
+
+bool GLUtils::isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor)
+{
+ // If the bitmap is the pure color, skip the transfer step, and update the Tile Info.
+ // This check is taking < 1ms if we do full bitmap check per tile.
+ // TODO: use the SkPicture to determine whether or not a tile is single color.
+ pureColor = Color(Color::transparent);
+ bitmap.lockPixels();
+ bool sameColor = true;
+ int bitmapWidth = bitmap.width();
+
+ // Create a row of pure color using the first pixel.
+ // TODO: improve the perf here, by either picking a random pixel, or
+ // creating an array of rows with pre-defined commonly used color, add
+ // smart LUT to speed things up if possible.
+ int* firstPixelPtr = static_cast<int*> (bitmap.getPixels());
+ int* pixelsRow = new int[bitmapWidth];
+ for (int i = 0; i < bitmapWidth; i++)
+ pixelsRow[i] = (*firstPixelPtr);
+
+ // Then compare the pure color row with each row of the bitmap.
+ for (int j = 0; j < bitmap.height(); j++) {
+ if (memcmp(pixelsRow, &firstPixelPtr[bitmapWidth * j], 4 * bitmapWidth)) {
+ sameColor = false;
+ break;
+ }
+ }
+ delete pixelsRow;
+ pixelsRow = 0;
+
+ if (sameColor) {
+ char* rgbaPtr = static_cast<char*>(bitmap.getPixels());
+ pureColor = Color(rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]);
+ ALOGV("sameColor tile found , %x at (%d, %d, %d, %d)",
+ *firstPixelPtr, rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]);
+ }
+ bitmap.unlockPixels();
+
+ return sameColor;
+}
+
+// Return true when the tile is pure color.
+bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap)
+{
+ bool skipTransfer = false;
+ Tile* tilePtr = renderInfo->baseTile;
+
+ // TODO: use pure color for partial invals as well
+ if (renderInfo->invalRect)
+ return false;
+
+ if (tilePtr) {
+ TileTexture* tileTexture = tilePtr->backTexture();
+ // Check the bitmap, and make everything ready here.
+ if (tileTexture && renderInfo->isPureColor) {
+ // update basetile's info
+ // Note that we are skipping the whole TransferQueue.
+ renderInfo->textureInfo->m_width = bitmap.width();
+ renderInfo->textureInfo->m_height = bitmap.height();
+ renderInfo->textureInfo->m_internalFormat = GL_RGBA;
+
+ TilesManager::instance()->transferQueue()->addItemInPureColorQueue(renderInfo);
+
+ skipTransfer = true;
+ }
+ }
+ return skipTransfer;
+}
+
+void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap)
+{
+ if (!renderInfo)
+ return;
+ const SkSize& requiredSize = renderInfo->tileSize;
+ TextureInfo* textureInfo = renderInfo->textureInfo;
+
+ if (skipTransferForPureColor(renderInfo, bitmap))
+ return;
+
+ if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height))
+ 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::updateQueueWithBitmap(renderInfo, bitmap);
+
+ textureInfo->m_width = bitmap.width();
+ textureInfo->m_height = bitmap.height();
+ textureInfo->m_internalFormat = GL_RGBA;
+ }
+}
+
+void GLUtils::updateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap)
+{
+ if (!renderInfo
+ || !renderInfo->textureInfo
+ || !renderInfo->baseTile)
+ return;
+
+ 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()) {
+ ALOGW("bitmap (%dx%d) too large for buffer (%dx%d)!",
+ bitmap.width(), bitmap.height(),
+ buffer.width, buffer.height);
+ ANativeWindow_unlockAndPost(anw);
+ 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);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ SkBitmap::Config config = bitmap.getConfig();
+ int internalformat = getInternalFormat(config);
+ int type = getType(config);
+ bitmap.lockPixels();
+ glTexImage2D(GL_TEXTURE_2D, 0, internalformat, bitmap.width(), bitmap.height(),
+ 0, internalformat, type, bitmap.getPixels());
+ bitmap.unlockPixels();
+ if (GLUtils::checkGlError("glTexImage2D")) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("GL ERROR: glTexImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
+ " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
+ bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels());
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+
+ // The following is a workaround -- remove when EGLImage texture upload is fixed.
+ GLuint fboID;
+ glGenFramebuffers(1, &fboID);
+ glBindFramebuffer(GL_FRAMEBUFFER, fboID);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ glCheckFramebufferStatus(GL_FRAMEBUFFER); // should return GL_FRAMEBUFFER_COMPLETE
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO
+ glDeleteFramebuffers(1, &fboID);
+}
+
+void GLUtils::updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap,
+ const IntRect& inval, GLint filter)
+{
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ SkBitmap::Config config = bitmap.getConfig();
+ int internalformat = getInternalFormat(config);
+ int type = getType(config);
+ bitmap.lockPixels();
+ if (inval.isEmpty()) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
+ internalformat, type, bitmap.getPixels());
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), inval.width(), inval.height(),
+ internalformat, type, bitmap.getPixels());
+ }
+ bitmap.unlockPixels();
+ if (GLUtils::checkGlError("glTexSubImage2D")) {
+#ifndef DEBUG
+ if (allowGLLog())
+#endif
+ ALOGE("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
+ " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
+ bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels());
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+}
+
+void GLUtils::createEGLImageFromTexture(GLuint texture, EGLImageKHR* image)
+{
+ EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(texture);
+ static const EGLint attr[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ *image = eglCreateImageKHR(eglGetCurrentDisplay(), eglGetCurrentContext(),
+ EGL_GL_TEXTURE_2D_KHR, buffer, attr);
+ GLUtils::checkEglError("eglCreateImage", (*image != EGL_NO_IMAGE_KHR));
+}
+
+void GLUtils::createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter)
+{
+ glBindTexture(GL_TEXTURE_2D, texture);
+ GLUtils::checkGlError("glBindTexture");
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+}
+
+void GLUtils::convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix)
+{
+ transformMatrix.setMatrix(
+ matrix[0], matrix[1], matrix[2], matrix[3],
+ matrix[4], matrix[5], matrix[6], matrix[7],
+ matrix[8], matrix[9], matrix[10], matrix[11],
+ matrix[12], matrix[13], matrix[14], matrix[15]);
+}
+
+void GLUtils::clearBackgroundIfOpaque(const Color* backgroundColor)
+{
+ if (!backgroundColor->hasAlpha()) {
+ if (TilesManager::instance()->invertedScreen()) {
+ float color = 1.0 - ((((float) backgroundColor->red() / 255.0) +
+ ((float) backgroundColor->green() / 255.0) +
+ ((float) backgroundColor->blue() / 255.0)) / 3.0);
+ glClearColor(color, color, color, 1);
+ } else {
+ glClearColor((float)backgroundColor->red() / 255.0,
+ (float)backgroundColor->green() / 255.0,
+ (float)backgroundColor->blue() / 255.0, 1);
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h
new file mode 100644
index 0000000..d4a2e84
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2010, 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 GLUtils_h
+#define GLUtils_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Color.h"
+#include "SkBitmap.h"
+#include "SkMatrix.h"
+#include "TransformationMatrix.h"
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace android {
+
+class SurfaceTexture;
+
+} // namespace android
+
+namespace WebCore {
+
+class TileRenderInfo;
+
+class GLUtils {
+
+public:
+ // Matrix utilities
+ static void toGLMatrix(GLfloat* flattened, const TransformationMatrix& matrix);
+ static void toSkMatrix(SkMatrix& skmatrix, const TransformationMatrix& matrix);
+ static void setOrthographicMatrix(TransformationMatrix& ortho, float left, float top,
+ float right, float bottom, float nearZ, float farZ);
+
+ // GL & EGL error checks
+ static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
+ static bool checkGlErrorOn(void* p, const char* op);
+ static bool checkGlError(const char* op);
+ static void checkSurfaceTextureError(const char* functionName, int status);
+
+ // GL & EGL extension checks
+ static bool isEGLImageSupported();
+ static bool isEGLFenceSyncSupported();
+
+ // Texture utilities
+ static EGLContext createBackgroundContext(EGLContext sharedContext);
+ static void deleteTexture(GLuint* texture);
+ static GLuint createSampleColorTexture(int r, int g, int b);
+ static GLuint createSampleTexture();
+ static GLuint createTileGLTexture(int width, int height);
+
+ static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR);
+ static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR);
+ static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image);
+ static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR);
+
+ static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, 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);
+ static bool skipTransferForPureColor(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap);
+ static void clearBackgroundIfOpaque(const Color* backgroundColor);
+ static bool allowGLLog();
+ static double m_previousLogTime;
+ static int m_currentLogCounter;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // GLUtils_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshContext.cpp b/Source/WebCore/platform/graphics/android/rendering/GaneshContext.cpp
new file mode 100644
index 0000000..bf43652
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GaneshContext.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2011, 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 "GaneshContext"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "GaneshContext.h"
+
+#include "AndroidLog.h"
+#include "GLUtils.h"
+#include "TextureInfo.h"
+#include "TilesManager.h"
+#include "TransferQueue.h"
+
+#include "android/native_window.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+namespace WebCore {
+
+GaneshContext::GaneshContext()
+ : m_grContext(0)
+ , m_tileDeviceSurface(0)
+ , m_surfaceConfig(0)
+ , m_surfaceContext(EGL_NO_CONTEXT)
+{
+}
+
+GaneshContext* GaneshContext::gInstance = 0;
+
+GaneshContext* GaneshContext::instance()
+{
+ if (!gInstance)
+ gInstance = new GaneshContext();
+ return gInstance;
+}
+
+GrContext* GaneshContext::getGrContext()
+{
+ if (!m_grContext) {
+ m_grContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
+ }
+ return m_grContext;
+}
+
+void GaneshContext::flush()
+{
+ if (m_grContext)
+ m_grContext->flush();
+}
+
+SkDevice* GaneshContext::getDeviceForTile(const TileRenderInfo& renderInfo)
+{
+ // Ganesh should be the only code in the rendering thread that is using GL
+ // and setting the EGLContext. If this is not the case then we need to
+ // reset the Ganesh context to prevent rendering issues.
+ bool contextNeedsReset = false;
+ if (eglGetCurrentContext() != m_surfaceContext) {
+ ALOGV("Warning: EGLContext has Changed! %p, %p",
+ m_surfaceContext, eglGetCurrentContext());
+ contextNeedsReset = true;
+ }
+
+ EGLDisplay display;
+
+ if (!m_surfaceContext) {
+
+ if(eglGetCurrentContext() != EGL_NO_CONTEXT) {
+ ALOGV("ERROR: should not have a context yet");
+ }
+
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ GLUtils::checkEglError("eglGetDisplay");
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLBoolean returnValue = eglInitialize(display, &majorVersion, &minorVersion);
+ GLUtils::checkEglError("eglInitialize", returnValue);
+
+ EGLint numConfigs;
+ static const EGLint configAttribs[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_STENCIL_SIZE, 8,
+ EGL_NONE
+ };
+
+ eglChooseConfig(display, configAttribs, &m_surfaceConfig, 1, &numConfigs);
+ GLUtils::checkEglError("eglChooseConfig");
+
+ static const EGLint contextAttribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ m_surfaceContext = eglCreateContext(display, m_surfaceConfig, NULL, contextAttribs);
+ GLUtils::checkEglError("eglCreateContext");
+ } else {
+ display = eglGetCurrentDisplay();
+ GLUtils::checkEglError("eglGetCurrentDisplay");
+ }
+
+ TransferQueue* tileQueue = TilesManager::instance()->transferQueue();
+ if (tileQueue->m_eglSurface == EGL_NO_SURFACE) {
+
+ const float tileWidth = renderInfo.tileSize.width();
+ const float tileHeight = renderInfo.tileSize.height();
+
+ ANativeWindow* anw = tileQueue->m_ANW.get();
+
+ int result = ANativeWindow_setBuffersGeometry(anw, (int)tileWidth,
+ (int)tileHeight, WINDOW_FORMAT_RGBA_8888);
+
+ renderInfo.textureInfo->m_width = tileWidth;
+ renderInfo.textureInfo->m_height = tileHeight;
+ tileQueue->m_eglSurface = eglCreateWindowSurface(display, m_surfaceConfig, anw, NULL);
+
+ GLUtils::checkEglError("eglCreateWindowSurface");
+ ALOGV("eglCreateWindowSurface");
+ }
+
+ EGLBoolean returnValue = eglMakeCurrent(display, tileQueue->m_eglSurface, tileQueue->m_eglSurface, m_surfaceContext);
+ GLUtils::checkEglError("eglMakeCurrent", returnValue);
+ ALOGV("eglMakeCurrent");
+
+ if (!m_tileDeviceSurface) {
+
+ GrPlatformRenderTargetDesc renderTargetDesc;
+ renderTargetDesc.fWidth = TilesManager::tileWidth();
+ renderTargetDesc.fHeight = TilesManager::tileHeight();
+ renderTargetDesc.fConfig = kRGBA_8888_PM_GrPixelConfig;
+ renderTargetDesc.fSampleCnt = 0;
+ renderTargetDesc.fStencilBits = 8;
+ renderTargetDesc.fRenderTargetHandle = 0;
+
+ GrContext* grContext = getGrContext();
+ GrRenderTarget* renderTarget = grContext->createPlatformRenderTarget(renderTargetDesc);
+
+ m_tileDeviceSurface = new SkGpuDevice(grContext, renderTarget);
+ renderTarget->unref();
+ ALOGV("generated device %p", m_tileDeviceSurface);
+ }
+
+ GLUtils::checkGlError("getDeviceForTile");
+
+ // We must reset the Ganesh context only after we are sure we have
+ // re-established our EGLContext as the current context.
+ if (m_tileDeviceSurface && contextNeedsReset)
+ getGrContext()->resetContext();
+
+ return m_tileDeviceSurface;
+}
+
+
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshContext.h b/Source/WebCore/platform/graphics/android/rendering/GaneshContext.h
new file mode 100644
index 0000000..57e8e19
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GaneshContext.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011, 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 GaneshContext_h
+#define GaneshContext_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "BaseRenderer.h"
+#include "GrContext.h"
+#include "SkGpuDevice.h"
+#include <EGL/egl.h>
+
+namespace WebCore {
+
+class GaneshContext {
+public:
+ static GaneshContext* instance();
+
+ SkDevice* getDeviceForTile(const TileRenderInfo& renderInfo);
+
+ void flush();
+
+private:
+
+ GaneshContext();
+
+ GrContext* getGrContext();
+ GrContext* m_grContext;
+
+ SkGpuDevice* m_tileDeviceSurface;
+ EGLConfig m_surfaceConfig;
+ EGLContext m_surfaceContext;
+
+ static GaneshContext* gInstance;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // GaneshContext_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp
new file mode 100644
index 0000000..208adb6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011, 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 "GaneshRenderer"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "GaneshRenderer.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "GaneshContext.h"
+#include "SkCanvas.h"
+#include "SkGpuDevice.h"
+#include "TilesManager.h"
+#include "TransferQueue.h"
+
+namespace WebCore {
+
+GaneshRenderer::GaneshRenderer() : BaseRenderer(BaseRenderer::Ganesh)
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("GaneshRenderer");
+#endif
+}
+
+GaneshRenderer::~GaneshRenderer()
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("GaneshRenderer");
+#endif
+}
+
+void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas)
+{
+ GaneshContext* ganesh = GaneshContext::instance();
+
+ TransferQueue* tileQueue = TilesManager::instance()->transferQueue();
+
+ tileQueue->lockQueue();
+
+ bool ready = tileQueue->readyForUpdate();
+ if (!ready) {
+ ALOGV("!ready");
+ tileQueue->unlockQueue();
+ return;
+ }
+
+ SkDevice* device = NULL;
+ if (renderInfo.tileSize.width() == TilesManager::tileWidth()
+ && renderInfo.tileSize.height() == TilesManager::tileHeight()) {
+ device = ganesh->getDeviceForTile(renderInfo);
+ } else {
+ // TODO support arbitrary sizes for layers
+ ALOGV("ERROR: expected (%d,%d) actual (%d,%d)",
+ TilesManager::tileWidth(), TilesManager::tileHeight(),
+ renderInfo.tileSize.width(), renderInfo.tileSize.height());
+ }
+
+ // set the GPU device to the canvas
+ canvas->setDevice(device);
+}
+
+void GaneshRenderer::setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas)
+{
+ // set the clip to our invalRect
+ SkRect clipRect = SkRect::MakeLTRB(renderInfo.invalRect->fLeft,
+ renderInfo.invalRect->fTop,
+ renderInfo.invalRect->fRight,
+ renderInfo.invalRect->fBottom);
+ canvas->clipRect(clipRect);
+}
+
+void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas)
+{
+ ALOGV("rendered to tile (%d,%d)", renderInfo.x, renderInfo.y);
+
+ GaneshContext::instance()->flush();
+
+ // In SurfaceTextureMode we must call swapBuffers to unlock and post the
+ // tile's ANativeWindow (i.e. SurfaceTexture) buffer
+ TransferQueue* tileQueue = TilesManager::instance()->transferQueue();
+ eglSwapBuffers(eglGetCurrentDisplay(), tileQueue->m_eglSurface);
+ tileQueue->addItemInTransferQueue(&renderInfo, GpuUpload, 0);
+ tileQueue->unlockQueue();
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h
new file mode 100644
index 0000000..d7eda24
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2011, 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 GaneshRenderer_h
+#define GaneshRenderer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "BaseRenderer.h"
+#include "SkRect.h"
+
+class SkCanvas;
+class SkDevice;
+
+namespace WebCore {
+
+/**
+ *
+ */
+class GaneshRenderer : public BaseRenderer {
+public:
+ GaneshRenderer();
+ ~GaneshRenderer();
+
+protected:
+
+ virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas);
+ virtual void setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas);
+ virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas);
+ virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) {
+ renderInfo.isPureColor = false;
+ }
+
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // GaneshRenderer_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp
new file mode 100644
index 0000000..b2ead6a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/ImageTexture.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011, 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 "ImageTexture"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "ImageTexture.h"
+
+#include "AndroidLog.h"
+#include "ClassTracker.h"
+#include "ImagesManager.h"
+#include "LayerAndroid.h"
+#include "SkDevice.h"
+#include "SkPicture.h"
+#include "TileGrid.h"
+#include "TilesManager.h"
+
+namespace WebCore {
+
+// CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp
+static void makeCrcTable(unsigned crcTable[256])
+{
+ for (unsigned i = 0; i < 256; i++) {
+ unsigned c = i;
+ for (int k = 0; k < 8; k++) {
+ if (c & 1)
+ c = -306674912 ^ ((c >> 1) & 0x7fffffff);
+ else
+ c = c >> 1;
+ }
+ crcTable[i] = c;
+ }
+}
+
+unsigned computeCrc(uint8_t* buffer, size_t size)
+{
+ static unsigned crcTable[256];
+ static bool crcTableComputed = false;
+ if (!crcTableComputed) {
+ makeCrcTable(crcTable);
+ crcTableComputed = true;
+ }
+
+ unsigned crc = 0xffffffffL;
+ for (size_t i = 0; i < size; ++i)
+ crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL);
+ return crc ^ 0xffffffffL;
+}
+
+ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc)
+ : m_image(bmp)
+ , m_texture(0)
+ , m_layer(0)
+ , m_picture(0)
+ , m_crc(crc)
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("ImageTexture");
+#endif
+ if (!m_image)
+ return;
+
+ // NOTE: This constructor is called on the webcore thread
+
+ // Create a picture containing the image (needed for TileGrid)
+ m_picture = new SkPicture();
+ SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height());
+ pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0));
+ pcanvas->drawBitmap(*m_image, 0, 0);
+ m_picture->endRecording();
+}
+
+ImageTexture::~ImageTexture()
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("ImageTexture");
+#endif
+ delete m_image;
+ delete m_texture;
+ SkSafeUnref(m_picture);
+}
+
+SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap)
+{
+ SkBitmap* img = new SkBitmap();
+ int w = bitmap->width();
+ int h = bitmap->height();
+
+ // Create a copy of the image
+ img->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ img->allocPixels();
+ SkDevice* device = new SkDevice(*img);
+ SkCanvas canvas;
+ canvas.setDevice(device);
+ device->unref();
+ SkRect dest;
+ dest.set(0, 0, w, h);
+ img->setIsOpaque(false);
+ img->eraseARGB(0, 0, 0, 0);
+ canvas.drawBitmapRect(*bitmap, 0, dest);
+
+ return img;
+}
+
+unsigned ImageTexture::computeCRC(const SkBitmap* bitmap)
+{
+ if (!bitmap)
+ return 0;
+ bitmap->lockPixels();
+ uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels());
+ unsigned crc = computeCrc(img, bitmap->getSize());
+ bitmap->unlockPixels();
+ return crc;
+}
+
+bool ImageTexture::equalsCRC(unsigned crc)
+{
+ return m_crc == crc;
+}
+
+int ImageTexture::nbTextures()
+{
+ if (!hasContentToShow())
+ return 0;
+ if (!m_texture)
+ return 0;
+
+ // TODO: take in account the visible clip (need to maintain
+ // a list of the clients layer, etc.)
+ IntRect visibleArea(0, 0, m_image->width(), m_image->height());
+ int nbTextures = m_texture->nbTextures(visibleArea, 1.0);
+ ALOGV("ImageTexture %p, %d x %d needs %d textures",
+ this, m_image->width(), m_image->height(),
+ nbTextures);
+ return nbTextures;
+}
+
+bool ImageTexture::hasContentToShow()
+{
+ // Don't display 1x1 image -- no need to allocate a full texture for this
+ if (!m_image)
+ return false;
+ if (m_image->width() == 1 && m_image->height() == 1)
+ return false;
+ return true;
+}
+
+bool ImageTexture::prepareGL(GLWebViewState* state)
+{
+ if (!hasContentToShow())
+ return false;
+
+ if (!m_texture && m_picture) {
+ bool isLayerTile = true;
+ m_texture = new TileGrid(isLayerTile);
+ SkRegion region;
+ region.setRect(0, 0, m_image->width(), m_image->height());
+ m_texture->markAsDirty(region);
+ }
+
+ if (!m_texture)
+ return false;
+
+ IntRect unclippedArea(0, 0, m_image->width(), m_image->height());
+ m_texture->prepareGL(state, 1.0, unclippedArea, unclippedArea, this);
+ if (m_texture->isReady()) {
+ m_texture->swapTiles();
+ return false;
+ }
+ return true;
+}
+
+const TransformationMatrix* ImageTexture::transform()
+{
+ if (!m_layer)
+ return 0;
+
+ FloatPoint p(0, 0);
+ p = m_layer->drawTransform()->mapPoint(p);
+ IntRect layerArea = m_layer->unclippedArea();
+ float scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width());
+ float scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height());
+ TransformationMatrix d = *(m_layer->drawTransform());
+ TransformationMatrix m;
+ m.scaleNonUniform(scaleW, scaleH);
+ m_layerMatrix = d.multiply(m);
+ return &m_layerMatrix;
+}
+
+float ImageTexture::opacity()
+{
+ if (!m_layer)
+ return 1.0;
+ return m_layer->drawOpacity();
+}
+
+bool ImageTexture::paint(Tile* tile, SkCanvas* canvas)
+{
+ if (!m_picture) {
+ ALOGV("IT %p COULDNT PAINT, NO PICTURE", this);
+ return false;
+ }
+
+ ALOGV("IT %p painting tile %d, %d with picture %p", this, tile->x(), tile->y(), m_picture);
+ canvas->drawPicture(*m_picture);
+
+ return true;
+}
+
+void ImageTexture::drawGL(LayerAndroid* layer, float opacity)
+{
+ if (!layer)
+ return;
+ if (!hasContentToShow())
+ return;
+
+ // TileGrid::draw() will call us back to know the
+ // transform and opacity, so we need to set m_layer
+ m_layer = layer;
+ if (m_texture) {
+ IntRect visibleArea = m_layer->visibleArea();
+ m_texture->drawGL(visibleArea, opacity, transform());
+ }
+ m_layer = 0;
+}
+
+void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect)
+{
+ if (canvas && m_image)
+ canvas->drawBitmapRect(*m_image, 0, rect);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/ImageTexture.h b/Source/WebCore/platform/graphics/android/rendering/ImageTexture.h
new file mode 100644
index 0000000..34430f1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/ImageTexture.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2011, 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 ImageTexture_h
+#define ImageTexture_h
+
+#include "GLUtils.h"
+#include "SkBitmap.h"
+#include "SkBitmapRef.h"
+#include "SkPicture.h"
+#include "SkRefCnt.h"
+#include "TilePainter.h"
+
+namespace WebCore {
+
+class GLWebViewState;
+class LayerAndroid;
+class TexturesResult;
+class TileGrid;
+
+/////////////////////////////////////////////////////////////////////////////////
+// Image sharing codepath for layers
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Layers containing only an image take a slightly different codepath;
+// GraphicsLayer::setContentsToImage() is called on the webcore thread,
+// passing an Image instance. We get the native image (an SkBitmap) and create
+// an ImageTexture instance with it (or increment the refcount of an existing
+// instance if the SkBitmap is similar to one already stored in ImagesManager,
+// i.e. if two GraphicsLayer share the same image).
+//
+// To detect if an image is similar, we compute and use a CRC. Each ImageTexture
+// is stored in ImagesManager using its CRC as a hash key.
+// Simply comparing the address is not enough -- different image could end up
+// at the same address (i.e. the image is deallocated then a new one is
+// reallocated at the old address)
+//
+// Each ImageTexture's CRC being unique, LayerAndroid instances simply store that
+// and retain/release the corresponding ImageTexture (so that
+// queued painting request will work correctly and not crash...).
+// LayerAndroid running on the UI thread will get the corresponding
+// ImageTexture at draw time.
+//
+// ImageTexture recopy the original SkBitmap so that they can safely be used
+// on a different thread; it uses TileGrid to allocate and paint the image,
+// so that we can share the same textures and limits as the rest of the layers.
+//
+/////////////////////////////////////////////////////////////////////////////////
+class ImageTexture : public TilePainter {
+public:
+ ImageTexture(SkBitmap* bmp, unsigned crc);
+ virtual ~ImageTexture();
+
+ bool prepareGL(GLWebViewState*);
+ void drawGL(LayerAndroid* layer, float opacity);
+ void drawCanvas(SkCanvas*, SkRect&);
+ bool hasContentToShow();
+ SkBitmap* bitmap() { return m_image; }
+ unsigned imageCRC() { return m_crc; }
+
+ static SkBitmap* convertBitmap(SkBitmap* bitmap);
+
+ static unsigned computeCRC(const SkBitmap* bitmap);
+ bool equalsCRC(unsigned crc);
+
+ // methods used by TileGrid
+ virtual bool paint(Tile* tile, SkCanvas* canvas);
+ virtual float opacity();
+
+ int nbTextures();
+
+ virtual SurfaceType type() { return TilePainter::Image; }
+
+private:
+ const TransformationMatrix* transform();
+
+ SkBitmapRef* m_imageRef;
+ SkBitmap* m_image;
+ TileGrid* m_texture;
+ LayerAndroid* m_layer;
+ SkPicture* m_picture;
+ TransformationMatrix m_layerMatrix;
+ unsigned m_crc;
+};
+
+} // namespace WebCore
+
+#endif // ImageTexture
diff --git a/Source/WebCore/platform/graphics/android/rendering/ImagesManager.cpp b/Source/WebCore/platform/graphics/android/rendering/ImagesManager.cpp
new file mode 100644
index 0000000..8452503
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/ImagesManager.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2011, 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 "ImagesManager"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "ImagesManager.h"
+
+#include "AndroidLog.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkRefCnt.h"
+#include "ImageTexture.h"
+
+namespace WebCore {
+
+ImagesManager* ImagesManager::instance()
+{
+ if (!gInstance)
+ gInstance = new ImagesManager();
+
+ return gInstance;
+}
+
+ImagesManager* ImagesManager::gInstance = 0;
+
+ImageTexture* ImagesManager::setImage(SkBitmapRef* imgRef)
+{
+ if (!imgRef)
+ return 0;
+
+ SkBitmap* bitmap = &imgRef->bitmap();
+ ImageTexture* image = 0;
+ SkBitmap* img = 0;
+ unsigned crc = 0;
+
+ img = ImageTexture::convertBitmap(bitmap);
+ crc = ImageTexture::computeCRC(img);
+
+ {
+ android::Mutex::Autolock lock(m_imagesLock);
+ if (m_images.contains(crc)) {
+ image = m_images.get(crc);
+ SkSafeRef(image);
+ return image;
+ }
+ }
+
+ // the image is not in the map, we add it
+
+ image = new ImageTexture(img, crc);
+
+ android::Mutex::Autolock lock(m_imagesLock);
+ m_images.set(crc, image);
+
+ return image;
+}
+
+ImageTexture* ImagesManager::retainImage(unsigned imgCRC)
+{
+ if (!imgCRC)
+ return 0;
+
+ android::Mutex::Autolock lock(m_imagesLock);
+ ImageTexture* image = 0;
+ if (m_images.contains(imgCRC)) {
+ image = m_images.get(imgCRC);
+ SkSafeRef(image);
+ }
+ return image;
+}
+
+void ImagesManager::releaseImage(unsigned imgCRC)
+{
+ if (!imgCRC)
+ return;
+
+ android::Mutex::Autolock lock(m_imagesLock);
+ if (m_images.contains(imgCRC)) {
+ ImageTexture* image = m_images.get(imgCRC);
+ if (image->getRefCnt() == 1)
+ m_images.remove(imgCRC);
+ SkSafeUnref(image);
+ }
+}
+
+int ImagesManager::nbTextures()
+{
+ android::Mutex::Autolock lock(m_imagesLock);
+ HashMap<unsigned, ImageTexture*>::iterator end = m_images.end();
+ int i = 0;
+ int nb = 0;
+ for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) {
+ nb += it->second->nbTextures();
+ i++;
+ }
+ return nb;
+}
+
+bool ImagesManager::prepareTextures(GLWebViewState* state)
+{
+ bool ret = false;
+ android::Mutex::Autolock lock(m_imagesLock);
+ HashMap<unsigned, ImageTexture*>::iterator end = m_images.end();
+ for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) {
+ ret |= it->second->prepareGL(state);
+ }
+ return ret;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/ImagesManager.h b/Source/WebCore/platform/graphics/android/rendering/ImagesManager.h
new file mode 100644
index 0000000..b915a46
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/ImagesManager.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011, 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 ImagesManager_h
+#define ImagesManager_h
+
+#include "HashMap.h"
+#include "SkBitmap.h"
+#include "SkBitmapRef.h"
+#include "SkRefCnt.h"
+#include "Vector.h"
+
+#include <utils/threads.h>
+
+namespace WebCore {
+
+class ImageTexture;
+class GLWebViewState;
+
+class ImagesManager {
+public:
+ static ImagesManager* instance();
+
+ ImageTexture* setImage(SkBitmapRef* imgRef);
+ ImageTexture* retainImage(unsigned imgCRC);
+ void releaseImage(unsigned imgCRC);
+
+ bool prepareTextures(GLWebViewState*);
+ int nbTextures();
+
+private:
+ ImagesManager() {}
+
+ static ImagesManager* gInstance;
+
+ android::Mutex m_imagesLock;
+ HashMap<unsigned, ImageTexture*> m_images;
+};
+
+} // namespace WebCore
+
+#endif // ImagesManager
diff --git a/Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.cpp b/Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.cpp
new file mode 100644
index 0000000..f9edb74
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2011, 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 "InspectorCanvas"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "InspectorCanvas.h"
+
+#include "AndroidLog.h"
+#include "SkPicture.h"
+
+namespace WebCore {
+
+
+void InspectorCanvas::setHasText()
+{
+ m_hasText = true;
+ setHasContent();
+}
+
+void InspectorCanvas::setHasContent()
+{
+ m_hasContent = true;
+ if (m_hasText) {
+ // has text. Have to paint properly, so no further
+ // information is useful
+ m_picture->abortPlayback();
+ }
+}
+
+void InspectorCanvas::setIsBackground(const SkPaint& paint)
+{
+ // TODO: if the paint is a solid color, opaque, and the last instruction in
+ // the picture, replace the picture with simple draw rect info
+ setHasContent();
+}
+
+void InspectorCanvas::commonDrawBitmap(const SkBitmap& bitmap,
+ const SkIRect* rect,
+ const SkMatrix&,
+ const SkPaint&)
+{
+ setHasContent();
+}
+
+void InspectorCanvas::drawPaint(const SkPaint& paint)
+{
+ setHasContent();
+}
+
+void InspectorCanvas::drawPath(const SkPath&, const SkPaint& paint)
+{
+ setHasContent();
+}
+void InspectorCanvas::drawPoints(PointMode, size_t,
+ const SkPoint [], const SkPaint& paint)
+{
+ setHasContent();
+}
+
+void InspectorCanvas::drawRect(const SkRect& rect, const SkPaint& paint)
+{
+ if (rect.fLeft == 0
+ && rect.fTop == 0
+ && rect.width() >= m_picture->width()
+ && rect.height() >= m_picture->height()) {
+ // rect same size as canvas, treat layer as a single color rect until
+ // more content is drawn
+ setIsBackground(paint);
+ } else {
+ // regular rect drawing path
+ setHasContent();
+ }
+ ALOGV("draw rect at %f %f, size %f %f, picture size %d %d",
+ rect.fLeft, rect.fTop, rect.width(), rect.height(),
+ m_picture->width(), m_picture->height());
+}
+void InspectorCanvas::drawSprite(const SkBitmap& , int , int ,
+ const SkPaint* paint)
+{
+ setHasContent();
+}
+
+void InspectorCanvas::drawText(const void*, size_t byteLength, SkScalar,
+ SkScalar, const SkPaint& paint)
+{
+ setHasText();
+}
+
+void InspectorCanvas::drawPosText(const void* , size_t byteLength,
+ const SkPoint [], const SkPaint& paint)
+{
+ setHasText();
+}
+
+void InspectorCanvas::drawPosTextH(const void*, size_t byteLength,
+ const SkScalar [], SkScalar,
+ const SkPaint& paint)
+{
+ setHasText();
+}
+
+void InspectorCanvas::drawTextOnPath(const void*, size_t byteLength,
+ const SkPath&, const SkMatrix*,
+ const SkPaint& paint)
+{
+ setHasText();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.h b/Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.h
new file mode 100644
index 0000000..415a579
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/InspectorCanvas.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011, 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 InspectorCanvas_h
+#define InspectorCanvas_h
+
+#include "SkBounder.h"
+#include "SkCanvas.h"
+
+namespace WebCore {
+
+class InspectorBounder : public SkBounder {
+ virtual bool onIRect(const SkIRect& rect)
+ {
+ return false;
+ }
+};
+
+class InspectorCanvas : public SkCanvas {
+public:
+ InspectorCanvas(SkBounder* bounder, SkPicture* picture)
+ : m_picture(picture)
+ , m_hasText(false)
+ , m_hasContent(false)
+ {
+ setBounder(bounder);
+ }
+
+ bool hasText() {return m_hasText;}
+ bool hasContent() {return m_hasContent;}
+
+ virtual bool clipPath(const SkPath&, SkRegion::Op) {
+ return true;
+ }
+
+ virtual void commonDrawBitmap(const SkBitmap& bitmap,
+ const SkIRect* rect,
+ const SkMatrix&,
+ const SkPaint&);
+
+ virtual void drawPaint(const SkPaint& paint);
+ virtual void drawPath(const SkPath&, const SkPaint& paint);
+ virtual void drawPoints(PointMode, size_t,
+ const SkPoint [], const SkPaint& paint);
+
+ virtual void drawRect(const SkRect& , const SkPaint& paint);
+ virtual void drawSprite(const SkBitmap& , int , int ,
+ const SkPaint* paint = NULL);
+
+ virtual void drawText(const void*, size_t byteLength, SkScalar,
+ SkScalar, const SkPaint& paint);
+ virtual void drawPosText(const void* , size_t byteLength,
+ const SkPoint [], const SkPaint& paint);
+ virtual void drawPosTextH(const void*, size_t byteLength,
+ const SkScalar [], SkScalar,
+ const SkPaint& paint);
+ virtual void drawTextOnPath(const void*, size_t byteLength,
+ const SkPath&, const SkMatrix*,
+ const SkPaint& paint);
+
+private:
+
+ // vector instructions exist, must repaint at any scale
+ void setHasText();
+
+ // painting is required
+ void setHasContent();
+
+ // rect covering entire content, don't need to use a texture if nothing else
+ // is painted
+ void setIsBackground(const SkPaint& paint);
+
+ SkPicture* m_picture;
+ bool m_hasText;
+ bool m_hasContent;
+};
+
+} // namespace WebCore
+
+#endif // InspectorCanvas_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp
new file mode 100644
index 0000000..b5e435b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011, 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 "PaintTileOperation"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "PaintTileOperation.h"
+
+#include "AndroidLog.h"
+#include "GLWebViewState.h"
+#include "ImageTexture.h"
+#include "ImagesManager.h"
+#include "LayerAndroid.h"
+#include "TilesManager.h"
+
+namespace WebCore {
+
+PaintTileOperation::PaintTileOperation(Tile* tile, TilePainter* painter,
+ GLWebViewState* state, bool isLowResPrefetch)
+ : m_tile(tile)
+ , m_painter(painter)
+ , m_state(state)
+ , m_isLowResPrefetch(isLowResPrefetch)
+{
+ if (m_tile)
+ m_tile->setRepaintPending(true);
+ SkSafeRef(m_painter);
+}
+
+PaintTileOperation::~PaintTileOperation()
+{
+ if (m_tile) {
+ m_tile->setRepaintPending(false);
+ m_tile = 0;
+ }
+
+ if (m_painter && m_painter->type() == TilePainter::Image) {
+ ImageTexture* image = static_cast<ImageTexture*>(m_painter);
+ ImagesManager::instance()->releaseImage(image->imageCRC());
+ } else {
+ SkSafeUnref(m_painter);
+ }
+}
+
+bool PaintTileOperation::operator==(const QueuedOperation* operation)
+{
+ const PaintTileOperation* op = static_cast<const PaintTileOperation*>(operation);
+ return op->m_tile == m_tile;
+}
+
+void PaintTileOperation::run()
+{
+ if (m_tile) {
+ m_tile->paintBitmap(m_painter);
+ m_tile->setRepaintPending(false);
+ m_tile = 0;
+ }
+}
+
+int PaintTileOperation::priority()
+{
+ if (!m_tile)
+ return -1;
+
+ int priority = 200000;
+
+ // prioritize low res while scrolling
+ if (m_isLowResPrefetch)
+ priority = m_state->isScrolling() ? 0 : 400000;
+
+ // prioritize higher draw count
+ unsigned long long currentDraw = TilesManager::instance()->getDrawGLCount();
+ unsigned long long drawDelta = currentDraw - m_tile->drawCount();
+ priority += 100000 * (int)std::min(drawDelta, (unsigned long long)1000);
+
+ // prioritize unpainted tiles, within the same drawCount
+ if (m_tile->frontTexture())
+ priority += 50000;
+
+ // for base tiles, prioritize based on position
+ if (!m_tile->isLayerTile()) {
+ bool goingDown = m_state->goingDown();
+ priority += m_tile->x();
+
+ if (goingDown)
+ priority += 100000 - (1 + m_tile->y()) * 1000;
+ else
+ priority += m_tile->y() * 1000;
+ }
+
+ return priority;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h
new file mode 100644
index 0000000..1d376bf
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2010, 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 PaintTileSetOperation_h
+#define PaintTileSetOperation_h
+
+#include "Tile.h"
+#include "QueuedOperation.h"
+#include "SkRefCnt.h"
+
+namespace WebCore {
+
+class LayerAndroid;
+class TilePainter;
+class ImageTexture;
+
+class PaintTileOperation : public QueuedOperation {
+public:
+ PaintTileOperation(Tile* tile, TilePainter* painter,
+ GLWebViewState* state, bool isLowResPrefetch);
+ 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_painter; }
+ float scale() { return m_tile->scale(); }
+
+private:
+ Tile* m_tile;
+ TilePainter* m_painter;
+ GLWebViewState* m_state;
+ bool m_isLowResPrefetch;
+};
+
+class ScaleFilter : public OperationFilter {
+public:
+ ScaleFilter(const TilePainter* painter, float scale)
+ : m_painter(painter)
+ , m_scale(scale) {}
+ virtual bool check(QueuedOperation* operation)
+ {
+ PaintTileOperation* op = static_cast<PaintTileOperation*>(operation);
+ return ((op->painter() == m_painter) && (op->scale() != m_scale));
+ }
+private:
+ const TilePainter* m_painter;
+ float m_scale;
+};
+
+
+class TilePainterFilter : public OperationFilter {
+public:
+ TilePainterFilter(TilePainter* painter) : m_painter(painter) {}
+ virtual bool check(QueuedOperation* operation)
+ {
+ PaintTileOperation* op = static_cast<PaintTileOperation*>(operation);
+ return op->painter() == m_painter;
+ }
+private:
+ TilePainter* m_painter;
+};
+
+}
+
+#endif // PaintTileSetOperation_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h b/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h
new file mode 100644
index 0000000..f98efcd
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010, 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 QueuedOperation_h
+#define QueuedOperation_h
+
+namespace WebCore {
+
+class QueuedOperation {
+public:
+ virtual ~QueuedOperation() {}
+ virtual void run() = 0;
+ virtual bool operator==(const QueuedOperation* operation) = 0;
+ virtual int priority() = 0;
+};
+
+class OperationFilter {
+public:
+ virtual ~OperationFilter() {}
+ virtual bool check(QueuedOperation* operation) = 0;
+};
+
+}
+
+#endif // QueuedOperation_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp
new file mode 100644
index 0000000..b880eef
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011, 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 "RasterRenderer"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "RasterRenderer.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "GLUtils.h"
+#include "SkBitmap.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "Tile.h"
+#include "TilesManager.h"
+
+namespace WebCore {
+
+SkBitmap* RasterRenderer::g_bitmap = 0;
+
+RasterRenderer::RasterRenderer() : BaseRenderer(BaseRenderer::Raster)
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("RasterRenderer");
+#endif
+ if (!g_bitmap) {
+ g_bitmap = new SkBitmap();
+ g_bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ TilesManager::instance()->tileWidth(),
+ TilesManager::instance()->tileHeight());
+ g_bitmap->allocPixels();
+ }
+}
+
+RasterRenderer::~RasterRenderer()
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("RasterRenderer");
+#endif
+}
+
+void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas)
+{
+ if (renderInfo.baseTile->isLayerTile()) {
+ g_bitmap->setIsOpaque(false);
+ g_bitmap->eraseARGB(0, 0, 0, 0);
+ } else {
+ Color defaultBackground = Color::white;
+ Color* background = renderInfo.tilePainter->background();
+ if (!background) {
+ ALOGV("No background color for base layer!");
+ background = &defaultBackground;
+ }
+ ALOGV("setupCanvas use background on Base Layer %x", background->rgb());
+ g_bitmap->setIsOpaque(!background->hasAlpha());
+ g_bitmap->eraseARGB(background->alpha(), background->red(),
+ background->green(), background->blue());
+ }
+
+ SkDevice* device = new SkDevice(*g_bitmap);
+
+ canvas->setDevice(device);
+
+ device->unref();
+
+ // If we have a partially painted bitmap
+ if (renderInfo.invalRect) {
+ SkRect clipRect = SkRect::MakeWH(renderInfo.invalRect->width(),
+ renderInfo.invalRect->height());
+ // ensure the canvas origin is translated to the coordinates of our inval rect
+ canvas->clipRect(clipRect);
+ canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop);
+ }
+}
+
+void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas)
+{
+ const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false);
+ GLUtils::paintTextureWithBitmap(&renderInfo, bitmap);
+}
+
+void RasterRenderer::checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas)
+{
+ renderInfo.isPureColor = GLUtils::isPureColorBitmap(*g_bitmap, renderInfo.pureColor);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h
new file mode 100644
index 0000000..39e00f2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011, 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 RasterRenderer_h
+#define RasterRenderer_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "BaseRenderer.h"
+#include "SkBitmap.h"
+#include "SkRect.h"
+
+class SkCanvas;
+class SkDevice;
+
+namespace WebCore {
+
+/**
+ *
+ */
+class RasterRenderer : public BaseRenderer {
+public:
+ RasterRenderer();
+ ~RasterRenderer();
+
+protected:
+
+ virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas);
+ virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas);
+ virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas);
+
+private:
+ static SkBitmap* g_bitmap;
+
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // RasterRenderer_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp
new file mode 100644
index 0000000..a0d9e56
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2010, 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 "ShaderProgram"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "ShaderProgram.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "DrawQuadData.h"
+#include "FloatPoint3D.h"
+#include "GLUtils.h"
+#include "TilesManager.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace WebCore {
+
+static const char gVertexShader[] =
+ "attribute vec4 vPosition;\n"
+ "uniform mat4 projectionMatrix;\n"
+ "varying vec2 v_texCoord;\n"
+ "void main() {\n"
+ " gl_Position = projectionMatrix * vPosition;\n"
+ " v_texCoord = vec2(vPosition);\n"
+ "}\n";
+
+static const char gFragmentShader[] =
+ "precision mediump float;\n"
+ "varying vec2 v_texCoord; \n"
+ "uniform float alpha; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
+ " gl_FragColor *= alpha; "
+ "}\n";
+
+// We could pass the pureColor into either Vertex or Frag Shader.
+// The reason we passed the color into the Vertex Shader is that some driver
+// might create redundant copy when uniforms in fragment shader changed.
+static const char gPureColorVertexShader[] =
+ "attribute vec4 vPosition;\n"
+ "uniform mat4 projectionMatrix;\n"
+ "uniform vec4 inputColor;\n"
+ "varying vec4 v_color;\n"
+ "void main() {\n"
+ " gl_Position = projectionMatrix * vPosition;\n"
+ " v_color = inputColor;\n"
+ "}\n";
+
+static const char gPureColorFragmentShader[] =
+ "precision mediump float;\n"
+ "varying vec4 v_color;\n"
+ "void main() {\n"
+ " gl_FragColor = v_color;\n"
+ "}\n";
+
+static const char gFragmentShaderInverted[] =
+ "precision mediump float;\n"
+ "varying vec2 v_texCoord; \n"
+ "uniform float alpha; \n"
+ "uniform float contrast; \n"
+ "uniform sampler2D s_texture; \n"
+ "void main() {\n"
+ " vec4 pixel = texture2D(s_texture, v_texCoord); \n"
+ " float a = pixel.a; \n"
+ " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
+ " color = ((color - a/2.0) * contrast) + a/2.0; \n"
+ " pixel.rgb = vec3(color, color, color); \n "
+ " gl_FragColor = pixel; \n"
+ " gl_FragColor *= alpha; \n"
+ "}\n";
+
+static const char gVideoVertexShader[] =
+ "attribute vec4 vPosition;\n"
+ "uniform mat4 textureMatrix;\n"
+ "uniform mat4 projectionMatrix;\n"
+ "varying vec2 v_texCoord;\n"
+ "void main() {\n"
+ " gl_Position = projectionMatrix * vPosition;\n"
+ " v_texCoord = vec2(textureMatrix * vec4(vPosition.x, 1.0 - vPosition.y, 0.0, 1.0));\n"
+ "}\n";
+
+static const char gVideoFragmentShader[] =
+ "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES s_yuvTexture;\n"
+ "varying vec2 v_texCoord;\n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(s_yuvTexture, v_texCoord);\n"
+ "}\n";
+
+static const char gSurfaceTextureOESFragmentShader[] =
+ "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 v_texCoord; \n"
+ "uniform float alpha; \n"
+ "uniform samplerExternalOES s_texture; \n"
+ "void main() {\n"
+ " gl_FragColor = texture2D(s_texture, v_texCoord); \n"
+ " gl_FragColor *= alpha; "
+ "}\n";
+
+static const char gSurfaceTextureOESFragmentShaderInverted[] =
+ "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 v_texCoord; \n"
+ "uniform float alpha; \n"
+ "uniform float contrast; \n"
+ "uniform samplerExternalOES s_texture; \n"
+ "void main() {\n"
+ " vec4 pixel = texture2D(s_texture, v_texCoord); \n"
+ " float a = pixel.a; \n"
+ " float color = a - (0.2989 * pixel.r + 0.5866 * pixel.g + 0.1145 * pixel.b);\n"
+ " color = ((color - a/2.0) * contrast) + a/2.0; \n"
+ " pixel.rgb = vec3(color, color, color); \n "
+ " gl_FragColor = pixel; \n"
+ " gl_FragColor *= alpha; \n"
+ "}\n";
+
+GLuint ShaderProgram::loadShader(GLenum shaderType, const char* pSource)
+{
+ GLuint shader = glCreateShader(shaderType);
+ if (shader) {
+ glShaderSource(shader, 1, &pSource, 0);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(shader, infoLen, 0, buf);
+ ALOGE("could not compile shader %d:\n%s\n", shaderType, buf);
+ free(buf);
+ }
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+GLint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragmentSource)
+{
+ GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+ if (!vertexShader) {
+ ALOGE("couldn't load the vertex shader!");
+ return -1;
+ }
+
+ GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+ if (!pixelShader) {
+ ALOGE("couldn't load the pixel shader!");
+ return -1;
+ }
+
+ GLuint program = glCreateProgram();
+ if (program) {
+ glAttachShader(program, vertexShader);
+ GLUtils::checkGlError("glAttachShader vertex");
+ glAttachShader(program, pixelShader);
+ GLUtils::checkGlError("glAttachShader pixel");
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus != GL_TRUE) {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if (bufLength) {
+ char* buf = (char*) malloc(bufLength);
+ if (buf) {
+ glGetProgramInfoLog(program, bufLength, 0, buf);
+ ALOGE("could not link program:\n%s\n", buf);
+ free(buf);
+ }
+ }
+ glDeleteProgram(program);
+ program = -1;
+ }
+ }
+
+ ShaderResource newResource(program, vertexShader, pixelShader);
+ m_resources.append(newResource);
+ return program;
+}
+
+ShaderProgram::ShaderProgram()
+ : m_blendingEnabled(false)
+ , m_contrast(1)
+ , m_alphaLayer(false)
+ , m_currentScale(1.0f)
+ , m_needsInit(true)
+{
+}
+
+void ShaderProgram::cleanupGLResources()
+{
+ for (unsigned int i = 0; i < m_resources.size(); i++) {
+ glDetachShader(m_resources[i].program, m_resources[i].vertexShader);
+ glDetachShader(m_resources[i].program, m_resources[i].fragmentShader);
+ glDeleteShader(m_resources[i].vertexShader);
+ glDeleteShader(m_resources[i].fragmentShader);
+ glDeleteProgram(m_resources[i].program);
+ }
+ glDeleteBuffers(1, m_textureBuffer);
+
+ m_resources.clear();
+ m_needsInit = true;
+ GLUtils::checkGlError("cleanupGLResources");
+
+ return;
+}
+
+void ShaderProgram::initGLResources()
+{
+ // To detect whether or not resources for ShaderProgram allocated
+ // successfully, we clean up pre-existing errors here and will check for
+ // new errors at the end of this function.
+ GLUtils::checkGlError("before initGLResources");
+
+ GLint tex2DProgram = createProgram(gVertexShader, gFragmentShader);
+ GLint pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader);
+ GLint tex2DInvProgram = createProgram(gVertexShader, gFragmentShaderInverted);
+ GLint videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader);
+ GLint texOESProgram =
+ createProgram(gVertexShader, gSurfaceTextureOESFragmentShader);
+ GLint texOESInvProgram =
+ createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted);
+
+ if (tex2DProgram == -1
+ || pureColorProgram == -1
+ || tex2DInvProgram == -1
+ || videoProgram == -1
+ || texOESProgram == -1
+ || texOESInvProgram == -1) {
+ m_needsInit = true;
+ return;
+ }
+
+ GLint pureColorPosition = glGetAttribLocation(pureColorProgram, "vPosition");
+ GLint pureColorProjMtx = glGetUniformLocation(pureColorProgram, "projectionMatrix");
+ GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor");
+ m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram,
+ pureColorProjMtx, pureColorValue, -1, -1);
+
+ GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha");
+ GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition");
+ GLint tex2DProjMtx = glGetUniformLocation(tex2DProgram, "projectionMatrix");
+ GLint tex2DTexSampler = glGetUniformLocation(tex2DProgram, "s_texture");
+ m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram,
+ tex2DProjMtx, -1, tex2DTexSampler, -1);
+
+ GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha");
+ GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast");
+ GLint tex2DInvPosition = glGetAttribLocation(tex2DInvProgram, "vPosition");
+ GLint tex2DInvProjMtx = glGetUniformLocation(tex2DInvProgram, "projectionMatrix");
+ GLint tex2DInvTexSampler = glGetUniformLocation(tex2DInvProgram, "s_texture");
+ m_handleArray[Tex2DInv].init(tex2DInvAlpha, tex2DInvContrast,
+ tex2DInvPosition, tex2DInvProgram,
+ tex2DInvProjMtx, -1,
+ tex2DInvTexSampler, -1);
+
+ GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha");
+ GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition");
+ GLint texOESProjMtx = glGetUniformLocation(texOESProgram, "projectionMatrix");
+ GLint texOESTexSampler = glGetUniformLocation(texOESProgram, "s_texture");
+ m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram,
+ texOESProjMtx, -1, texOESTexSampler, -1);
+
+ GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha");
+ GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast");
+ GLint texOESInvPosition = glGetAttribLocation(texOESInvProgram, "vPosition");
+ GLint texOESInvProjMtx = glGetUniformLocation(texOESInvProgram, "projectionMatrix");
+ GLint texOESInvTexSampler = glGetUniformLocation(texOESInvProgram, "s_texture");
+ m_handleArray[TexOESInv].init(texOESInvAlpha, texOESInvContrast,
+ texOESInvPosition, texOESInvProgram,
+ texOESInvProjMtx, -1,
+ texOESInvTexSampler, -1);
+
+ GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition");
+ GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix");
+ GLint videoTexSampler = glGetUniformLocation(videoProgram, "s_yuvTexture");
+ GLint videoTexMtx = glGetUniformLocation(videoProgram, "textureMatrix");
+ m_handleArray[Video].init(-1, -1, videoPosition, videoProgram,
+ videoProjMtx, -1, videoTexSampler,
+ videoTexMtx);
+
+ const GLfloat coord[] = {
+ 0.0f, 0.0f, // C
+ 1.0f, 0.0f, // D
+ 0.0f, 1.0f, // A
+ 1.0f, 1.0f // B
+ };
+
+ glGenBuffers(1, m_textureBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
+ glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW);
+
+ TransformationMatrix matrix;
+ // Map x,y from (0,1) to (-1, 1)
+ matrix.scale3d(2, 2, 1);
+ matrix.translate3d(-0.5, -0.5, 0);
+ GLUtils::toGLMatrix(m_transferProjMtx, matrix);
+
+ m_needsInit = GLUtils::checkGlError("initGLResources");
+ return;
+}
+
+void ShaderProgram::resetBlending()
+{
+ glDisable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendEquation(GL_FUNC_ADD);
+ m_blendingEnabled = false;
+}
+
+void ShaderProgram::setBlendingState(bool enableBlending)
+{
+ if (enableBlending == m_blendingEnabled)
+ return;
+
+ if (enableBlending)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ m_blendingEnabled = enableBlending;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Drawing
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void ShaderProgram::setupDrawing(const IntRect& viewRect, const SkRect& visibleRect,
+ const IntRect& webViewRect, int titleBarHeight,
+ const IntRect& screenClip, float scale)
+{
+ m_webViewRect = webViewRect;
+ m_titleBarHeight = titleBarHeight;
+
+ //// viewport ////
+ TransformationMatrix ortho;
+ GLUtils::setOrthographicMatrix(ortho, visibleRect.fLeft, visibleRect.fTop,
+ visibleRect.fRight, visibleRect.fBottom, -1000, 1000);
+ // In most case , visibleRect / viewRect * scale should 1.0, but for the
+ // translation case, the scale factor can be 1 but visibleRect is smaller
+ // than viewRect, we need to tune in this factor to make sure we scale them
+ // right. Conceptually, that means, no matter how animation affects the
+ // visibleRect, the scaling should respect the viewRect if zoomScale is 1.0.
+ // Note that at TiledPage, we already scale the tile size inversely to make
+ // zooming animation right.
+ float orthoScaleX = scale * visibleRect.width() / viewRect.width();
+ float orthoScaleY = scale * visibleRect.height() / viewRect.height();
+
+ TransformationMatrix orthoScale;
+ orthoScale.scale3d(orthoScaleX, orthoScaleY, 1.0);
+
+ m_projectionMatrix = ortho * orthoScale;
+ m_viewport = visibleRect;
+ m_currentScale = scale;
+
+
+ //// viewRect ////
+ m_viewRect = viewRect;
+
+ // We do clipping using glScissor, which needs to take
+ // coordinates in screen space. The following matrix transform
+ // content coordinates in screen coordinates.
+ TransformationMatrix viewTranslate;
+ viewTranslate.translate(1.0, 1.0);
+
+ TransformationMatrix viewScale;
+ viewScale.scale3d(m_viewRect.width() * 0.5f, m_viewRect.height() * 0.5f, 1);
+
+ m_documentToScreenMatrix = viewScale * viewTranslate * m_projectionMatrix;
+
+ viewTranslate.scale3d(1, -1, 1);
+ m_documentToInvScreenMatrix = viewScale * viewTranslate * m_projectionMatrix;
+
+ IntRect rect(0, 0, m_webViewRect.width(), m_webViewRect.height());
+ m_documentViewport = m_documentToScreenMatrix.inverse().mapRect(rect);
+
+
+ //// clipping ////
+ IntRect mclip = screenClip;
+
+ // the clip from frameworks is in full screen coordinates
+ mclip.setY(screenClip.y() - m_webViewRect.y() - m_titleBarHeight);
+ FloatRect tclip = convertInvScreenCoordToScreenCoord(mclip);
+ m_screenClip.setLocation(IntPoint(tclip.x(), tclip.y()));
+ // use ceilf to handle view -> doc -> view coord rounding errors
+ m_screenClip.setSize(IntSize(ceilf(tclip.width()), ceilf(tclip.height())));
+
+ resetBlending();
+}
+
+// Calculate the right color value sent into the shader considering the (0,1)
+// clamp and alpha blending.
+Color ShaderProgram::shaderColor(Color pureColor, float opacity)
+{
+ float r = pureColor.red() / 255.0;
+ float g = pureColor.green() / 255.0;
+ float b = pureColor.blue() / 255.0;
+ float a = pureColor.alpha() / 255.0;
+
+ if (TilesManager::instance()->invertedScreen()) {
+ float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b);
+ intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0;
+ intensity *= opacity;
+ return Color(intensity, intensity, intensity, a * opacity);
+ }
+ return Color(r * opacity, g * opacity, b * opacity, a * opacity);
+}
+
+// For shaders using texture, it is easy to get the type from the textureTarget.
+ShaderType ShaderProgram::getTextureShaderType(GLenum textureTarget)
+{
+ ShaderType type = UndefinedShader;
+ if (textureTarget == GL_TEXTURE_2D) {
+ if (!TilesManager::instance()->invertedScreen())
+ type = Tex2D;
+ else {
+ // With the new GPU texture upload path, we do not use an FBO
+ // to blit the texture we receive from the TexturesGenerator thread.
+ // To implement inverted rendering, we thus have to do the rendering
+ // live, by using a different shader.
+ type = Tex2DInv;
+ }
+ } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES) {
+ if (!TilesManager::instance()->invertedScreen())
+ type = TexOES;
+ else
+ type = TexOESInv;
+ }
+ return type;
+}
+
+// This function transform a clip rect extracted from the current layer
+// into a clip rect in screen coordinates -- used by the clipping rects
+FloatRect ShaderProgram::rectInScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
+{
+ FloatRect srect(0, 0, size.width(), size.height());
+ TransformationMatrix renderMatrix = m_documentToScreenMatrix * drawMatrix;
+ return renderMatrix.mapRect(srect);
+}
+
+// used by the partial screen invals
+FloatRect ShaderProgram::rectInInvScreenCoord(const TransformationMatrix& drawMatrix, const IntSize& size)
+{
+ FloatRect srect(0, 0, size.width(), size.height());
+ TransformationMatrix renderMatrix = m_documentToInvScreenMatrix * drawMatrix;
+ return renderMatrix.mapRect(srect);
+}
+
+FloatRect ShaderProgram::rectInInvScreenCoord(const FloatRect& rect)
+{
+ return m_documentToInvScreenMatrix.mapRect(rect);
+}
+
+FloatRect ShaderProgram::rectInScreenCoord(const FloatRect& rect)
+{
+ return m_documentToScreenMatrix.mapRect(rect);
+}
+
+FloatRect ShaderProgram::convertScreenCoordToDocumentCoord(const FloatRect& rect)
+{
+ return m_documentToScreenMatrix.inverse().mapRect(rect);
+}
+
+FloatRect ShaderProgram::convertInvScreenCoordToScreenCoord(const FloatRect& rect)
+{
+ FloatRect documentRect = m_documentToInvScreenMatrix.inverse().mapRect(rect);
+ return rectInScreenCoord(documentRect);
+}
+
+FloatRect ShaderProgram::convertScreenCoordToInvScreenCoord(const FloatRect& rect)
+{
+ FloatRect documentRect = m_documentToScreenMatrix.inverse().mapRect(rect);
+ return rectInInvScreenCoord(documentRect);
+}
+
+// clip is in screen coordinates
+void ShaderProgram::clip(const FloatRect& clip)
+{
+ if (clip == m_clipRect)
+ return;
+
+ ALOGV("--clipping rect %f %f, %f x %f",
+ clip.x(), clip.y(), clip.width(), clip.height());
+
+ // we should only call glScissor in this function, so that we can easily
+ // track the current clipping rect.
+
+ IntRect screenClip(clip.x(),
+ clip.y(),
+ clip.width(), clip.height());
+
+ if (!m_screenClip.isEmpty())
+ screenClip.intersect(m_screenClip);
+
+ screenClip.setY(screenClip.y() + m_viewRect.y());
+ if (screenClip.x() < 0) {
+ int w = screenClip.width();
+ w += screenClip.x();
+ screenClip.setX(0);
+ screenClip.setWidth(w);
+ }
+ if (screenClip.y() < 0) {
+ int h = screenClip.height();
+ h += screenClip.y();
+ screenClip.setY(0);
+ screenClip.setHeight(h);
+ }
+
+ glScissor(screenClip.x(), screenClip.y(), screenClip.width(), screenClip.height());
+
+ m_clipRect = clip;
+}
+
+IntRect ShaderProgram::clippedRectWithViewport(const IntRect& rect, int margin)
+{
+ IntRect viewport(m_viewport.fLeft - margin, m_viewport.fTop - margin,
+ m_viewport.width() + margin, m_viewport.height() + margin);
+ viewport.intersect(rect);
+ return viewport;
+}
+
+float ShaderProgram::zValue(const TransformationMatrix& drawMatrix, float w, float h)
+{
+ TransformationMatrix modifiedDrawMatrix = drawMatrix;
+ modifiedDrawMatrix.scale3d(w, h, 1);
+ TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
+ FloatPoint3D point(0.5, 0.5, 0.0);
+ FloatPoint3D result = renderMatrix.mapPoint(point);
+ return result.z();
+}
+
+void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix,
+ int textureId, float opacity,
+ GLenum textureTarget, GLenum filter,
+ const Color& pureColor)
+{
+ glUseProgram(m_handleArray[type].programHandle);
+ glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix);
+
+ if (type != PureColor) {
+ glActiveTexture(GL_TEXTURE0);
+ glUniform1i(m_handleArray[type].texSamplerHandle, 0);
+ glBindTexture(textureTarget, textureId);
+ glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter);
+ glUniform1f(m_handleArray[type].alphaHandle, opacity);
+
+ GLint contrastHandle = m_handleArray[type].contrastHandle;
+ if (contrastHandle != -1)
+ glUniform1f(contrastHandle, m_contrast);
+ } else {
+ glUniform4f(m_handleArray[type].pureColorHandle,
+ pureColor.red() / 255.0, pureColor.green() / 255.0,
+ pureColor.blue() / 255.0, pureColor.alpha() / 255.0);
+ }
+
+ GLint positionHandle = m_handleArray[type].positionHandle;
+ glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
+ glEnableVertexAttribArray(positionHandle);
+ glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+// Calculate the matrix given the geometry.
+GLfloat* ShaderProgram::getProjectionMatrix(const DrawQuadData* data)
+{
+ DrawQuadType type = data->type();
+ const TransformationMatrix* matrix = data->drawMatrix();
+ const SkRect* geometry = data->geometry();
+ if (type == Blit)
+ return m_transferProjMtx;
+ TransformationMatrix modifiedDrawMatrix;
+ if (type == LayerQuad)
+ modifiedDrawMatrix = *matrix;
+ // move the drawing depending on where the texture is on the layer
+ modifiedDrawMatrix.translate(geometry->fLeft, geometry->fTop);
+ modifiedDrawMatrix.scale3d(geometry->width(), geometry->height(), 1);
+
+ TransformationMatrix renderMatrix;
+ if (!m_alphaLayer)
+ renderMatrix = m_projectionMatrix * m_repositionMatrix
+ * m_webViewMatrix * modifiedDrawMatrix;
+ else
+ renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
+
+ GLUtils::toGLMatrix(m_tileProjMatrix, renderMatrix);
+ return m_tileProjMatrix;
+}
+
+void ShaderProgram::drawQuad(const DrawQuadData* data)
+{
+ GLfloat* matrix = getProjectionMatrix(data);
+
+ float opacity = data->opacity();
+ bool forceBlending = data->forceBlending();
+ bool enableBlending = forceBlending || opacity < 1.0;
+
+ ShaderType shaderType = UndefinedShader;
+ int textureId = 0;
+ GLint textureFilter = 0;
+ GLenum textureTarget = 0;
+
+ Color quadColor = data->quadColor();
+ if (data->pureColor()) {
+ shaderType = PureColor;
+ quadColor = shaderColor(quadColor, opacity);
+ enableBlending = enableBlending || quadColor.hasAlpha();
+ if (!quadColor.alpha() && enableBlending)
+ return;
+ } else {
+ textureId = data->textureId();
+ textureFilter = data->textureFilter();
+ textureTarget = data->textureTarget();
+ shaderType = getTextureShaderType(textureTarget);
+ }
+ setBlendingState(enableBlending);
+ drawQuadInternal(shaderType, matrix, textureId, opacity,
+ textureTarget, textureFilter, quadColor);
+}
+
+void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
+ float* textureMatrix, SkRect& geometry,
+ int textureId)
+{
+ // switch to our custom yuv video rendering program
+ glUseProgram(m_handleArray[Video].programHandle);
+
+ TransformationMatrix modifiedDrawMatrix = drawMatrix;
+ modifiedDrawMatrix.translate(geometry.fLeft, geometry.fTop);
+ modifiedDrawMatrix.scale3d(geometry.width(), geometry.height(), 1);
+ TransformationMatrix renderMatrix = m_projectionMatrix * modifiedDrawMatrix;
+
+ GLfloat projectionMatrix[16];
+ GLUtils::toGLMatrix(projectionMatrix, renderMatrix);
+ glUniformMatrix4fv(m_handleArray[Video].projMtxHandle, 1, GL_FALSE,
+ projectionMatrix);
+ glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE,
+ textureMatrix);
+
+ glActiveTexture(GL_TEXTURE0);
+ glUniform1i(m_handleArray[Video].texSamplerHandle, 0);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
+
+ GLint videoPosition = m_handleArray[Video].positionHandle;
+ glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]);
+ glEnableVertexAttribArray(videoPosition);
+ glVertexAttribPointer(videoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ setBlendingState(false);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+void ShaderProgram::setWebViewMatrix(const float* matrix, bool alphaLayer)
+{
+ GLUtils::convertToTransformationMatrix(matrix, m_webViewMatrix);
+ m_alphaLayer = alphaLayer;
+}
+
+void ShaderProgram::calculateAnimationDelta()
+{
+ // The matrix contains the scrolling info, so this rect is starting from
+ // the m_viewport.
+ // So we just need to map the webview's visible rect using the matrix,
+ // calculate the difference b/t transformed rect and the webViewRect,
+ // then we can get the delta x , y caused by the animation.
+ // Note that the Y is for reporting back to GL viewport, so it is inverted.
+ // When it is alpha animation, then we rely on the framework implementation
+ // such that there is no matrix applied in native webkit.
+ if (!m_alphaLayer) {
+ FloatRect rect(m_viewport.fLeft * m_currentScale,
+ m_viewport.fTop * m_currentScale,
+ m_webViewRect.width(),
+ m_webViewRect.height());
+ rect = m_webViewMatrix.mapRect(rect);
+ m_animationDelta.setX(rect.x() - m_webViewRect.x() );
+ m_animationDelta.setY(rect.y() + rect.height() - m_webViewRect.y()
+ - m_webViewRect.height() - m_titleBarHeight);
+
+ m_repositionMatrix.makeIdentity();
+ m_repositionMatrix.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0);
+ m_repositionMatrix.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0);
+ m_repositionMatrix.translate3d(-m_animationDelta.x(), -m_animationDelta.y(), 0);
+ } else {
+ m_animationDelta.setX(0);
+ m_animationDelta.setY(0);
+ m_repositionMatrix.makeIdentity();
+ }
+
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h
new file mode 100644
index 0000000..b233f2b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ShaderProgram_h
+#define ShaderProgram_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "Color.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "SkRect.h"
+#include "TransformationMatrix.h"
+#include <GLES2/gl2.h>
+
+#define MAX_CONTRAST 5
+
+namespace WebCore {
+
+class DrawQuadData;
+class PureColorQuadData;
+class TextureQuadData;
+
+enum ShaderType {
+ UndefinedShader = -1,
+ PureColor,
+ Tex2D,
+ Tex2DInv,
+ TexOES,
+ TexOESInv,
+ Video,
+ // When growing this enum list, make sure to insert before the
+ // MaxShaderNumber and init the m_handleArray accordingly.
+ MaxShaderNumber
+};
+
+struct ShaderHandles {
+ ShaderHandles()
+ : alphaHandle(-1)
+ , contrastHandle(-1)
+ , positionHandle(-1)
+ , programHandle(-1)
+ , projMtxHandle(-1)
+ , pureColorHandle(-1)
+ , texSamplerHandle(-1)
+ , videoMtxHandle(-1)
+ {
+ }
+
+ void init(GLint alphaHdl, GLint contrastHdl, GLint posHdl, GLint pgmHdl,
+ GLint projMtxHdl, GLint colorHdl, GLint texSamplerHdl,
+ GLint videoMtxHdl)
+ {
+ alphaHandle = alphaHdl;
+ contrastHandle = contrastHdl;
+ positionHandle = posHdl;
+ programHandle = pgmHdl;
+ projMtxHandle = projMtxHdl;
+ pureColorHandle = colorHdl;
+ texSamplerHandle = texSamplerHdl;
+ videoMtxHandle = videoMtxHdl;
+ }
+
+ GLint alphaHandle;
+ GLint contrastHandle;
+ GLint positionHandle;
+ GLint programHandle;
+ GLint projMtxHandle;
+ GLint pureColorHandle;
+ GLint texSamplerHandle;
+ GLint videoMtxHandle;
+};
+
+struct ShaderResource {
+ ShaderResource()
+ : program(-1)
+ , vertexShader(-1)
+ , fragmentShader(-1)
+ {
+ };
+
+ ShaderResource(GLuint prog, GLuint vertex, GLuint fragment)
+ : program(prog)
+ , vertexShader(vertex)
+ , fragmentShader(fragment)
+ {
+ };
+
+ GLuint program;
+ GLuint vertexShader;
+ GLuint fragmentShader;
+};
+
+class ShaderProgram {
+public:
+ ShaderProgram();
+ void initGLResources();
+ void cleanupGLResources();
+ // Drawing
+ void setupDrawing(const IntRect& viewRect, const SkRect& visibleRect,
+ const IntRect& webViewRect, int titleBarHeight,
+ const IntRect& screenClip, float scale);
+ float zValue(const TransformationMatrix& drawMatrix, float w, float h);
+
+ // For drawQuad and drawLayerQuad, they can handle 3 cases for now:
+ // 1) textureTarget == GL_TEXTURE_2D
+ // Normal texture in GL_TEXTURE_2D target.
+ // 2) textureTarget == GL_TEXTURE_EXTERNAL_OES
+ // Surface texture in GL_TEXTURE_EXTERNAL_OES target.
+ // 3) textureId == 0
+ // No texture needed, just a pureColor quad.
+ void drawQuad(const DrawQuadData* data);
+ void drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
+ float* textureMatrix, SkRect& geometry, int textureId);
+ FloatRect rectInScreenCoord(const TransformationMatrix& drawMatrix,
+ const IntSize& size);
+ FloatRect rectInInvScreenCoord(const TransformationMatrix& drawMatrix,
+ const IntSize& size);
+
+ FloatRect rectInInvScreenCoord(const FloatRect& rect);
+ FloatRect rectInScreenCoord(const FloatRect& rect);
+ FloatRect convertScreenCoordToDocumentCoord(const FloatRect& rect);
+ FloatRect convertInvScreenCoordToScreenCoord(const FloatRect& rect);
+ FloatRect convertScreenCoordToInvScreenCoord(const FloatRect& rect);
+
+ void clip(const FloatRect& rect);
+ IntRect clippedRectWithViewport(const IntRect& rect, int margin = 0);
+ FloatRect documentViewport() { return m_documentViewport; }
+
+ float contrast() { return m_contrast; }
+ void setContrast(float c)
+ {
+ float contrast = c;
+ if (contrast < 0)
+ contrast = 0;
+ if (contrast > MAX_CONTRAST)
+ contrast = MAX_CONTRAST;
+ m_contrast = contrast;
+ }
+ void setWebViewMatrix(const float* matrix, bool alphaLayer);
+
+ // This delta is the delta from the layout pos and the current animation pos.
+ // Basically, in terms of layout, the webview is still in the original layout
+ // pos, as without animation. Such that the viewport and visible rect etc are
+ // still in that pos, too, except the clipping info.
+ // Our rendering approach is after applying all the matrix, webView is
+ // rendered as if it was at the original layout pos, but then offset the
+ // glViewport to match the animation.
+ void calculateAnimationDelta();
+ int getAnimationDeltaX() { return m_animationDelta.x(); }
+ int getAnimationDeltaY() { return m_animationDelta.y(); }
+ bool needsInit() { return m_needsInit; }
+
+private:
+ GLuint loadShader(GLenum shaderType, const char* pSource);
+ GLint createProgram(const char* vertexSource, const char* fragmentSource);
+ GLfloat* getProjectionMatrix(const DrawQuadData* data);
+ void setBlendingState(bool enableBlending);
+ void drawQuadInternal(ShaderType type, const GLfloat* matrix, int textureId,
+ float opacity, GLenum textureTarget, GLenum filter,
+ const Color& pureColor);
+ Color shaderColor(Color pureColor, float opacity);
+ ShaderType getTextureShaderType(GLenum textureTarget);
+ void resetBlending();
+
+ bool m_blendingEnabled;
+
+ TransformationMatrix m_projectionMatrix;
+ GLuint m_textureBuffer[1];
+
+ TransformationMatrix m_documentToScreenMatrix;
+ TransformationMatrix m_documentToInvScreenMatrix;
+ SkRect m_viewport;
+ IntRect m_viewRect;
+ FloatRect m_clipRect;
+ IntRect m_screenClip;
+ int m_titleBarHeight;
+ IntRect m_webViewRect;
+
+ FloatRect m_documentViewport;
+
+ float m_contrast;
+
+ bool m_alphaLayer;
+ TransformationMatrix m_webViewMatrix;
+ float m_currentScale;
+
+ // After the webViewTranform, we need to reposition the rect to match our viewport.
+ // Basically, the webViewTransformMatrix should apply on the screen resolution.
+ // So we start by doing the scale and translate to get each tile into screen coordinates.
+ // After applying the webViewTransformMatrix, b/c the way it currently set up
+ // for scroll and titlebar, we need to offset both of them.
+ // Finally, map everything back to (-1, 1) by using the m_projectionMatrix.
+ // TODO: Given that m_webViewMatrix contains most of the tranformation
+ // information, we should be able to get rid of some parameter we got from
+ // Java side and simplify our code.
+ TransformationMatrix m_repositionMatrix;
+ IntPoint m_animationDelta;
+
+ // Put all the uniform location (handle) info into an array, and group them
+ // by the shader's type, this can help to clean up the interface.
+ // TODO: use the type and data comparison to skip GL call if possible.
+ ShaderHandles m_handleArray[MaxShaderNumber];
+
+ // If there is any GL error happens such that the Shaders are not initialized
+ // successfully at the first time, then we need to init again when we draw.
+ bool m_needsInit;
+
+ // For transfer queue blitting, we need a special matrix map from (0,1) to
+ // (-1,1)
+ GLfloat m_transferProjMtx[16];
+
+ GLfloat m_tileProjMatrix[16];
+
+ Vector<ShaderResource> m_resources;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // ShaderProgram_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp
new file mode 100644
index 0000000..3ed3aad
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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 "Surface"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "Surface.h"
+
+#include "AndroidLog.h"
+#include "ClassTracker.h"
+#include "LayerAndroid.h"
+#include "GLWebViewState.h"
+#include "SkCanvas.h"
+#include "SurfaceBacking.h"
+#include "TilesManager.h"
+
+// Surfaces with an area larger than 2048*2048 should never be unclipped
+#define MAX_UNCLIPPED_AREA 4194304
+
+namespace WebCore {
+
+Surface::Surface()
+ : m_surfaceBacking(0)
+ , m_needsTexture(false)
+ , m_hasText(false)
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("Surface");
+#endif
+}
+
+Surface::~Surface()
+{
+ for (unsigned int i = 0; i < m_layers.size(); i++)
+ SkSafeUnref(m_layers[i]);
+ if (m_surfaceBacking)
+ SkSafeUnref(m_surfaceBacking);
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("Surface");
+#endif
+}
+
+bool Surface::tryUpdateSurface(Surface* oldSurface)
+{
+ if (!needsTexture() || !oldSurface->needsTexture())
+ return false;
+
+ // merge surfaces based on first layer ID
+ if (getFirstLayer()->uniqueId() != oldSurface->getFirstLayer()->uniqueId())
+ return false;
+
+ m_surfaceBacking = oldSurface->m_surfaceBacking;
+ SkSafeRef(m_surfaceBacking);
+
+ ALOGV("%p taking old SurfBack %p from surface %p, nt %d",
+ this, m_surfaceBacking, oldSurface, oldSurface->needsTexture());
+
+ if (!m_surfaceBacking) {
+ // no SurfBack to inval, so don't worry about it.
+ return true;
+ }
+
+ if (singleLayer() && oldSurface->singleLayer()) {
+ // both are single matching layers, simply apply inval
+ SkRegion* layerInval = getFirstLayer()->getInvalRegion();
+ m_surfaceBacking->markAsDirty(*layerInval);
+ } else {
+ SkRegion invalRegion;
+ bool fullInval = m_layers.size() != oldSurface->m_layers.size();
+ if (!fullInval) {
+ for (unsigned int i = 0; i < m_layers.size(); i++) {
+ if (m_layers[i]->uniqueId() != oldSurface->m_layers[i]->uniqueId()) {
+ // layer list has changed, fully invalidate
+ // TODO: partially invalidate based on layer size/position
+ fullInval = true;
+ break;
+ } else if (!m_layers[i]->getInvalRegion()->isEmpty()) {
+ // merge layer inval - translate the layer's inval region into surface coordinates
+ SkPoint pos = m_layers[i]->getPosition();
+ m_layers[i]->getInvalRegion()->translate(pos.fX, pos.fY);
+ invalRegion.op(*(m_layers[i]->getInvalRegion()), SkRegion::kUnion_Op);
+ break;
+ }
+ }
+ }
+
+ if (fullInval)
+ invalRegion.setRect(-1e8, -1e8, 2e8, 2e8);
+
+ m_surfaceBacking->markAsDirty(invalRegion);
+ }
+ return true;
+}
+
+void Surface::addLayer(LayerAndroid* layer, const TransformationMatrix& transform)
+{
+ m_layers.append(layer);
+ SkSafeRef(layer);
+
+ m_needsTexture |= layer->needsTexture();
+ m_hasText |= layer->hasText();
+
+ // calculate area size for comparison later
+ IntRect rect = layer->unclippedArea();
+ SkPoint pos = layer->getPosition();
+ rect.setLocation(IntPoint(pos.fX, pos.fY));
+
+ if (layer->needsTexture()) {
+ if (m_unclippedArea.isEmpty()) {
+ m_drawTransform = transform;
+ m_drawTransform.translate3d(-pos.fX, -pos.fY, 0);
+ m_unclippedArea = rect;
+ } else
+ m_unclippedArea.unite(rect);
+ ALOGV("Surf %p adding LA %p, size %d, %d %dx%d, now Surf size %d,%d %dx%d",
+ this, layer, rect.x(), rect.y(), rect.width(), rect.height(),
+ m_unclippedArea.x(), m_unclippedArea.y(),
+ m_unclippedArea.width(), m_unclippedArea.height());
+ }
+}
+
+IntRect Surface::visibleArea()
+{
+ if (singleLayer())
+ return getFirstLayer()->visibleArea();
+
+ IntRect rect = m_unclippedArea;
+
+ // clip with the viewport in documents coordinate
+ IntRect documentViewport(TilesManager::instance()->shader()->documentViewport());
+ rect.intersect(documentViewport);
+
+ // TODO: handle recursive layer clip
+
+ return rect;
+}
+
+IntRect Surface::unclippedArea()
+{
+ if (singleLayer())
+ return getFirstLayer()->unclippedArea();
+ return m_unclippedArea;
+}
+
+bool Surface::useAggressiveRendering()
+{
+ // When the background is semi-opaque, 0 < alpha < 255, we had to turn off
+ // low res to avoid artifacts from double drawing.
+ // TODO: avoid double drawing for low res tiles.
+ return isBase()
+ && (!m_background.alpha()
+ || !m_background.hasAlpha());
+}
+
+void Surface::prepareGL(bool layerTilesDisabled)
+{
+ bool tilesDisabled = layerTilesDisabled && !isBase();
+ if (!m_surfaceBacking) {
+ ALOGV("prepareGL on Surf %p, no SurfBack, needsTexture? %d",
+ this, m_surfaceBacking, needsTexture());
+
+ if (!needsTexture())
+ return;
+
+ m_surfaceBacking = new SurfaceBacking(isBase());
+ }
+
+ if (tilesDisabled) {
+ m_surfaceBacking->discardTextures();
+ } else {
+ bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors
+ IntRect prepareArea = computePrepareArea();
+ IntRect fullArea = unclippedArea();
+
+ ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers",
+ this, m_surfaceBacking, m_layers.size());
+
+ m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom,
+ prepareArea, fullArea,
+ this, useAggressiveRendering());
+ }
+}
+
+bool Surface::drawGL(bool layerTilesDisabled)
+{
+ bool tilesDisabled = layerTilesDisabled && !isBase();
+ if (!getFirstLayer()->visible())
+ return false;
+
+ if (!isBase()) {
+ // TODO: why are clipping regions wrong for base layer?
+ FloatRect drawClip = getFirstLayer()->drawClip();
+ FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip);
+ TilesManager::instance()->shader()->clip(clippingRect);
+ }
+
+ bool askRedraw = false;
+ if (m_surfaceBacking && !tilesDisabled) {
+ ALOGV("drawGL on Surf %p with SurfBack %p", this, m_surfaceBacking);
+
+ // TODO: why this visibleArea is different from visibleRect at zooming for base?
+ IntRect drawArea = visibleArea();
+ m_surfaceBacking->drawGL(drawArea, opacity(), drawTransform(),
+ useAggressiveRendering(), background());
+ }
+
+ // draw member layers (draws image textures, glextras)
+ for (unsigned int i = 0; i < m_layers.size(); i++)
+ askRedraw |= m_layers[i]->drawGL(tilesDisabled);
+
+ return askRedraw;
+}
+
+void Surface::swapTiles()
+{
+ if (!m_surfaceBacking)
+ return;
+
+ m_surfaceBacking->swapTiles();
+}
+
+bool Surface::isReady()
+{
+ if (!m_surfaceBacking)
+ return true;
+
+ return m_surfaceBacking->isReady();
+}
+
+IntRect Surface::computePrepareArea() {
+ IntRect area;
+
+ if (!getFirstLayer()->contentIsScrollable()
+ && !isBase()
+ && getFirstLayer()->state()->layersRenderingMode() == GLWebViewState::kAllTextures) {
+
+ area = unclippedArea();
+
+ double total = ((double) area.width()) * ((double) area.height());
+ if (total > MAX_UNCLIPPED_AREA)
+ area = visibleArea();
+ } else {
+ area = visibleArea();
+ }
+
+ return area;
+}
+
+void Surface::computeTexturesAmount(TexturesResult* result)
+{
+ if (!m_surfaceBacking || isBase())
+ return;
+
+ m_surfaceBacking->computeTexturesAmount(result, getFirstLayer());
+}
+
+bool Surface::isBase()
+{
+ // base layer surface
+ // - doesn't use layer tiles (disables blending, doesn't compute textures amount)
+ // - ignores clip rects
+ // - only prepares clippedArea
+ return getFirstLayer()->subclassType() == LayerAndroid::BaseLayer;
+}
+
+bool Surface::paint(Tile* tile, SkCanvas* canvas)
+{
+ if (singleLayer()) {
+ getFirstLayer()->contentDraw(canvas, Layer::UnmergedLayers);
+
+ // TODO: double buffer by disabling SurfaceCollection swaps and position
+ // updates until painting complete
+
+ // In single surface mode, draw layer content onto the base layer
+ if (isBase()
+ && getFirstLayer()->countChildren()
+ && getFirstLayer()->state()->layersRenderingMode() > GLWebViewState::kClippedTextures)
+ getFirstLayer()->getChild(0)->drawCanvas(canvas, true, Layer::FlattenedLayers);
+ } else {
+ SkAutoCanvasRestore acr(canvas, true);
+ SkMatrix matrix;
+ GLUtils::toSkMatrix(matrix, m_drawTransform);
+
+ SkMatrix inverse;
+ inverse.reset();
+ matrix.invert(&inverse);
+
+ SkMatrix canvasMatrix = canvas->getTotalMatrix();
+ inverse.postConcat(canvasMatrix);
+ canvas->setMatrix(inverse);
+
+ for (unsigned int i=0; i<m_layers.size(); i++)
+ m_layers[i]->drawCanvas(canvas, false, Layer::MergedLayers);
+ }
+ return true;
+}
+
+float Surface::opacity()
+{
+ if (singleLayer())
+ return getFirstLayer()->drawOpacity();
+ return 1.0;
+}
+
+Color* Surface::background()
+{
+ if (!isBase() || !m_background.isValid())
+ return 0;
+ return &m_background;
+}
+
+const TransformationMatrix* Surface::drawTransform()
+{
+ // single layer surfaces query the layer's draw transform, while multi-layer
+ // surfaces copy the draw transform once, during initialization
+ // TODO: support fixed multi-layer surfaces by querying the changing drawTransform
+ if (singleLayer())
+ return getFirstLayer()->drawTransform();
+
+ return &m_drawTransform;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.h b/Source/WebCore/platform/graphics/android/rendering/Surface.h
new file mode 100644
index 0000000..27c997e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/Surface.h
@@ -0,0 +1,115 @@
+/*
+ * 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 Surface_h
+#define Surface_h
+
+#include "Color.h"
+#include "IntRect.h"
+#include "TilePainter.h"
+#include "Vector.h"
+
+class SkCanvas;
+class SkRegion;
+
+namespace WebCore {
+
+class Tile;
+class SurfaceBacking;
+class LayerAndroid;
+class TexturesResult;
+
+class Surface : public TilePainter {
+public:
+ Surface();
+ virtual ~Surface();
+
+ bool tryUpdateSurface(Surface* oldSurface);
+
+ void addLayer(LayerAndroid* layer, const TransformationMatrix& transform);
+ void prepareGL(bool layerTilesDisabled);
+ bool drawGL(bool layerTilesDisabled);
+ void swapTiles();
+ bool isReady();
+
+ void computeTexturesAmount(TexturesResult* result);
+
+ LayerAndroid* getFirstLayer() { return m_layers[0]; }
+ bool needsTexture() { return m_needsTexture; }
+ bool hasText() { return m_hasText; }
+ bool isBase();
+ void setBackground(Color background) { m_background = background; }
+
+ // TilePainter methods
+ virtual bool paint(Tile* tile, SkCanvas* canvas);
+ virtual float opacity();
+ virtual Color* background();
+
+private:
+ IntRect computePrepareArea();
+ IntRect visibleArea();
+ IntRect unclippedArea();
+ bool singleLayer() { return m_layers.size() == 1; }
+ void updateBackground(const Color& background);
+ bool useAggressiveRendering();
+
+ const TransformationMatrix* drawTransform();
+ IntRect m_unclippedArea;
+ TransformationMatrix m_drawTransform;
+
+ SurfaceBacking* m_surfaceBacking;
+ bool m_needsTexture;
+ bool m_hasText;
+ Vector<LayerAndroid*> m_layers;
+
+ Color m_background;
+};
+
+class LayerMergeState {
+public:
+ LayerMergeState(Vector<Surface*>* const allGroups)
+ : surfaceList(allGroups)
+ , currentSurface(0)
+ , nonMergeNestedLevel(-1) // start at -1 to ignore first LayerAndroid's clipping
+ , depth(0)
+ {}
+
+ // vector storing all generated layer groups
+ Vector<Surface*>* const surfaceList;
+
+ // currently merging group. if cleared, no more layers may join
+ Surface* currentSurface;
+
+ // records depth within non-mergeable parents (clipping, fixed, scrolling)
+ // and disable merging therein.
+ int nonMergeNestedLevel;
+
+ // counts layer tree depth for debugging
+ int depth;
+};
+
+} // namespace WebCore
+
+#endif //#define Surface_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp
new file mode 100644
index 0000000..7c8f570
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2011, 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 "SurfaceBacking"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "SurfaceBacking.h"
+
+#include "AndroidLog.h"
+#include "Color.h"
+#include "GLWebViewState.h"
+#include "LayerAndroid.h"
+
+#define LOW_RES_PREFETCH_SCALE_MODIFIER 0.3f
+
+namespace WebCore {
+
+SurfaceBacking::SurfaceBacking(bool isBaseSurface)
+{
+ m_frontTexture = new TileGrid(isBaseSurface);
+ m_backTexture = new TileGrid(isBaseSurface);
+ m_scale = -1;
+ m_futureScale = -1;
+ m_zooming = false;
+}
+
+SurfaceBacking::~SurfaceBacking()
+{
+ delete m_frontTexture;
+ delete m_backTexture;
+}
+
+void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom,
+ const IntRect& prepareArea, const IntRect& unclippedArea,
+ TilePainter* painter, bool aggressiveRendering)
+{
+ float scale = state->scale();
+ if (scale > 1 && !allowZoom)
+ scale = 1;
+
+ if (m_scale == -1) {
+ m_scale = scale;
+ m_futureScale = scale;
+ }
+
+ if (m_futureScale != scale) {
+ m_futureScale = scale;
+ m_zoomUpdateTime = WTF::currentTime() + SurfaceBacking::s_zoomUpdateDelay;
+ m_zooming = true;
+ }
+
+ bool useExpandPrefetch = aggressiveRendering;
+ ALOGV("Prepare SurfBack %p, scale %.2f, m_scale %.2f, futScale: %.2f, zooming: %d, f %p, b %p",
+ this, scale, m_scale, m_futureScale, m_zooming,
+ m_frontTexture, m_backTexture);
+
+ if (!m_zooming) {
+ m_frontTexture->prepareGL(state, m_scale,
+ prepareArea, unclippedArea, painter, false, useExpandPrefetch);
+ if (aggressiveRendering) {
+ // prepare the back tiled texture to render content in low res
+ float lowResPrefetchScale = m_scale * LOW_RES_PREFETCH_SCALE_MODIFIER;
+ m_backTexture->prepareGL(state, lowResPrefetchScale,
+ prepareArea, unclippedArea, painter, true, useExpandPrefetch);
+ m_backTexture->swapTiles();
+ }
+ } else if (m_zoomUpdateTime < WTF::currentTime()) {
+ m_backTexture->prepareGL(state, m_futureScale,
+ prepareArea, unclippedArea, painter, false, useExpandPrefetch);
+ if (m_backTexture->isReady()) {
+ // zooming completed, swap the textures and new front tiles
+ swapTileGrids();
+
+ m_frontTexture->swapTiles();
+ m_backTexture->discardTextures();
+
+ m_scale = m_futureScale;
+ m_zooming = false;
+ }
+ }
+}
+
+void SurfaceBacking::drawGL(const IntRect& visibleArea, float opacity,
+ const TransformationMatrix* transform,
+ bool aggressiveRendering, const Color* background)
+{
+ // draw low res prefetch page, if needed
+ if (aggressiveRendering && !m_zooming && m_frontTexture->isMissingContent())
+ m_backTexture->drawGL(visibleArea, opacity, transform);
+
+ m_frontTexture->drawGL(visibleArea, opacity, transform, background);
+}
+
+void SurfaceBacking::markAsDirty(const SkRegion& dirtyArea)
+{
+ m_backTexture->markAsDirty(dirtyArea);
+ m_frontTexture->markAsDirty(dirtyArea);
+}
+
+void SurfaceBacking::swapTiles()
+{
+ m_backTexture->swapTiles();
+ m_frontTexture->swapTiles();
+}
+
+void SurfaceBacking::computeTexturesAmount(TexturesResult* result, LayerAndroid* layer)
+{
+ // TODO: shouldn't use layer, as this SB may paint multiple layers
+ if (!layer)
+ return;
+
+ IntRect unclippedArea = layer->unclippedArea();
+ IntRect clippedVisibleArea = layer->visibleArea();
+
+ // get two numbers here:
+ // - textures needed for a clipped area
+ // - textures needed for an un-clipped area
+ TileGrid* tiledTexture = m_zooming ? m_backTexture : m_frontTexture;
+ int nbTexturesUnclipped = tiledTexture->nbTextures(unclippedArea, m_scale);
+ int nbTexturesClipped = tiledTexture->nbTextures(clippedVisibleArea, m_scale);
+
+ // Set kFixedLayers level
+ if (layer->isPositionFixed())
+ result->fixed += nbTexturesClipped;
+
+ // Set kScrollableAndFixedLayers level
+ if (layer->contentIsScrollable()
+ || layer->isPositionFixed())
+ result->scrollable += nbTexturesClipped;
+
+ // Set kClippedTextures level
+ result->clipped += nbTexturesClipped;
+
+ // Set kAllTextures level
+ if (layer->contentIsScrollable())
+ result->full += nbTexturesClipped;
+ else
+ result->full += nbTexturesUnclipped;
+}
+
+void SurfaceBacking::swapTileGrids()
+{
+ TileGrid* temp = m_frontTexture;
+ m_frontTexture = m_backTexture;
+ m_backTexture = temp;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h
new file mode 100644
index 0000000..b04e462
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011, 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 SurfaceBacking_h
+#define SurfaceBacking_h
+
+#include "SkRefCnt.h"
+#include "TileGrid.h"
+
+namespace WebCore {
+
+class LayerAndroid;
+class TexturesResult;
+class TilePainter;
+
+class SurfaceBacking : public SkRefCnt {
+// TODO: investigate webkit threadsafe ref counting
+public:
+ SurfaceBacking(bool isBaseSurface);
+ ~SurfaceBacking();
+ void prepareGL(GLWebViewState* state, bool allowZoom,
+ const IntRect& prepareArea, const IntRect& unclippedArea,
+ TilePainter* painter, bool aggressiveRendering);
+ void swapTiles();
+ void drawGL(const IntRect& visibleArea, float opacity,
+ const TransformationMatrix* transform, bool aggressiveRendering,
+ const Color* background);
+ void markAsDirty(const SkRegion& dirtyArea);
+ void computeTexturesAmount(TexturesResult* result, LayerAndroid* layer);
+ void discardTextures()
+ {
+ m_frontTexture->discardTextures();
+ m_backTexture->discardTextures();
+ }
+ bool isReady()
+ {
+ return !m_zooming && m_frontTexture->isReady() && m_scale > 0;
+ }
+
+ int nbTextures(IntRect& area, float scale)
+ {
+ // TODO: consider the zooming case for the backTexture
+ if (!m_frontTexture)
+ return 0;
+ return m_frontTexture->nbTextures(area, scale);
+ }
+
+private:
+ void swapTileGrids();
+
+ // Delay before we schedule a new tile at the new scale factor
+ static const double s_zoomUpdateDelay = 0.2; // 200 ms
+
+ TileGrid* m_frontTexture;
+ TileGrid* m_backTexture;
+ float m_scale;
+ float m_futureScale;
+ double m_zoomUpdateTime;
+ bool m_zooming;
+};
+
+} // namespace WebCore
+
+#endif // SurfaceBacking_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp
new file mode 100644
index 0000000..0bbaf91
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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 "SurfaceCollection"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "SurfaceCollection.h"
+
+#include "AndroidLog.h"
+#include "BaseLayerAndroid.h"
+#include "ClassTracker.h"
+#include "GLWebViewState.h"
+#include "LayerAndroid.h"
+#include "Surface.h"
+#include "ScrollableLayerAndroid.h"
+#include "TilesManager.h"
+
+namespace WebCore {
+
+////////////////////////////////////////////////////////////////////////////////
+// TILED PAINTING / SURFACES //
+////////////////////////////////////////////////////////////////////////////////
+
+SurfaceCollection::SurfaceCollection(LayerAndroid* layer)
+ : m_compositedRoot(layer)
+{
+ // layer must be non-null.
+ SkSafeRef(m_compositedRoot);
+
+ // calculate draw transforms and z values
+ SkRect visibleRect = SkRect::MakeLTRB(0, 0, 1, 1);
+ m_compositedRoot->updateLayerPositions(visibleRect);
+ // TODO: updateGLPositionsAndScale?
+
+ // allocate surfaces for layers, merging where possible
+ ALOGV("new tree, allocating surfaces for tree %p", m_baseLayer);
+
+ LayerMergeState layerMergeState(&m_surfaces);
+ m_compositedRoot->assignSurfaces(&layerMergeState);
+
+ // set the layersurfaces' update count, to be drawn on painted tiles
+ unsigned int updateCount = TilesManager::instance()->incWebkitContentUpdates();
+ for (unsigned int i = 0; i < m_surfaces.size(); i++) {
+ m_surfaces[i]->setUpdateCount(updateCount);
+ if (m_surfaces[i]->isBase())
+ m_surfaces[i]->setBackground(getBackground());
+ }
+
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("SurfaceCollection");
+#endif
+}
+
+SurfaceCollection::~SurfaceCollection()
+{
+ SkSafeUnref(m_compositedRoot);
+ for (unsigned int i = 0; i < m_surfaces.size(); i++)
+ SkSafeUnref(m_surfaces[i]);
+ m_surfaces.clear();
+
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("SurfaceCollection");
+#endif
+}
+
+void SurfaceCollection::prepareGL(const SkRect& visibleRect)
+{
+ updateLayerPositions(visibleRect);
+ bool layerTilesDisabled = m_compositedRoot->state()->layersRenderingMode()
+ > GLWebViewState::kClippedTextures;
+ for (unsigned int i = 0; i < m_surfaces.size(); i++)
+ m_surfaces[i]->prepareGL(layerTilesDisabled);
+}
+
+bool SurfaceCollection::drawGL(const SkRect& visibleRect)
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->show();
+#endif
+
+ bool needsRedraw = false;
+ updateLayerPositions(visibleRect);
+ bool layerTilesDisabled = m_compositedRoot->state()->layersRenderingMode()
+ > GLWebViewState::kClippedTextures;
+ for (unsigned int i = 0; i < m_surfaces.size(); i++)
+ needsRedraw |= m_surfaces[i]->drawGL(layerTilesDisabled);
+
+ return needsRedraw;
+}
+
+Color SurfaceCollection::getBackground()
+{
+ return static_cast<BaseLayerAndroid*>(m_compositedRoot)->getBackgroundColor();
+}
+
+void SurfaceCollection::swapTiles()
+{
+ for (unsigned int i = 0; i < m_surfaces.size(); i++)
+ m_surfaces[i]->swapTiles();
+}
+
+bool SurfaceCollection::isReady()
+{
+ // Override layer readiness check for single surface mode
+ if (m_compositedRoot->state()->layersRenderingMode() > GLWebViewState::kClippedTextures) {
+ // TODO: single surface mode should be properly double buffered
+ return true;
+ }
+
+ for (unsigned int i = 0; i < m_surfaces.size(); i++) {
+ if (!m_surfaces[i]->isReady()) {
+ ALOGV("layer surface %p isn't ready", m_surfaces[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+void SurfaceCollection::computeTexturesAmount(TexturesResult* result)
+{
+ for (unsigned int i = 0; i < m_surfaces.size(); i++)
+ m_surfaces[i]->computeTexturesAmount(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RECURSIVE ANIMATION / INVALS / LAYERS //
+////////////////////////////////////////////////////////////////////////////////
+
+void SurfaceCollection::setIsPainting(SurfaceCollection* drawingSurface)
+{
+ if (!drawingSurface)
+ return;
+
+ for (unsigned int i = 0; i < m_surfaces.size(); i++) {
+ Surface* newSurface = m_surfaces[i];
+ if (!newSurface->needsTexture())
+ continue;
+
+ for (unsigned int j = 0; j < drawingSurface->m_surfaces.size(); j++) {
+ Surface* oldSurface = drawingSurface->m_surfaces[j];
+ if (newSurface->tryUpdateSurface(oldSurface))
+ break;
+ }
+ }
+}
+
+void SurfaceCollection::setIsDrawing()
+{
+ m_compositedRoot->initAnimations();
+}
+
+void SurfaceCollection::mergeInvalsInto(SurfaceCollection* replacementSurface)
+{
+ m_compositedRoot->mergeInvalsInto(replacementSurface->m_compositedRoot);
+}
+
+void SurfaceCollection::evaluateAnimations(double currentTime)
+{
+ m_compositedRoot->evaluateAnimations(currentTime);
+}
+
+bool SurfaceCollection::hasCompositedLayers()
+{
+ return m_compositedRoot->countChildren();
+}
+
+bool SurfaceCollection::hasCompositedAnimations()
+{
+ return m_compositedRoot->hasAnimations();
+}
+
+void SurfaceCollection::updateScrollableLayer(int layerId, int x, int y)
+{
+ LayerAndroid* layer = m_compositedRoot->findById(layerId);
+ if (layer && layer->contentIsScrollable())
+ static_cast<ScrollableLayerAndroid*>(layer)->scrollTo(x, y);
+}
+
+void SurfaceCollection::updateLayerPositions(const SkRect& visibleRect)
+{
+ TransformationMatrix ident;
+ m_compositedRoot->updateLayerPositions(visibleRect);
+ FloatRect clip(0, 0, 1e10, 1e10);
+ m_compositedRoot->updateGLPositionsAndScale(
+ ident, clip, 1, m_compositedRoot->state()->scale());
+
+#ifdef DEBUG
+ m_compositedRoot->showLayer(0);
+ ALOGV("We have %d layers, %d textured",
+ m_compositedRoot->nbLayers(),
+ m_compositedRoot->nbTexturedLayers());
+#endif
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h
new file mode 100644
index 0000000..6450c9c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollection.h
@@ -0,0 +1,76 @@
+/*
+ * 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 SurfaceCollection_h
+#define SurfaceCollection_h
+
+#include "Color.h"
+#include "SkRect.h"
+#include "SkRefCnt.h"
+
+#include <wtf/Vector.h>
+
+class SkCanvas;
+class SkRegion;
+
+namespace WebCore {
+
+class LayerAndroid;
+class Surface;
+class TexturesResult;
+
+class SurfaceCollection : public SkRefCnt {
+// TODO: investigate webkit threadsafe ref counting
+public:
+ SurfaceCollection(LayerAndroid* compositedRoot);
+ virtual ~SurfaceCollection();
+
+ // Tiled painting methods (executed on groups)
+ void prepareGL(const SkRect& visibleRect);
+ bool drawGL(const SkRect& visibleRect);
+ Color getBackground();
+ void swapTiles();
+ bool isReady();
+ void computeTexturesAmount(TexturesResult* result);
+
+ // Recursive tree methods (animations, invals, etc)
+ void setIsPainting(SurfaceCollection* drawingSurfaceCollection);
+ void setIsDrawing();
+ void mergeInvalsInto(SurfaceCollection* replacementSurfaceCollection);
+ void evaluateAnimations(double currentTime);
+
+ bool hasCompositedLayers();
+ bool hasCompositedAnimations();
+ void updateScrollableLayer(int layerId, int x, int y);
+
+private:
+ void updateLayerPositions(const SkRect& visibleRect);
+ LayerAndroid* m_compositedRoot;
+ WTF::Vector<Surface*> m_surfaces;
+};
+
+} // namespace WebCore
+
+#endif //#define SurfaceCollection_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp
new file mode 100644
index 0000000..8fb4d4b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2011, 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 "SurfaceCollectionManager"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "SurfaceCollectionManager.h"
+
+#include "AndroidLog.h"
+#include "private/hwui/DrawGlInfo.h"
+#include "TilesManager.h"
+#include "SurfaceCollection.h"
+
+namespace WebCore {
+
+SurfaceCollectionManager::SurfaceCollectionManager(GLWebViewState* state)
+ : m_state(state)
+ , m_drawingCollection(0)
+ , m_paintingCollection(0)
+ , m_queuedCollection(0)
+ , m_fastSwapMode(false)
+{
+}
+
+SurfaceCollectionManager::~SurfaceCollectionManager()
+{
+ clearCollections();
+}
+
+// the painting collection has finished painting:
+// discard the drawing collection
+// swap the painting collection in place of the drawing collection
+// and start painting the queued collection
+void SurfaceCollectionManager::swap()
+{
+ // swap can't be called unless painting just finished
+ ASSERT(m_paintingCollection);
+
+ android::Mutex::Autolock lock(m_paintSwapLock);
+
+ ALOGV("SWAPPING, D %p, P %p, Q %p",
+ m_drawingCollection, m_paintingCollection, m_queuedCollection);
+
+ // if we have a drawing collection, discard it since the painting collection is done
+ if (m_drawingCollection) {
+ ALOGV("destroying drawing collection %p", m_drawingCollection);
+ SkSafeUnref(m_drawingCollection);
+ }
+
+ // painting collection becomes the drawing collection
+ ALOGV("drawing collection %p", m_paintingCollection);
+ m_paintingCollection->setIsDrawing(); // initialize animations
+
+ if (m_queuedCollection) {
+ // start painting with the queued collection
+ ALOGV("now painting collection %p", m_queuedCollection);
+ m_queuedCollection->setIsPainting(m_paintingCollection);
+ }
+ m_drawingCollection = m_paintingCollection;
+ m_paintingCollection = m_queuedCollection;
+ m_queuedCollection = 0;
+
+ ALOGV("SWAPPING COMPLETE, D %p, P %p, Q %p",
+ m_drawingCollection, m_paintingCollection, m_queuedCollection);
+}
+
+// clear all of the content in the three collections held by the collection manager
+void SurfaceCollectionManager::clearCollections()
+{
+ ALOGV("SurfaceCollectionManager %p removing PS from state %p", this, m_state);
+
+ SkSafeUnref(m_drawingCollection);
+ m_drawingCollection = 0;
+ SkSafeUnref(m_paintingCollection);
+ m_paintingCollection = 0;
+ SkSafeUnref(m_queuedCollection);
+ m_queuedCollection = 0;
+}
+
+// a new layer collection has arrived, queue it if we're painting something already,
+// or start painting it if we aren't. Returns true if the manager has two collections
+// already queued.
+bool SurfaceCollectionManager::updateWithSurfaceCollection(SurfaceCollection* newCollection,
+ bool brandNew)
+{
+ // can't have a queued collection unless have a painting collection too
+ ASSERT(m_paintingCollection || !m_queuedCollection);
+
+ android::Mutex::Autolock lock(m_paintSwapLock);
+
+ if (!newCollection || brandNew) {
+ clearCollections();
+ if (brandNew) {
+ m_paintingCollection = newCollection;
+ m_paintingCollection->setIsPainting(m_drawingCollection);
+ }
+ return false;
+ }
+
+ ALOGV("updateWithSurfaceCollection - %p, has children %d, has animations %d",
+ newCollection, newCollection->hasCompositedLayers(),
+ newCollection->hasCompositedAnimations());
+
+ if (m_queuedCollection || m_paintingCollection) {
+ // currently painting, so defer this new collection
+ if (m_queuedCollection) {
+ // already have a queued collection, copy over invals so the regions are
+ // eventually repainted and let the old queued collection be discarded
+ m_queuedCollection->mergeInvalsInto(newCollection);
+
+ if (!TilesManager::instance()->useDoubleBuffering()) {
+ // not double buffering, count discarded collection/webkit paint as an update
+ TilesManager::instance()->incContentUpdates();
+ }
+
+ ALOGV("DISCARDING collection - %p, has children %d, has animations %d",
+ newCollection, newCollection->hasCompositedLayers(),
+ newCollection->hasCompositedAnimations());
+ }
+ SkSafeUnref(m_queuedCollection);
+ m_queuedCollection = newCollection;
+ } else {
+ // don't have painting collection, paint this one!
+ m_paintingCollection = newCollection;
+ m_paintingCollection->setIsPainting(m_drawingCollection);
+ }
+ return m_drawingCollection && TilesManager::instance()->useDoubleBuffering();
+}
+
+void SurfaceCollectionManager::updateScrollableLayer(int layerId, int x, int y)
+{
+ if (m_queuedCollection)
+ m_queuedCollection->updateScrollableLayer(layerId, x, y);
+ if (m_paintingCollection)
+ m_paintingCollection->updateScrollableLayer(layerId, x, y);
+ if (m_drawingCollection)
+ m_drawingCollection->updateScrollableLayer(layerId, x, y);
+}
+
+int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect,
+ SkRect& visibleRect, float scale,
+ bool enterFastSwapMode,
+ bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr,
+ TexturesResult* texturesResultPtr, bool shouldDraw)
+{
+ m_fastSwapMode |= enterFastSwapMode;
+
+ ALOGV("drawGL, D %p, P %p, Q %p, fastSwap %d shouldDraw %d",
+ m_drawingCollection, m_paintingCollection,
+ m_queuedCollection, m_fastSwapMode, shouldDraw);
+
+ bool didCollectionSwap = false;
+ if (m_paintingCollection) {
+ ALOGV("preparing painting collection %p", m_paintingCollection);
+
+ m_paintingCollection->evaluateAnimations(currentTime);
+
+ m_paintingCollection->prepareGL(visibleRect);
+ m_paintingCollection->computeTexturesAmount(texturesResultPtr);
+
+ if (!TilesManager::instance()->useDoubleBuffering() || m_paintingCollection->isReady()) {
+ ALOGV("have painting collection %p ready, swapping!", m_paintingCollection);
+ didCollectionSwap = true;
+ TilesManager::instance()->incContentUpdates();
+ if (collectionsSwappedPtr)
+ *collectionsSwappedPtr = true;
+ if (newCollectionHasAnimPtr)
+ *newCollectionHasAnimPtr = m_paintingCollection->hasCompositedAnimations();
+ swap();
+ }
+ } else if (m_drawingCollection) {
+ ALOGV("preparing drawing collection %p", m_drawingCollection);
+ m_drawingCollection->prepareGL(visibleRect);
+ m_drawingCollection->computeTexturesAmount(texturesResultPtr);
+ }
+
+ // ask for kStatusInvoke while painting, kStatusDraw if we have content to be redrawn next frame
+ // returning 0 indicates all painting complete, no framework inval needed.
+ int returnFlags = 0;
+
+ if (m_paintingCollection)
+ returnFlags |= uirenderer::DrawGlInfo::kStatusInvoke;
+
+ if (!shouldDraw) {
+ if (didCollectionSwap) {
+ m_drawingCollection->swapTiles();
+ returnFlags |= uirenderer::DrawGlInfo::kStatusDraw;
+ }
+
+ return returnFlags;
+ }
+
+ // ===========================================================================
+ // Don't have a drawing collection, draw white background
+ Color background = Color::white;
+ if (m_drawingCollection) {
+ bool drawingReady = didCollectionSwap || m_drawingCollection->isReady();
+
+ // call the page swap callback if registration happened without more collections enqueued
+ if (collectionsSwappedPtr && drawingReady && !m_paintingCollection)
+ *collectionsSwappedPtr = true;
+
+ if (didCollectionSwap || m_fastSwapMode || (drawingReady && !m_paintingCollection))
+ m_drawingCollection->swapTiles();
+
+ if (drawingReady) {
+ // exit fast swap mode, as content is up to date
+ m_fastSwapMode = false;
+ } else {
+ // drawing isn't ready, must redraw
+ returnFlags |= uirenderer::DrawGlInfo::kStatusInvoke;
+ }
+
+ m_drawingCollection->evaluateAnimations(currentTime);
+
+ ALOGV("drawing collection %p", m_drawingCollection);
+ background = m_drawingCollection->getBackground();
+ } else if (m_paintingCollection) {
+ // Use paintingCollection background color while tiles are not done painting.
+ background = m_paintingCollection->getBackground();
+ }
+
+ // Start doing the actual GL drawing.
+ ALOGV("background is %x", background.rgb());
+ // If background is opaque, we can safely and efficiently clear it here.
+ // Otherwise, we have to calculate all the missing tiles and blend the background.
+ GLUtils::clearBackgroundIfOpaque(&background);
+ if (m_drawingCollection && m_drawingCollection->drawGL(visibleRect))
+ returnFlags |= uirenderer::DrawGlInfo::kStatusDraw;
+
+ ALOGV("returnFlags %d, m_paintingCollection %d ", returnFlags, m_paintingCollection);
+ return returnFlags;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h
new file mode 100644
index 0000000..cc98899
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011, 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 SurfaceCollectionManager_h
+#define SurfaceCollectionManager_h
+
+#include "TestExport.h"
+#include <utils/threads.h>
+
+class SkRect;
+class SkCanvas;
+
+namespace WebCore {
+
+class GLWebViewState;
+class IntRect;
+class TexturesResult;
+class SurfaceCollection;
+
+class TEST_EXPORT SurfaceCollectionManager {
+public:
+ SurfaceCollectionManager(GLWebViewState* state);
+
+ ~SurfaceCollectionManager();
+
+ bool updateWithSurfaceCollection(SurfaceCollection* collection, bool brandNew);
+
+ void updateScrollableLayer(int layerId, int x, int y);
+
+ int drawGL(double currentTime, IntRect& viewRect,
+ SkRect& visibleRect, float scale,
+ bool enterFastSwapMode, bool* collectionsSwappedPtr, bool* newCollectionHasAnimPtr,
+ TexturesResult* texturesResultPtr, bool shouldDraw);
+
+private:
+ void swap();
+ void clearCollections();
+
+ android::Mutex m_paintSwapLock;
+
+ GLWebViewState* m_state;
+
+ SurfaceCollection* m_drawingCollection;
+ SurfaceCollection* m_paintingCollection;
+ SurfaceCollection* m_queuedCollection;
+
+ bool m_fastSwapMode;
+};
+
+} // namespace WebCore
+
+#endif //#define SurfaceCollectionManager_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TextureInfo.cpp b/Source/WebCore/platform/graphics/android/rendering/TextureInfo.cpp
new file mode 100644
index 0000000..f5c8b02
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TextureInfo.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011, 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.
+ */
+
+#include "config.h"
+#include "TextureInfo.h"
+
+#include "WebCoreJni.h"
+
+#include <JNIUtility.h>
+#include <android/native_window.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+namespace WebCore {
+
+TextureInfo::TextureInfo()
+{
+ m_textureId = GL_NO_TEXTURE;
+ m_width = 0;
+ m_height = 0;
+ m_internalFormat = 0;
+}
+
+bool TextureInfo::equalsAttributes(const TextureInfo* otherTexture)
+{
+ return otherTexture->m_width == m_width
+ && otherTexture->m_height == m_height
+ && otherTexture->m_internalFormat == m_internalFormat;
+}
+
+void TextureInfo::copyAttributes(const TextureInfo* sourceTexture)
+{
+ m_width = sourceTexture->m_width;
+ m_height = sourceTexture->m_height;
+ m_internalFormat = sourceTexture->m_internalFormat;
+}
+
+bool TextureInfo::operator==(const TextureInfo& otherTexture)
+{
+ return otherTexture.m_textureId == m_textureId && equalsAttributes(&otherTexture);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/TextureInfo.h b/Source/WebCore/platform/graphics/android/rendering/TextureInfo.h
new file mode 100644
index 0000000..7d182c3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TextureInfo.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011, 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 TextureInfo_h
+#define TextureInfo_h
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <jni.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+using android::sp;
+
+namespace android {
+class SurfaceTexture;
+}
+
+namespace WebCore {
+
+static const GLuint GL_NO_TEXTURE = 0;
+/**
+ * TextureInfo is a class that stores both the texture and metadata about the
+ * texture.
+ */
+
+class TextureInfo {
+public:
+ TextureInfo();
+
+ bool equalsAttributes(const TextureInfo* otherTexture);
+ void copyAttributes(const TextureInfo* sourceTexture);
+
+ bool operator==(const TextureInfo& otherTexture);
+
+ GLuint m_textureId;
+ int32_t m_width;
+ int32_t m_height;
+ GLenum m_internalFormat;
+};
+
+} // namespace WebCore
+
+#endif // TextureInfo_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TextureOwner.h b/Source/WebCore/platform/graphics/android/rendering/TextureOwner.h
new file mode 100644
index 0000000..b12d8b7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TextureOwner.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010, 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 TextureOwner_h
+#define TextureOwner_h
+
+class SkCanvas;
+class Layer;
+
+namespace WebCore {
+
+class TileTexture;
+class GLWebViewState;
+
+class TextureOwner {
+public:
+ virtual ~TextureOwner() { }
+ virtual bool removeTexture(TileTexture* texture) = 0;
+ virtual bool isRepaintPending() = 0;
+ virtual unsigned long long drawCount() = 0;
+};
+
+}
+
+#endif // TextureOwner_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp
new file mode 100644
index 0000000..f884e52
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2010, 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 "TexturesGenerator"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TexturesGenerator.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "GLUtils.h"
+#include "PaintTileOperation.h"
+#include "TilesManager.h"
+#include "TransferQueue.h"
+
+namespace WebCore {
+
+void TexturesGenerator::scheduleOperation(QueuedOperation* operation)
+{
+ {
+ android::Mutex::Autolock lock(mRequestedOperationsLock);
+ mRequestedOperations.append(operation);
+ }
+ mRequestedOperationsCond.signal();
+}
+
+void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter, bool waitForRunning)
+{
+ if (!filter)
+ return;
+
+ android::Mutex::Autolock lock(mRequestedOperationsLock);
+ for (unsigned int i = 0; i < mRequestedOperations.size();) {
+ QueuedOperation* operation = mRequestedOperations[i];
+ if (filter->check(operation)) {
+ mRequestedOperations.remove(i);
+ delete operation;
+ } else {
+ i++;
+ }
+ }
+
+ if (waitForRunning && m_currentOperation) {
+ QueuedOperation* operation = m_currentOperation;
+
+ if (operation && filter->check(operation)) {
+ m_waitForCompletion = true;
+ // The reason we are signaling the transferQueue is :
+ // TransferQueue may be waiting a slot to work on, but now UI
+ // thread is waiting for Tex Gen thread to finish first before the
+ // UI thread can free a slot for the transferQueue.
+ // Therefore, it could be a deadlock.
+ // The solution is use this as a flag to tell Tex Gen thread that
+ // UI thread is waiting now, Tex Gen thread should not wait for the
+ // queue any more.
+ m_tilesManager->transferQueue()->interruptTransferQueue(true);
+ }
+
+ delete filter;
+
+ // 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.
+ while (m_waitForCompletion)
+ mRequestedOperationsCond.wait(mRequestedOperationsLock);
+ } else {
+ delete filter;
+ }
+}
+
+status_t TexturesGenerator::readyToRun()
+{
+ ALOGV("Thread ready to run");
+ return NO_ERROR;
+}
+
+// Must be called from within a lock!
+QueuedOperation* TexturesGenerator::popNext()
+{
+ // Priority can change between when it was added and now
+ // Hence why the entire queue is rescanned
+ QueuedOperation* current = mRequestedOperations.last();
+ int currentPriority = current->priority();
+ if (currentPriority < 0) {
+ mRequestedOperations.removeLast();
+ return current;
+ }
+ int currentIndex = mRequestedOperations.size() - 1;
+ // Scan from the back to make removing faster (less items to copy)
+ for (int i = mRequestedOperations.size() - 2; i >= 0; i--) {
+ QueuedOperation *next = mRequestedOperations[i];
+ int nextPriority = next->priority();
+ if (nextPriority < 0) {
+ // Found a very high priority item, go ahead and just handle it now
+ mRequestedOperations.remove(i);
+ return next;
+ }
+ // pick items preferrably by priority, or if equal, by order of
+ // insertion (as we add items at the back of the queue)
+ if (nextPriority <= currentPriority) {
+ current = next;
+ currentPriority = nextPriority;
+ currentIndex = i;
+ }
+ }
+ mRequestedOperations.remove(currentIndex);
+ return current;
+}
+
+bool TexturesGenerator::threadLoop()
+{
+ // Check if we have any pending operations.
+ mRequestedOperationsLock.lock();
+ while (!mRequestedOperations.size())
+ mRequestedOperationsCond.wait(mRequestedOperationsLock);
+
+ ALOGV("threadLoop, got signal");
+ mRequestedOperationsLock.unlock();
+
+ m_currentOperation = 0;
+ bool stop = false;
+ while (!stop) {
+ mRequestedOperationsLock.lock();
+ ALOGV("threadLoop, %d operations in the queue", mRequestedOperations.size());
+ if (mRequestedOperations.size())
+ m_currentOperation = popNext();
+ mRequestedOperationsLock.unlock();
+
+ if (m_currentOperation) {
+ ALOGV("threadLoop, painting the request with priority %d",
+ m_currentOperation->priority());
+ m_currentOperation->run();
+ }
+
+ QueuedOperation* oldOperation = m_currentOperation;
+ mRequestedOperationsLock.lock();
+ if (m_currentOperation)
+ m_currentOperation = 0;
+ if (!mRequestedOperations.size())
+ stop = true;
+ if (m_waitForCompletion) {
+ m_waitForCompletion = false;
+ m_tilesManager->transferQueue()->interruptTransferQueue(false);
+ mRequestedOperationsCond.signal();
+ }
+ mRequestedOperationsLock.unlock();
+ if (oldOperation)
+ delete oldOperation; // delete outside lock
+ }
+ ALOGV("threadLoop empty");
+
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h
new file mode 100644
index 0000000..08f69ae
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010, 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 TexturesGenerator_h
+#define TexturesGenerator_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "QueuedOperation.h"
+#include "TilePainter.h"
+#include <wtf/Vector.h>
+
+#include <utils/threads.h>
+
+namespace WebCore {
+
+using namespace android;
+
+class TilesManager;
+
+class TexturesGenerator : public Thread {
+public:
+ TexturesGenerator(TilesManager* instance) : Thread(false)
+ , m_waitForCompletion(false)
+ , m_currentOperation(0)
+ , m_tilesManager(instance) { }
+ virtual ~TexturesGenerator() { }
+ virtual status_t readyToRun();
+
+ void removeOperationsForFilter(OperationFilter* filter, bool waitForRunning = true);
+
+ void scheduleOperation(QueuedOperation* operation);
+
+private:
+ QueuedOperation* popNext();
+ virtual bool threadLoop();
+ WTF::Vector<QueuedOperation*> mRequestedOperations;
+ android::Mutex mRequestedOperationsLock;
+ android::Condition mRequestedOperationsCond;
+ bool m_waitForCompletion;
+ QueuedOperation* m_currentOperation;
+ TilesManager* m_tilesManager;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // TexturesGenerator_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp
new file mode 100644
index 0000000..35fded1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2010, 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 "Tile"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "Tile.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "GLUtils.h"
+#include "RasterRenderer.h"
+#include "TextureInfo.h"
+#include "TileTexture.h"
+#include "TilesManager.h"
+
+// If the dirty portion of a tile exceeds this ratio, fully repaint.
+// Lower values give fewer partial repaints, thus fewer front-to-back
+// texture copies (cost will vary by device). It's a tradeoff between
+// the rasterization cost and the FBO texture recopy cost when using
+// GPU for the transfer queue.
+#define MAX_INVAL_AREA 0.6
+
+namespace WebCore {
+
+Tile::Tile(bool isLayerTile)
+ : m_x(-1)
+ , m_y(-1)
+ , m_frontTexture(0)
+ , m_backTexture(0)
+ , m_scale(1)
+ , m_dirty(true)
+ , m_repaintPending(false)
+ , m_fullRepaint(true)
+ , m_isLayerTile(isLayerTile)
+ , m_drawCount(0)
+ , m_state(Unpainted)
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("Tile");
+#endif
+ m_renderer = BaseRenderer::createRenderer();
+}
+
+Tile::~Tile()
+{
+ if (m_backTexture)
+ m_backTexture->release(this);
+ if (m_frontTexture)
+ m_frontTexture->release(this);
+
+ delete m_renderer;
+
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("Tile");
+#endif
+}
+
+// All the following functions must be called from the main GL thread.
+
+void Tile::setContents(int x, int y, float scale, bool isExpandedPrefetchTile)
+{
+ // TODO: investigate whether below check/discard is necessary
+ if ((m_x != x)
+ || (m_y != y)
+ || (m_scale != scale)) {
+ // neither texture is relevant
+ discardTextures();
+ }
+
+ android::AutoMutex lock(m_atomicSync);
+ m_x = x;
+ m_y = y;
+ m_scale = scale;
+ m_drawCount = TilesManager::instance()->getDrawGLCount();
+ if (isExpandedPrefetchTile)
+ m_drawCount--; // deprioritize expanded painting region
+}
+
+void Tile::reserveTexture()
+{
+ TileTexture* texture = TilesManager::instance()->getAvailableTexture(this);
+
+ android::AutoMutex lock(m_atomicSync);
+ if (texture && m_backTexture != texture) {
+ ALOGV("tile %p reserving texture %p, back was %p (front %p)",
+ this, texture, m_backTexture, m_frontTexture);
+ m_state = Unpainted;
+ m_backTexture = texture;
+ }
+
+ if (m_state == UpToDate) {
+ ALOGV("moving tile %p to unpainted, since it reserved while up to date", this);
+ m_dirty = true;
+ m_state = Unpainted;
+ }
+}
+
+bool Tile::removeTexture(TileTexture* texture)
+{
+ ALOGV("%p removeTexture %p, back %p front %p",
+ this, texture, m_backTexture, m_frontTexture);
+ // We update atomically, so paintBitmap() can see the correct value
+ android::AutoMutex lock(m_atomicSync);
+ if (m_frontTexture == texture) {
+ if (m_state == UpToDate) {
+ ALOGV("front texture removed, state was UpToDate, now becoming unpainted, bt is %p", m_backTexture);
+ m_state = Unpainted;
+ }
+
+ m_frontTexture = 0;
+ }
+ if (m_backTexture == texture) {
+ m_state = Unpainted;
+ m_backTexture = 0;
+ }
+
+ // mark dirty regardless of which texture was taken - the back texture may
+ // have been ready to swap
+ m_dirty = true;
+
+ return true;
+}
+
+void Tile::markAsDirty(const SkRegion& dirtyArea)
+{
+ if (dirtyArea.isEmpty())
+ return;
+ android::AutoMutex lock(m_atomicSync);
+ m_dirtyArea.op(dirtyArea, SkRegion::kUnion_Op);
+
+ // Check if we actually intersect with the area
+ bool intersect = false;
+ SkRegion::Iterator cliperator(dirtyArea);
+ SkRect realTileRect;
+ SkRect dirtyRect;
+ while (!cliperator.done()) {
+ dirtyRect.set(cliperator.rect());
+ if (intersectWithRect(m_x, m_y, TilesManager::tileWidth(), TilesManager::tileHeight(),
+ m_scale, dirtyRect, realTileRect)) {
+ intersect = true;
+ break;
+ }
+ cliperator.next();
+ }
+
+ if (!intersect)
+ return;
+
+ m_dirty = true;
+ if (m_state == UpToDate) {
+ // We only mark a tile as unpainted in 'markAsDirty' if its status is
+ // UpToDate: marking dirty means we need to repaint, but don't stop the
+ // current paint
+ m_state = Unpainted;
+ } else if (m_state != Unpainted) {
+ // TODO: fix it so that they can paint while deferring the markAsDirty
+ // call (or block updates)
+ ALOGV("Warning: tried to mark tile %p at %d, %d islayertile %d as dirty, state %d",
+ this, m_x, m_y, isLayerTile(), m_state);
+
+ // prefetch tiles can be marked dirty while in the process of painting,
+ // due to not using an update lock. force them to fail validate step.
+ m_state = Unpainted;
+ }
+}
+
+bool Tile::isDirty()
+{
+ android::AutoMutex lock(m_atomicSync);
+ return m_dirty;
+}
+
+bool Tile::isRepaintPending()
+{
+ android::AutoMutex lock(m_atomicSync);
+ return m_repaintPending;
+}
+
+void Tile::setRepaintPending(bool pending)
+{
+ android::AutoMutex lock(m_atomicSync);
+ m_repaintPending = pending;
+}
+
+bool Tile::drawGL(float opacity, const SkRect& rect, float scale,
+ const TransformationMatrix* transform,
+ bool forceBlending)
+{
+ if (m_x < 0 || m_y < 0 || m_scale != scale)
+ return false;
+
+ // No need to mutex protect reads of m_backTexture as it is only written to by
+ // the consumer thread.
+ if (!m_frontTexture)
+ return false;
+
+ m_frontTexture->drawGL(isLayerTile(), rect, opacity, transform, forceBlending);
+ return true;
+}
+
+bool Tile::isTileReady()
+{
+ // Return true if the tile's most recently drawn texture is up to date
+ android::AutoMutex lock(m_atomicSync);
+ TileTexture * texture = (m_state == ReadyToSwap) ? m_backTexture : m_frontTexture;
+
+ if (!texture)
+ return false;
+
+ if (texture->owner() != this)
+ return false;
+
+ if (m_dirty)
+ return false;
+
+ if (m_state != ReadyToSwap && m_state != UpToDate)
+ return false;
+
+ return true;
+}
+
+bool Tile::intersectWithRect(int x, int y, int tileWidth, int tileHeight,
+ float scale, const SkRect& dirtyRect,
+ SkRect& realTileRect)
+{
+ // compute the rect to corresponds to pixels
+ realTileRect.fLeft = x * tileWidth;
+ realTileRect.fTop = y * tileHeight;
+ realTileRect.fRight = realTileRect.fLeft + tileWidth;
+ realTileRect.fBottom = realTileRect.fTop + tileHeight;
+
+ // scale the dirtyRect for intersect computation.
+ SkRect realDirtyRect = SkRect::MakeWH(dirtyRect.width() * scale,
+ dirtyRect.height() * scale);
+ realDirtyRect.offset(dirtyRect.fLeft * scale, dirtyRect.fTop * scale);
+
+ if (!realTileRect.intersect(realDirtyRect))
+ return false;
+ return true;
+}
+
+bool Tile::isTileVisible(const IntRect& viewTileBounds)
+{
+ return (m_x >= viewTileBounds.x()
+ && m_x < viewTileBounds.x() + viewTileBounds.width()
+ && m_y >= viewTileBounds.y()
+ && m_y < viewTileBounds.y() + viewTileBounds.height());
+}
+
+// This is called from the texture generation thread
+void Tile::paintBitmap(TilePainter* painter)
+{
+ // 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();
+ bool dirty = m_dirty;
+ TileTexture* texture = m_backTexture;
+ SkRegion dirtyArea = m_dirtyArea;
+ float scale = m_scale;
+ const int x = m_x;
+ const int y = m_y;
+
+ if (!dirty || !texture) {
+ m_atomicSync.unlock();
+ return;
+ }
+ if (m_state != Unpainted) {
+ ALOGV("Warning: started painting tile %p, but was at state %d, ft %p bt %p",
+ this, m_state, m_frontTexture, m_backTexture);
+ }
+ m_state = PaintingStarted;
+ TextureInfo* textureInfo = texture->getTextureInfo();
+ m_atomicSync.unlock();
+
+ // at this point we can safely check the ownership (if the texture got
+ // transferred to another Tile under us)
+ if (texture->owner() != this) {
+ return;
+ }
+
+ // swap out the renderer if necessary
+ BaseRenderer::swapRendererIfNeeded(m_renderer);
+ // setup the common renderInfo fields;
+ TileRenderInfo renderInfo;
+ renderInfo.x = x;
+ renderInfo.y = y;
+ renderInfo.scale = scale;
+ renderInfo.tileSize = texture->getSize();
+ renderInfo.tilePainter = painter;
+ renderInfo.baseTile = this;
+ renderInfo.textureInfo = textureInfo;
+
+ const float tileWidth = renderInfo.tileSize.width();
+ const float tileHeight = renderInfo.tileSize.height();
+
+ SkRegion::Iterator cliperator(dirtyArea);
+
+ bool fullRepaint = false;
+
+ if (m_fullRepaint
+ || textureInfo->m_width != tileWidth
+ || textureInfo->m_height != tileHeight) {
+ fullRepaint = true;
+ }
+
+ // For now, only do full repaint
+ fullRepaint = true;
+
+ if (!fullRepaint) {
+ // compute the partial inval area
+ SkIRect totalRect;
+ totalRect.set(0, 0, 0, 0);
+ float tileSurface = tileWidth * tileHeight;
+ float tileSurfaceCap = MAX_INVAL_AREA * tileSurface;
+
+ // We join all the invals in the same tile for now
+ while (!fullRepaint && !cliperator.done()) {
+ SkRect realTileRect;
+ SkRect dirtyRect;
+ dirtyRect.set(cliperator.rect());
+ bool intersect = intersectWithRect(x, y, tileWidth, tileHeight,
+ scale, dirtyRect, realTileRect);
+ if (intersect) {
+ // initialize finalRealRect to the rounded values of realTileRect
+ SkIRect finalRealRect;
+ realTileRect.roundOut(&finalRealRect);
+
+ // stash the int values of the current width and height
+ const int iWidth = finalRealRect.width();
+ const int iHeight = finalRealRect.height();
+
+ if (iWidth == tileWidth || iHeight == tileHeight) {
+ fullRepaint = true;
+ break;
+ }
+
+ // translate the rect into tile space coordinates
+ finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth);
+ finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight);
+ finalRealRect.fRight = finalRealRect.fLeft + iWidth;
+ finalRealRect.fBottom = finalRealRect.fTop + iHeight;
+ totalRect.join(finalRealRect);
+ float repaintSurface = totalRect.width() * totalRect.height();
+
+ if (repaintSurface > tileSurfaceCap) {
+ fullRepaint = true;
+ break;
+ }
+ }
+
+ cliperator.next();
+ }
+
+ if (!fullRepaint) {
+ renderInfo.invalRect = &totalRect;
+ m_renderer->renderTiledContent(renderInfo);
+ }
+ }
+
+ // Do a full repaint if needed
+ if (fullRepaint) {
+ renderInfo.invalRect = 0;
+ m_renderer->renderTiledContent(renderInfo);
+ }
+
+ m_atomicSync.lock();
+
+ if (texture == m_backTexture) {
+ // set the fullrepaint flags
+ m_fullRepaint = false;
+
+ // The various checks to see if we are still dirty...
+
+ m_dirty = false;
+
+ if (m_scale != scale)
+ m_dirty = true;
+
+ if (fullRepaint)
+ m_dirtyArea.setEmpty();
+ else
+ m_dirtyArea.op(dirtyArea, SkRegion::kDifference_Op);
+
+ if (!m_dirtyArea.isEmpty())
+ m_dirty = true;
+
+ ALOGV("painted tile %p (%d, %d), texture %p, dirty=%d", this, x, y, texture, m_dirty);
+
+ validatePaint();
+ } else {
+ ALOGV("tile %p no longer owns texture %p, m_state %d. ft %p bt %p",
+ this, texture, m_state, m_frontTexture, m_backTexture);
+ }
+
+ m_atomicSync.unlock();
+}
+
+void Tile::discardTextures() {
+ android::AutoMutex lock(m_atomicSync);
+ ALOGV("%p discarding bt %p, ft %p",
+ this, m_backTexture, m_frontTexture);
+ if (m_frontTexture) {
+ m_frontTexture->release(this);
+ m_frontTexture = 0;
+ }
+ if (m_backTexture) {
+ m_backTexture->release(this);
+ m_backTexture = 0;
+ }
+ m_dirtyArea.setEmpty();
+ m_fullRepaint = true;
+
+ m_dirty = true;
+ m_state = Unpainted;
+}
+
+void Tile::discardBackTexture() {
+ android::AutoMutex lock(m_atomicSync);
+ if (m_backTexture) {
+ m_backTexture->release(this);
+ m_backTexture = 0;
+ }
+ m_state = Unpainted;
+ m_dirty = true;
+}
+
+bool Tile::swapTexturesIfNeeded() {
+ android::AutoMutex lock(m_atomicSync);
+ if (m_state == ReadyToSwap) {
+ // discard old texture and swap the new one in its place
+ if (m_frontTexture)
+ m_frontTexture->release(this);
+
+ m_frontTexture = m_backTexture;
+ m_backTexture = 0;
+ m_state = UpToDate;
+ ALOGV("display texture for %p at %d, %d front is now %p, back is %p",
+ this, m_x, m_y, m_frontTexture, m_backTexture);
+
+ return true;
+ }
+ return false;
+}
+
+void Tile::backTextureTransfer() {
+ android::AutoMutex lock(m_atomicSync);
+ if (m_state == PaintingStarted)
+ m_state = TransferredUnvalidated;
+ else if (m_state == ValidatedUntransferred)
+ m_state = ReadyToSwap;
+ else {
+ // shouldn't have transferred a tile in any other state, log
+ ALOGV("Note: transferred tile %p at %d %d, state wasn't paintingstarted or validated: %d",
+ this, m_x, m_y, m_state);
+ }
+}
+
+void Tile::backTextureTransferFail() {
+ // transfer failed for some reason, mark dirty so it will (repaint and) be
+ // retransferred.
+ android::AutoMutex lock(m_atomicSync);
+ m_state = Unpainted;
+ m_dirty = true;
+ // whether validatePaint is called before or after, it won't do anything
+}
+
+void Tile::validatePaint() {
+ // ONLY CALL while m_atomicSync is locked (at the end of paintBitmap())
+
+ if (!m_dirty) {
+ // since after the paint, the tile isn't dirty, 'validate' it - this
+ // may happed before or after the transfer queue operation. Only
+ // when both have happened, mark as 'ReadyToSwap'
+ if (m_state == PaintingStarted)
+ m_state = ValidatedUntransferred;
+ else if (m_state == TransferredUnvalidated) {
+ // When the backTexture has been marked pureColor, we will skip the
+ // transfer and marked as ReadyToSwap, in this case, we don't want
+ // to reset m_dirty bit to true.
+ m_state = ReadyToSwap;
+ } else {
+ ALOGV("Note: validated tile %p at %d %d, state wasn't paintingstarted or transferred %d",
+ this, m_x, m_y, m_state);
+ // failed transferring, in which case mark dirty (since
+ // paintBitmap() may have cleared m_dirty)
+ m_dirty = true;
+ }
+
+ if (m_deferredDirty) {
+ ALOGV("Note: deferred dirty flag set, possibly a missed paint on tile %p", this);
+ m_deferredDirty = false;
+ }
+ } else {
+ ALOGV("Note: paint was unsuccessful.");
+ m_state = Unpainted;
+ }
+
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.h b/Source/WebCore/platform/graphics/android/rendering/Tile.h
new file mode 100644
index 0000000..7010301
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/Tile.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2010, 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 Tile_h
+#define Tile_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "BaseRenderer.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+#include "TextureOwner.h"
+#include "TilePainter.h"
+
+#include <utils/threads.h>
+
+namespace WebCore {
+
+class TextureInfo;
+class TileTexture;
+class GLWebViewState;
+
+/**
+ * An individual tile that is used to construct part of a webpage's BaseLayer of
+ * content. Each tile is assigned to a TiledPage and is responsible for drawing
+ * and displaying their section of the page. The lifecycle of a tile is:
+ *
+ * 1. Each tile is created on the main GL thread and assigned to a specific
+ * location within a TiledPage.
+ * 2. When needed the tile is passed to the background thread where it paints
+ * the BaseLayer's most recent PictureSet to a bitmap which is then uploaded
+ * to the GPU.
+ * 3. After the bitmap is uploaded to the GPU the main GL thread then uses the
+ * tile's drawGL() function to display the tile to the screen.
+ * 4. Steps 2-3 are repeated as necessary.
+ * 5. The tile is destroyed when the user navigates to a new page.
+ *
+ */
+class Tile : public TextureOwner {
+public:
+
+ // eventually, m_dirty might be rolled into the state machine, but note
+ // that a tile that's continually marked dirty from animation should still
+ // progress through the state machine and be drawn periodically (esp. for
+ // layers)
+
+ // /-> TransferredUnvalidated (TQ interrupts paint) -\ (TQ & paint done)
+ // Unpainted -> PaintingStarted -- -> ReadyToSwap -> UpToDate
+ // ^ \-> ValidatedUntransferred (paint finish before TQ) -/
+ // |
+ // \--... (From any state when marked dirty. should usually come from UpToDate if the updates are locked)
+ //
+
+ enum TextureState{
+ // back texture is completely unpainted
+ Unpainted = 0,
+ // has started painting, but haven't been transferred or validated
+ PaintingStarted = 1,
+ // back texture painted, transferred before validating in PaintBitmap()
+ TransferredUnvalidated = 2,
+ // back texture painted, validated before transferring in TransferQueue
+ ValidatedUntransferred = 3,
+ // back texture has been blitted, will be swapped when next available
+ ReadyToSwap = 4,
+ // has been swapped, is ready to draw, all is well
+ UpToDate = 5,
+ };
+
+ Tile(bool isLayerTile = false);
+ ~Tile();
+
+ bool isLayerTile() { return m_isLayerTile; }
+
+ void setContents(int x, int y, float scale, bool isExpandedPrefetchTile);
+
+ void reserveTexture();
+
+ bool isTileReady();
+
+ // Return false when real draw didn't happen for any reason.
+ bool drawGL(float opacity, const SkRect& rect, float scale,
+ const TransformationMatrix* transform,
+ bool forceBlending = false);
+
+ // the only thread-safe function called by the background thread
+ void paintBitmap(TilePainter* painter);
+
+ bool intersectWithRect(int x, int y, int tileWidth, int tileHeight,
+ float scale, const SkRect& dirtyRect,
+ SkRect& realTileRect);
+ bool isTileVisible(const IntRect& viewTileBounds);
+
+ void markAsDirty(const SkRegion& dirtyArea);
+ bool isDirty();
+ virtual bool isRepaintPending();
+ void setRepaintPending(bool pending);
+ float scale() const { return m_scale; }
+ TextureState textureState() const { return m_state; }
+
+ int x() const { return m_x; }
+ int y() const { return m_y; }
+ TileTexture* frontTexture() { return m_frontTexture; }
+ TileTexture* backTexture() { return m_backTexture; }
+
+ // only used for prioritization - the higher, the more relevant the tile is
+ unsigned long long drawCount() { return m_drawCount; }
+ void discardTextures();
+ void discardBackTexture();
+ bool swapTexturesIfNeeded();
+ void backTextureTransfer();
+ void backTextureTransferFail();
+
+ // TextureOwner implementation
+ virtual bool removeTexture(TileTexture* texture);
+
+private:
+ void validatePaint();
+
+ int m_x;
+ int m_y;
+
+ // The remaining variables can be updated throughout the lifetime of the object
+
+ TileTexture* m_frontTexture;
+ TileTexture* m_backTexture;
+ float m_scale;
+
+ // used to signal that the that the tile is out-of-date and needs to be
+ // redrawn in the backTexture
+ bool m_dirty;
+
+ // currently only for debugging, to be used for tracking down dropped repaints
+ bool m_deferredDirty;
+
+ // used to signal that a repaint is pending
+ bool m_repaintPending;
+
+ // store the dirty region
+ SkRegion m_dirtyArea;
+ bool m_fullRepaint;
+
+ // 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.
+ android::Mutex m_atomicSync;
+
+ BaseRenderer* m_renderer;
+
+ bool m_isLayerTile;
+
+ // 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;
+
+ // Tracks the state of painting for the tile. High level overview:
+ // 1) Unpainted - until paint starts (and if marked dirty, in most cases)
+ // 2) PaintingStarted - until paint completes
+ // 3) TransferredUnvalidated - if transferred first
+ // or ValidatedUntransferred - if validated first
+ // 4) ReadyToSwap - if painted and transferred, but not swapped
+ // 5) UpToDate - until marked dirty again
+ TextureState m_state;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // Tile_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp
new file mode 100644
index 0000000..0e900a9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.cpp
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2011, 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 "TileGrid"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TileGrid.h"
+
+#include "AndroidLog.h"
+#include "DrawQuadData.h"
+#include "GLWebViewState.h"
+#include "PaintTileOperation.h"
+#include "Tile.h"
+#include "TilesManager.h"
+
+#include <wtf/CurrentTime.h>
+
+#define EXPANDED_BOUNDS_INFLATE 1
+#define EXPANDED_PREFETCH_BOUNDS_Y_INFLATE 1
+
+namespace WebCore {
+
+TileGrid::TileGrid(bool isBaseSurface)
+ : m_prevTileY(0)
+ , m_scale(1)
+ , m_isBaseSurface(isBaseSurface)
+{
+ m_dirtyRegion.setEmpty();
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("TileGrid");
+#endif
+}
+
+TileGrid::~TileGrid()
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("TileGrid");
+#endif
+ removeTiles();
+}
+
+bool TileGrid::isReady()
+{
+ bool tilesAllReady = true;
+ bool tilesVisible = false;
+ for (unsigned int i = 0; i < m_tiles.size(); i++) {
+ Tile* tile = m_tiles[i];
+ if (tile->isTileVisible(m_area)) {
+ tilesVisible = true;
+ if (!tile->isTileReady()) {
+ tilesAllReady = false;
+ break;
+ }
+ }
+ }
+ // For now, if no textures are available, consider ourselves as ready
+ // in order to unblock the zooming process.
+ // FIXME: have a better system -- maybe keeping the last scale factor
+ // able to fully render everything
+ ALOGV("TT %p, ready %d, visible %d, texturesRemain %d",
+ this, tilesAllReady, tilesVisible,
+ TilesManager::instance()->layerTexturesRemain());
+
+ return !TilesManager::instance()->layerTexturesRemain()
+ || !tilesVisible || tilesAllReady;
+}
+
+bool TileGrid::isMissingContent()
+{
+ for (unsigned int i = 0; i < m_tiles.size(); i++)
+ if (m_tiles[i]->isTileVisible(m_area) && !m_tiles[i]->frontTexture())
+ return true;
+ return false;
+}
+
+void TileGrid::swapTiles()
+{
+ int swaps = 0;
+ for (unsigned int i = 0; i < m_tiles.size(); i++)
+ if (m_tiles[i]->swapTexturesIfNeeded())
+ swaps++;
+ ALOGV("TT %p swapping, swaps = %d", this, swaps);
+}
+
+IntRect TileGrid::computeTilesArea(const IntRect& contentArea, float scale)
+{
+ IntRect computedArea;
+ IntRect area(contentArea.x() * scale,
+ contentArea.y() * scale,
+ ceilf(contentArea.width() * scale),
+ ceilf(contentArea.height() * scale));
+
+ ALOGV("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height());
+
+ if (area.width() == 0 && area.height() == 0) {
+ computedArea.setWidth(0);
+ computedArea.setHeight(0);
+ return computedArea;
+ }
+
+ int tileWidth = TilesManager::tileWidth();
+ int tileHeight = TilesManager::tileHeight();
+
+ computedArea.setX(area.x() / tileWidth);
+ computedArea.setY(area.y() / tileHeight);
+ float right = (area.x() + area.width()) / (float) tileWidth;
+ float bottom = (area.y() + area.height()) / (float) tileHeight;
+ computedArea.setWidth(ceilf(right) - computedArea.x());
+ computedArea.setHeight(ceilf(bottom) - computedArea.y());
+ return computedArea;
+}
+
+void TileGrid::prepareGL(GLWebViewState* state, float scale,
+ const IntRect& prepareArea, const IntRect& unclippedArea,
+ TilePainter* painter, bool isLowResPrefetch, bool useExpandPrefetch)
+{
+ // first, how many tiles do we need
+ m_area = computeTilesArea(prepareArea, scale);
+ if (m_area.isEmpty())
+ return;
+
+ ALOGV("prepare TileGrid %p with scale %.2f, prepareArea "
+ " %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles",
+ this, scale,
+ prepareArea.x(), prepareArea.y(),
+ prepareArea.width(), prepareArea.height(),
+ m_area.x(), m_area.y(),
+ m_area.width(), m_area.height());
+
+ bool goingDown = m_prevTileY < m_area.y();
+ m_prevTileY = m_area.y();
+
+ if (scale != m_scale)
+ TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(painter, m_scale));
+
+ m_scale = scale;
+
+ // apply dirty region to affected tiles
+ if (!m_dirtyRegion.isEmpty()) {
+ for (unsigned int i = 0; i < m_tiles.size(); i++)
+ m_tiles[i]->markAsDirty(m_dirtyRegion);
+
+ // log inval region for the base surface
+ if (m_isBaseSurface && TilesManager::instance()->getProfiler()->enabled()) {
+ SkRegion::Iterator iterator(m_dirtyRegion);
+ while (!iterator.done()) {
+ SkIRect r = iterator.rect();
+ TilesManager::instance()->getProfiler()->nextInval(r, scale);
+ iterator.next();
+ }
+ }
+ m_dirtyRegion.setEmpty();
+ }
+
+ // prepare standard bounds (clearing ExpandPrefetch flag)
+ for (int i = 0; i < m_area.width(); i++) {
+ if (goingDown) {
+ for (int j = 0; j < m_area.height(); j++)
+ prepareTile(m_area.x() + i, m_area.y() + j,
+ painter, state, isLowResPrefetch, false);
+ } else {
+ for (int j = m_area.height() - 1; j >= 0; j--)
+ prepareTile(m_area.x() + i, m_area.y() + j,
+ painter, state, isLowResPrefetch, false);
+ }
+ }
+
+ // prepare expanded bounds
+ if (useExpandPrefetch) {
+ IntRect fullArea = computeTilesArea(unclippedArea, scale);
+ IntRect expandedArea = m_area;
+ expandedArea.inflate(EXPANDED_BOUNDS_INFLATE);
+
+ if (isLowResPrefetch)
+ expandedArea.inflate(EXPANDED_PREFETCH_BOUNDS_Y_INFLATE);
+
+ // clip painting area to content
+ expandedArea.intersect(fullArea);
+
+ for (int i = expandedArea.x(); i < expandedArea.maxX(); i++)
+ for (int j = expandedArea.y(); j < expandedArea.maxY(); j++)
+ if (!m_area.contains(i, j))
+ prepareTile(i, j, painter, state, isLowResPrefetch, true);
+ }
+}
+
+void TileGrid::markAsDirty(const SkRegion& invalRegion)
+{
+ ALOGV("TT %p markAsDirty, current region empty %d, new empty %d",
+ this, m_dirtyRegion.isEmpty(), invalRegion.isEmpty());
+ m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
+}
+
+void TileGrid::prepareTile(int x, int y, TilePainter* painter,
+ GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch)
+{
+ Tile* tile = getTile(x, y);
+ if (!tile) {
+ bool isLayerTile = !m_isBaseSurface;
+ tile = new Tile(isLayerTile);
+ m_tiles.append(tile);
+ }
+
+ ALOGV("preparing tile %p at %d, %d, painter is %p", tile, x, y, painter);
+
+ tile->setContents(x, y, m_scale, isExpandPrefetch);
+
+ // TODO: move below (which is largely the same for layers / tiled page) into
+ // prepareGL() function
+
+ if (tile->isDirty() || !tile->frontTexture())
+ tile->reserveTexture();
+
+ if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending()) {
+ ALOGV("painting TT %p's tile %d %d for LG %p", this, x, y, painter);
+ PaintTileOperation *operation = new PaintTileOperation(tile, painter,
+ state, isLowResPrefetch);
+ TilesManager::instance()->scheduleOperation(operation);
+ }
+}
+
+Tile* TileGrid::getTile(int x, int y)
+{
+ for (unsigned int i = 0; i <m_tiles.size(); i++) {
+ Tile* tile = m_tiles[i];
+ if (tile->x() == x && tile->y() == y)
+ return tile;
+ }
+ return 0;
+}
+
+int TileGrid::nbTextures(IntRect& area, float scale)
+{
+ IntRect tileBounds = computeTilesArea(area, scale);
+ int numberTextures = tileBounds.width() * tileBounds.height();
+
+ // add the number of dirty tiles in the bounds, as they take up double
+ // textures for double buffering
+ for (unsigned int i = 0; i <m_tiles.size(); i++) {
+ Tile* tile = m_tiles[i];
+ if (tile->isDirty()
+ && tile->x() >= tileBounds.x() && tile->x() <= tileBounds.maxX()
+ && tile->y() >= tileBounds.y() && tile->y() <= tileBounds.maxY())
+ numberTextures++;
+ }
+ return numberTextures;
+}
+
+void TileGrid::drawGL(const IntRect& visibleArea, float opacity,
+ const TransformationMatrix* transform,
+ const Color* background)
+{
+ m_area = computeTilesArea(visibleArea, m_scale);
+ if (m_area.width() == 0 || m_area.height() == 0)
+ return;
+
+ float invScale = 1 / m_scale;
+ const float tileWidth = TilesManager::tileWidth() * invScale;
+ const float tileHeight = TilesManager::tileHeight() * invScale;
+
+ int drawn = 0;
+
+ SkRegion missingRegion;
+ bool semiOpaqueBaseSurface =
+ background ? (background->hasAlpha() && background->alpha() > 0) : false;
+ if (semiOpaqueBaseSurface) {
+ SkIRect totalArea = SkIRect::MakeXYWH(m_area.x(), m_area.y(),
+ m_area.width(), m_area.height());
+ missingRegion = SkRegion(totalArea);
+ }
+
+ for (unsigned int i = 0; i < m_tiles.size(); i++) {
+ Tile* tile = m_tiles[i];
+
+ bool tileInView = tile->isTileVisible(m_area);
+ if (tileInView) {
+ SkRect rect;
+ rect.fLeft = tile->x() * tileWidth;
+ rect.fTop = tile->y() * tileHeight;
+ rect.fRight = rect.fLeft + tileWidth;
+ rect.fBottom = rect.fTop + tileHeight;
+ ALOGV("tile %p (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
+ tile, tile->isLayerTile(), tile->x(), tile->y(),
+ tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
+
+ bool forceBaseBlending = background ? background->hasAlpha() : false;
+ bool success = tile->drawGL(opacity, rect, m_scale, transform,
+ forceBaseBlending);
+ if (semiOpaqueBaseSurface && success) {
+ // Cut the successful drawn tile area from the missing region.
+ missingRegion.op(SkIRect::MakeXYWH(tile->x(), tile->y(), 1, 1),
+ SkRegion::kDifference_Op);
+ }
+ if (tile->frontTexture())
+ drawn++;
+ }
+
+ if (semiOpaqueBaseSurface)
+ TilesManager::instance()->getProfiler()->nextTile(tile, invScale, tileInView);
+ }
+
+ // Draw missing Regions with blend turned on
+ if (semiOpaqueBaseSurface)
+ drawMissingRegion(missingRegion, opacity, background);
+
+ ALOGV("TT %p drew %d tiles, scale %f",
+ this, drawn, m_scale);
+}
+
+void TileGrid::drawMissingRegion(const SkRegion& region, float opacity,
+ const Color* background)
+{
+ SkRegion::Iterator iterator(region);
+ const float tileWidth = TilesManager::tileWidth() / m_scale;
+ const float tileHeight = TilesManager::tileHeight() / m_scale;
+ ShaderProgram* shader = TilesManager::instance()->shader();
+ while (!iterator.done()) {
+ SkIRect r = iterator.rect();
+ SkRect rect;
+ rect.fLeft = r.x() * tileWidth;
+ rect.fTop = r.y() * tileHeight;
+ rect.fRight = rect.fLeft + tileWidth * r.width();
+ rect.fBottom = rect.fTop + tileHeight * r.height();
+ ALOGV("draw tile x y, %d %d (%d %d) opacity %f", r.x(), r.y(),
+ r.width(), r.height(), opacity);
+ // Skia is using pre-multiplied color.
+ Color postAlpha = Color(background->red() * background->alpha() / 255,
+ background->green() * background->alpha() / 255,
+ background->blue() * background->alpha() / 255,
+ background->alpha() );
+
+ PureColorQuadData backGroundData(postAlpha, BaseQuad, 0, &rect, opacity);
+ TilesManager::instance()->shader()->drawQuad(&backGroundData);
+ iterator.next();
+ }
+}
+
+void TileGrid::removeTiles()
+{
+ for (unsigned int i = 0; i < m_tiles.size(); i++) {
+ delete m_tiles[i];
+ }
+ m_tiles.clear();
+}
+
+void TileGrid::discardTextures()
+{
+ ALOGV("TT %p discarding textures", this);
+ for (unsigned int i = 0; i < m_tiles.size(); i++)
+ m_tiles[i]->discardTextures();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/TileGrid.h b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h
new file mode 100644
index 0000000..ffb6c7e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TileGrid.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2011, 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 TileGrid_h
+#define TileGrid_h
+
+#include "IntRect.h"
+#include "SkRegion.h"
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Color;
+class GLWebViewState;
+class Tile;
+class TilePainter;
+class TransformationMatrix;
+
+class TileGrid {
+public:
+ TileGrid(bool isBaseSurface);
+ virtual ~TileGrid();
+
+ static IntRect computeTilesArea(const IntRect& contentArea, float scale);
+
+ void prepareGL(GLWebViewState* state, float scale,
+ const IntRect& prepareArea, const IntRect& unclippedArea,
+ TilePainter* painter, bool isLowResPrefetch = false,
+ bool useExpandPrefetch = false);
+ void swapTiles();
+ void drawGL(const IntRect& visibleArea, float opacity,
+ const TransformationMatrix* transform, const Color* background = 0);
+
+ void prepareTile(int x, int y, TilePainter* painter,
+ GLWebViewState* state, bool isLowResPrefetch, bool isExpandPrefetch);
+ void markAsDirty(const SkRegion& dirtyArea);
+
+ Tile* getTile(int x, int y);
+
+ void removeTiles();
+ void discardTextures();
+
+ bool isReady();
+ bool isMissingContent();
+
+ int nbTextures(IntRect& area, float scale);
+
+private:
+ void drawMissingRegion(const SkRegion& region, float opacity, const Color* tileBackground);
+ WTF::Vector<Tile*> m_tiles;
+
+ IntRect m_area;
+
+ SkRegion m_dirtyRegion;
+
+ int m_prevTileY;
+ float m_scale;
+
+ bool m_isBaseSurface;
+};
+
+} // namespace WebCore
+
+#endif // TileGrid_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilePainter.h b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h
new file mode 100644
index 0000000..d992aee
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TilePainter.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011, 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 TilePainter_h
+#define TilePainter_h
+
+#include "TransformationMatrix.h"
+#include "SkRefCnt.h"
+
+class SkCanvas;
+
+namespace WebCore {
+
+class Tile;
+class Color;
+
+class TilePainter : public SkRefCnt {
+// TODO: investigate webkit threadsafe ref counting
+public:
+ virtual ~TilePainter() { }
+ virtual bool paint(Tile* tile, SkCanvas* canvas) = 0;
+ virtual float opacity() { return 1.0; }
+ enum SurfaceType { Painted, Image };
+ virtual SurfaceType type() { return Painted; }
+ virtual Color* background() { return 0; }
+
+ unsigned int getUpdateCount() { return m_updateCount; }
+ void setUpdateCount(unsigned int updateCount) { m_updateCount = updateCount; }
+
+private:
+ unsigned int m_updateCount;
+};
+
+}
+
+#endif // TilePainter_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp b/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp
new file mode 100644
index 0000000..39effd7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TileTexture.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2010, 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 "TileTexture"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TileTexture.h"
+
+#include "AndroidLog.h"
+#include "Tile.h"
+#include "ClassTracker.h"
+#include "DrawQuadData.h"
+#include "GLUtils.h"
+#include "GLWebViewState.h"
+#include "TextureOwner.h"
+#include "TilesManager.h"
+
+namespace WebCore {
+
+TileTexture::TileTexture(uint32_t w, uint32_t h)
+ : m_owner(0)
+ , m_isPureColor(false)
+{
+ m_size.set(w, h);
+ m_ownTextureId = 0;
+
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->increment("TileTexture");
+#endif
+}
+
+TileTexture::~TileTexture()
+{
+#ifdef DEBUG_COUNT
+ ClassTracker::instance()->decrement("TileTexture");
+#endif
+}
+
+void TileTexture::requireGLTexture()
+{
+ if (!m_ownTextureId)
+ m_ownTextureId = GLUtils::createTileGLTexture(m_size.width(), m_size.height());
+}
+
+void TileTexture::discardGLTexture()
+{
+ if (m_ownTextureId)
+ GLUtils::deleteTexture(&m_ownTextureId);
+
+ if (m_owner) {
+ // clear both Tile->Texture and Texture->Tile links
+ m_owner->removeTexture(this);
+ release(m_owner);
+ }
+}
+
+bool TileTexture::acquire(TextureOwner* owner, bool force)
+{
+ if (m_owner == owner)
+ return true;
+
+ return setOwner(owner, force);
+}
+
+bool TileTexture::setOwner(TextureOwner* owner, bool force)
+{
+ bool proceed = true;
+ if (m_owner && m_owner != owner)
+ proceed = m_owner->removeTexture(this);
+
+ if (proceed) {
+ m_owner = owner;
+ return true;
+ }
+
+ return false;
+}
+
+bool TileTexture::release(TextureOwner* owner)
+{
+ ALOGV("texture %p releasing tile %p, m_owner %p", this, owner, m_owner);
+ if (m_owner != owner)
+ return false;
+
+ m_owner = 0;
+ return true;
+}
+
+void TileTexture::transferComplete()
+{
+ if (m_owner) {
+ Tile* owner = static_cast<Tile*>(m_owner);
+ owner->backTextureTransfer();
+ } else
+ ALOGE("ERROR: owner missing after transfer of texture %p", this);
+}
+
+void TileTexture::drawGL(bool isLayer, const SkRect& rect, float opacity,
+ const TransformationMatrix* transform,
+ bool forceBlending)
+{
+ ShaderProgram* shader = TilesManager::instance()->shader();
+
+ if (isLayer && !transform) {
+ ALOGE("ERROR: Missing tranform for layers!");
+ return;
+ }
+
+ // For base layer, we just follow the forceBlending, otherwise, blending is
+ // always turned on.
+ // TODO: Don't blend tiles if they are fully opaque.
+ forceBlending |= isLayer;
+ DrawQuadData commonData(isLayer ? LayerQuad : BaseQuad, transform, &rect,
+ opacity, forceBlending);
+ if (isPureColor()) {
+ PureColorQuadData data(commonData, pureColor());
+ shader->drawQuad(&data);
+ } else {
+ TextureQuadData data(commonData, m_ownTextureId, GL_TEXTURE_2D, GL_LINEAR);
+ shader->drawQuad(&data);
+ }
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/android/rendering/TileTexture.h b/Source/WebCore/platform/graphics/android/rendering/TileTexture.h
new file mode 100644
index 0000000..5fe43b0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TileTexture.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010, 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 TileTexture_h
+#define TileTexture_h
+
+#include "TextureInfo.h"
+#include "Color.h"
+#include "SkBitmap.h"
+#include "SkRect.h"
+#include "SkSize.h"
+
+#include <GLES2/gl2.h>
+
+class SkCanvas;
+
+namespace WebCore {
+
+class TextureOwner;
+class Tile;
+class TransformationMatrix;
+
+class TileTexture {
+public:
+ // This object is to be constructed on the consumer's thread and must have
+ // a width and height greater than 0.
+ TileTexture(uint32_t w, uint32_t h);
+ virtual ~TileTexture();
+
+ // 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);
+ bool release(TextureOwner* owner);
+
+ // set the texture owner if not busy. Return false if busy, true otherwise.
+ bool setOwner(TextureOwner* owner, bool force = false);
+
+ // private member accessor functions
+ TextureOwner* owner() { return m_owner; } // only used by the consumer thread
+
+ const SkSize& getSize() const { return m_size; }
+
+ // OpenGL ID of backing texture, 0 when not allocated
+ GLuint m_ownTextureId;
+ // these are used for dynamically (de)allocating backing graphics memory
+ void requireGLTexture();
+ void discardGLTexture();
+
+ void transferComplete();
+
+ TextureInfo* getTextureInfo() { return &m_ownTextureInfo; }
+
+ // Make sure the following pureColor getter/setter are only read/written
+ // in UI thread. Therefore no need for a lock.
+ void setPure(bool pure) { m_isPureColor = pure; }
+ bool isPureColor() {return m_isPureColor; }
+ void setPureColor(const Color& color) { m_pureColor = color; setPure(true); }
+ Color pureColor() { return m_pureColor; }
+
+ void drawGL(bool isLayer, const SkRect& rect, float opacity,
+ const TransformationMatrix* transform, bool forceBlending = false);
+private:
+ TextureInfo m_ownTextureInfo;
+ SkSize m_size;
+
+ // Tile owning the texture, only modified by UI thread
+ TextureOwner* m_owner;
+
+ // When the whole tile is single color, skip the transfer queue and draw
+ // it directly through shader.
+ bool m_isPureColor;
+ Color m_pureColor;
+};
+
+} // namespace WebCore
+
+#endif // TileTexture_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp
new file mode 100644
index 0000000..e8b8cd1
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2010, 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 "TilesManager"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TilesManager.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "GLWebViewState.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "Tile.h"
+#include "TileTexture.h"
+#include "TransferQueue.h"
+
+#include <android/native_window.h>
+#include <cutils/atomic.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+#include <wtf/CurrentTime.h>
+
+// Important: We need at least twice as many textures as is needed to cover
+// one viewport, otherwise the allocation may stall.
+// We need n textures for one TiledPage, and another n textures for the
+// second page used when scaling.
+// In our case, we use 256*256 textures. On the tablet, this equates to
+// at least 60 textures, or 112 with expanded tile boundaries.
+// 112(tiles)*256*256*4(bpp)*2(pages) = 56MB
+// It turns out the viewport dependent value m_maxTextureCount is a reasonable
+// number to cap the layer tile texturs, it worked on both phones and tablets.
+// TODO: after merge the pool of base tiles and layer tiles, we should revisit
+// the logic of allocation management.
+#define MAX_TEXTURE_ALLOCATION ((6+TILE_PREFETCH_DISTANCE*2)*(5+TILE_PREFETCH_DISTANCE*2)*4)
+#define TILE_WIDTH 256
+#define TILE_HEIGHT 256
+
+#define BYTES_PER_PIXEL 4 // 8888 config
+
+#define LAYER_TEXTURES_DESTROY_TIMEOUT 60 // If we do not need layers for 60 seconds, free the textures
+
+namespace WebCore {
+
+GLint TilesManager::getMaxTextureSize()
+{
+ static GLint maxTextureSize = 0;
+ if (!maxTextureSize)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ return maxTextureSize;
+}
+
+int TilesManager::getMaxTextureAllocation()
+{
+ return MAX_TEXTURE_ALLOCATION;
+}
+
+TilesManager::TilesManager()
+ : m_layerTexturesRemain(true)
+ , m_highEndGfx(false)
+ , m_maxTextureCount(0)
+ , m_maxLayerTextureCount(0)
+ , m_generatorReady(false)
+ , m_showVisualIndicator(false)
+ , m_invertedScreen(false)
+ , m_useMinimalMemory(true)
+ , m_useDoubleBuffering(true)
+ , m_contentUpdates(0)
+ , m_webkitContentUpdates(0)
+ , m_queue(0)
+ , m_drawGLCount(1)
+ , m_lastTimeLayersUsed(0)
+ , m_hasLayerTextures(false)
+{
+ ALOGV("TilesManager ctor");
+ m_textures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
+ m_availableTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
+ m_tilesTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
+ m_availableTilesTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION);
+ m_pixmapsGenerationThread = new TexturesGenerator(this);
+ m_pixmapsGenerationThread->run("TexturesGenerator");
+}
+
+void TilesManager::allocateTiles()
+{
+ int nbTexturesToAllocate = m_maxTextureCount - m_textures.size();
+ ALOGV("%d tiles to allocate (%d textures planned)", nbTexturesToAllocate, m_maxTextureCount);
+ int nbTexturesAllocated = 0;
+ for (int i = 0; i < nbTexturesToAllocate; i++) {
+ TileTexture* texture = new TileTexture(
+ tileWidth(), tileHeight());
+ // the atomic load ensures that the texture has been fully initialized
+ // before we pass a pointer for other threads to operate on
+ TileTexture* loadedTexture =
+ reinterpret_cast<TileTexture*>(
+ android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture)));
+ m_textures.append(loadedTexture);
+ nbTexturesAllocated++;
+ }
+
+ int nbLayersTexturesToAllocate = m_maxLayerTextureCount - m_tilesTextures.size();
+ ALOGV("%d layers tiles to allocate (%d textures planned)",
+ nbLayersTexturesToAllocate, m_maxLayerTextureCount);
+ int nbLayersTexturesAllocated = 0;
+ for (int i = 0; i < nbLayersTexturesToAllocate; i++) {
+ TileTexture* texture = new TileTexture(
+ tileWidth(), tileHeight());
+ // the atomic load ensures that the texture has been fully initialized
+ // before we pass a pointer for other threads to operate on
+ TileTexture* loadedTexture =
+ reinterpret_cast<TileTexture*>(
+ android_atomic_acquire_load(reinterpret_cast<int32_t*>(&texture)));
+ m_tilesTextures.append(loadedTexture);
+ nbLayersTexturesAllocated++;
+ }
+ ALOGV("allocated %d textures for base (total: %d, %d Mb), %d textures for layers (total: %d, %d Mb)",
+ nbTexturesAllocated, m_textures.size(),
+ m_textures.size() * TILE_WIDTH * TILE_HEIGHT * 4 / 1024 / 1024,
+ nbLayersTexturesAllocated, m_tilesTextures.size(),
+ m_tilesTextures.size() * tileWidth() * tileHeight() * 4 / 1024 / 1024);
+}
+
+void TilesManager::discardTextures(bool allTextures, bool glTextures)
+{
+ const unsigned int max = m_textures.size();
+
+ unsigned long long sparedDrawCount = ~0; // by default, spare no textures
+ if (!allTextures) {
+ // if we're not deallocating all textures, spare those with max drawcount
+ sparedDrawCount = 0;
+ for (unsigned int i = 0; i < max; i++) {
+ TextureOwner* owner = m_textures[i]->owner();
+ if (owner)
+ sparedDrawCount = std::max(sparedDrawCount, owner->drawCount());
+ }
+ }
+ discardTexturesVector(sparedDrawCount, m_textures, glTextures);
+ discardTexturesVector(sparedDrawCount, m_tilesTextures, glTextures);
+}
+
+void TilesManager::discardTexturesVector(unsigned long long sparedDrawCount,
+ WTF::Vector<TileTexture*>& textures,
+ bool deallocateGLTextures)
+{
+ const unsigned int max = textures.size();
+ int dealloc = 0;
+ WTF::Vector<int> discardedIndex;
+ for (unsigned int i = 0; i < max; i++) {
+ TextureOwner* owner = textures[i]->owner();
+ if (!owner || owner->drawCount() < sparedDrawCount) {
+ if (deallocateGLTextures) {
+ // deallocate textures' gl memory
+ textures[i]->discardGLTexture();
+ discardedIndex.append(i);
+ } else if (owner) {
+ // simply detach textures from owner
+ static_cast<Tile*>(owner)->discardTextures();
+ }
+ dealloc++;
+ }
+ }
+
+ bool base = textures == m_textures;
+ // Clean up the vector of TileTextures and reset the max texture count.
+ if (discardedIndex.size()) {
+ android::Mutex::Autolock lock(m_texturesLock);
+ for (int i = discardedIndex.size() - 1; i >= 0; i--)
+ textures.remove(discardedIndex[i]);
+
+ int remainedTextureNumber = textures.size();
+ int* countPtr = base ? &m_maxTextureCount : &m_maxLayerTextureCount;
+ if (remainedTextureNumber < *countPtr) {
+ ALOGV("reset maxTextureCount for %s tiles from %d to %d",
+ base ? "base" : "layer", *countPtr, remainedTextureNumber);
+ *countPtr = remainedTextureNumber;
+ }
+
+ }
+
+ ALOGV("Discarded %d %s textures (out of %d %s tiles)",
+ dealloc, (deallocateGLTextures ? "gl" : ""),
+ max, base ? "base" : "layer");
+}
+
+void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures,
+ int* nbLayerTextures, int* nbAllocatedLayerTextures)
+{
+ *nbTextures = m_textures.size();
+ for (unsigned int i = 0; i < m_textures.size(); i++) {
+ TileTexture* texture = m_textures[i];
+ if (texture->m_ownTextureId)
+ *nbAllocatedTextures += 1;
+ }
+ *nbLayerTextures = m_tilesTextures.size();
+ for (unsigned int i = 0; i < m_tilesTextures.size(); i++) {
+ TileTexture* texture = m_tilesTextures[i];
+ if (texture->m_ownTextureId)
+ *nbAllocatedLayerTextures += 1;
+ }
+}
+
+void TilesManager::printTextures()
+{
+#ifdef DEBUG
+ ALOGV("++++++");
+ for (unsigned int i = 0; i < m_textures.size(); i++) {
+ TileTexture* texture = m_textures[i];
+ Tile* o = 0;
+ if (texture->owner())
+ o = (Tile*) texture->owner();
+ int x = -1;
+ int y = -1;
+ if (o) {
+ x = o->x();
+ y = o->y();
+ }
+ ALOGV("[%d] texture %x owner: %x (%d, %d) scale: %.2f",
+ i, texture, o, x, y, o ? o->scale() : 0);
+ }
+ ALOGV("------");
+#endif // DEBUG
+}
+
+void TilesManager::gatherTextures()
+{
+ android::Mutex::Autolock lock(m_texturesLock);
+ m_availableTextures = m_textures;
+ m_availableTilesTextures = m_tilesTextures;
+ m_layerTexturesRemain = true;
+}
+
+TileTexture* TilesManager::getAvailableTexture(Tile* owner)
+{
+ android::Mutex::Autolock lock(m_texturesLock);
+
+ // Sanity check that the tile does not already own a texture
+ if (owner->backTexture() && owner->backTexture()->owner() == owner) {
+ ALOGV("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->backTexture()));
+ else
+ m_availableTextures.remove(m_availableTextures.find(owner->backTexture()));
+ return owner->backTexture();
+ }
+
+ WTF::Vector<TileTexture*>* availableTexturePool;
+ if (owner->isLayerTile()) {
+ availableTexturePool = &m_availableTilesTextures;
+ } else {
+ availableTexturePool = &m_availableTextures;
+ }
+
+ // The heuristic for selecting a texture is as follows:
+ // 1. Skip textures currently being painted, they can't be painted while
+ // busy anyway
+ // 2. If a tile isn't owned, break with that one
+ // 3. Don't let tiles acquire their front textures
+ // 4. Otherwise, use the least recently prepared tile, but ignoring tiles
+ // drawn in the last frame to avoid flickering
+
+ TileTexture* farthestTexture = 0;
+ unsigned long long oldestDrawCount = getDrawGLCount() - 1;
+ const unsigned int max = availableTexturePool->size();
+ for (unsigned int i = 0; i < max; i++) {
+ TileTexture* texture = (*availableTexturePool)[i];
+ Tile* currentOwner = static_cast<Tile*>(texture->owner());
+ if (!currentOwner) {
+ // unused texture! take it!
+ farthestTexture = texture;
+ break;
+ }
+
+ if (currentOwner == owner) {
+ // Don't let a tile acquire its own front texture, as the
+ // acquisition logic doesn't handle that
+ continue;
+ }
+
+ unsigned long long textureDrawCount = currentOwner->drawCount();
+ if (oldestDrawCount > textureDrawCount) {
+ farthestTexture = texture;
+ oldestDrawCount = textureDrawCount;
+ }
+ }
+
+ if (farthestTexture) {
+ Tile* previousOwner = static_cast<Tile*>(farthestTexture->owner());
+ if (farthestTexture->acquire(owner)) {
+ if (previousOwner) {
+ previousOwner->removeTexture(farthestTexture);
+
+ ALOGV("%s texture %p stolen from tile %d, %d for %d, %d, drawCount was %llu (now %llu)",
+ owner->isLayerTile() ? "LAYER" : "BASE",
+ farthestTexture, previousOwner->x(), previousOwner->y(),
+ owner->x(), owner->y(),
+ oldestDrawCount, getDrawGLCount());
+ }
+
+ availableTexturePool->remove(availableTexturePool->find(farthestTexture));
+ return farthestTexture;
+ }
+ } else {
+ if (owner->isLayerTile()) {
+ // couldn't find a tile for a layer, layers shouldn't request redraw
+ // TODO: once we do layer prefetching, don't set this for those
+ // tiles
+ m_layerTexturesRemain = false;
+ }
+ }
+
+ ALOGV("Couldn't find an available texture for %s tile %x (%d, %d) out of %d available",
+ owner->isLayerTile() ? "LAYER" : "BASE",
+ owner, owner->x(), owner->y(), max);
+#ifdef DEBUG
+ printTextures();
+#endif // DEBUG
+ return 0;
+}
+
+void TilesManager::setHighEndGfx(bool highEnd)
+{
+ m_highEndGfx = highEnd;
+}
+
+bool TilesManager::highEndGfx()
+{
+ return m_highEndGfx;
+}
+
+int TilesManager::maxTextureCount()
+{
+ android::Mutex::Autolock lock(m_texturesLock);
+ return m_maxTextureCount;
+}
+
+int TilesManager::maxLayerTextureCount()
+{
+ android::Mutex::Autolock lock(m_texturesLock);
+ return m_maxLayerTextureCount;
+}
+
+void TilesManager::setMaxTextureCount(int max)
+{
+ ALOGV("setMaxTextureCount: %d (current: %d, total:%d)",
+ max, m_maxTextureCount, MAX_TEXTURE_ALLOCATION);
+ if (m_maxTextureCount == MAX_TEXTURE_ALLOCATION ||
+ max <= m_maxTextureCount)
+ return;
+
+ android::Mutex::Autolock lock(m_texturesLock);
+
+ if (max < MAX_TEXTURE_ALLOCATION)
+ m_maxTextureCount = max;
+ else
+ m_maxTextureCount = MAX_TEXTURE_ALLOCATION;
+
+ allocateTiles();
+}
+
+void TilesManager::setMaxLayerTextureCount(int max)
+{
+ ALOGV("setMaxLayerTextureCount: %d (current: %d, total:%d)",
+ max, m_maxLayerTextureCount, MAX_TEXTURE_ALLOCATION);
+ if (!max && m_hasLayerTextures) {
+ double secondsSinceLayersUsed = WTF::currentTime() - m_lastTimeLayersUsed;
+ if (secondsSinceLayersUsed > LAYER_TEXTURES_DESTROY_TIMEOUT) {
+ unsigned long long sparedDrawCount = ~0; // by default, spare no textures
+ bool deleteGLTextures = true;
+ discardTexturesVector(sparedDrawCount, m_tilesTextures, deleteGLTextures);
+ m_hasLayerTextures = false;
+ }
+ return;
+ }
+ m_lastTimeLayersUsed = WTF::currentTime();
+ if (m_maxLayerTextureCount == MAX_TEXTURE_ALLOCATION ||
+ max <= m_maxLayerTextureCount)
+ return;
+
+ android::Mutex::Autolock lock(m_texturesLock);
+
+ if (max < MAX_TEXTURE_ALLOCATION)
+ m_maxLayerTextureCount = max;
+ else
+ m_maxLayerTextureCount = MAX_TEXTURE_ALLOCATION;
+
+ allocateTiles();
+ m_hasLayerTextures = true;
+}
+
+TransferQueue* TilesManager::transferQueue()
+{
+ // m_queue will be created on the UI thread, although it may
+ // be accessed from the TexturesGenerator. However, that can only happen after
+ // a previous transferQueue() call due to a prepare.
+ if (!m_queue)
+ m_queue = new TransferQueue(m_useMinimalMemory);
+ return m_queue;
+}
+
+float TilesManager::tileWidth()
+{
+ return TILE_WIDTH;
+}
+
+float TilesManager::tileHeight()
+{
+ return TILE_HEIGHT;
+}
+
+TilesManager* TilesManager::instance()
+{
+ if (!gInstance) {
+ gInstance = new TilesManager();
+ ALOGV("instance(), new gInstance is %x", gInstance);
+ }
+ return gInstance;
+}
+
+TilesManager* TilesManager::gInstance = 0;
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h
new file mode 100644
index 0000000..92c56d3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2010, 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 TilesManager_h
+#define TilesManager_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "LayerAndroid.h"
+#include "ShaderProgram.h"
+#include "TexturesGenerator.h"
+#include "TilesProfiler.h"
+#include "VideoLayerManager.h"
+#include <utils/threads.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class OperationFilter;
+class Tile;
+class TileTexture;
+class TransferQueue;
+
+class TilesManager {
+public:
+ // May only be called from the UI thread
+ static TilesManager* instance();
+ static GLint getMaxTextureSize();
+ static int getMaxTextureAllocation();
+
+ static bool hardwareAccelerationEnabled()
+ {
+ return gInstance != 0;
+ }
+
+ void removeOperationsForFilter(OperationFilter* filter, bool waitForRunning = false)
+ {
+ m_pixmapsGenerationThread->removeOperationsForFilter(filter, waitForRunning);
+ }
+
+ void scheduleOperation(QueuedOperation* operation)
+ {
+ m_pixmapsGenerationThread->scheduleOperation(operation);
+ }
+
+ ShaderProgram* shader() { return &m_shader; }
+ TransferQueue* transferQueue();
+ VideoLayerManager* videoLayerManager() { return &m_videoLayerManager; }
+
+ void gatherTextures();
+ bool layerTexturesRemain() { return m_layerTexturesRemain; }
+ void gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures,
+ int* nbLayerTextures, int* nbAllocatedLayerTextures);
+
+ TileTexture* getAvailableTexture(Tile* owner);
+
+ void printTextures();
+
+ // m_highEndGfx is written/read only on UI thread, no need for a lock.
+ void setHighEndGfx(bool highEnd);
+ bool highEndGfx();
+
+ int maxTextureCount();
+ int maxLayerTextureCount();
+ void setMaxTextureCount(int max);
+ void setMaxLayerTextureCount(int max);
+ static float tileWidth();
+ static float tileHeight();
+
+ void allocateTiles();
+
+ // remove all tiles from textures (and optionally deallocate gl memory)
+ void discardTextures(bool allTextures, bool glTextures);
+
+ bool getShowVisualIndicator()
+ {
+ return m_showVisualIndicator;
+ }
+
+ void setShowVisualIndicator(bool showVisualIndicator)
+ {
+ m_showVisualIndicator = showVisualIndicator;
+ }
+
+ TilesProfiler* getProfiler()
+ {
+ return &m_profiler;
+ }
+
+ bool invertedScreen()
+ {
+ return m_invertedScreen;
+ }
+
+ void setInvertedScreen(bool invert)
+ {
+ m_invertedScreen = invert;
+ }
+
+ void setInvertedScreenContrast(float contrast)
+ {
+ m_shader.setContrast(contrast);
+ }
+
+ void setUseMinimalMemory(bool useMinimalMemory)
+ {
+ m_useMinimalMemory = useMinimalMemory;
+ }
+
+ bool useMinimalMemory()
+ {
+ return m_useMinimalMemory;
+ }
+
+ void setUseDoubleBuffering(bool useDoubleBuffering)
+ {
+ m_useDoubleBuffering = useDoubleBuffering;
+ }
+ bool useDoubleBuffering() { return m_useDoubleBuffering; }
+
+
+ unsigned int incWebkitContentUpdates() { return m_webkitContentUpdates++; }
+
+ void incContentUpdates() { m_contentUpdates++; }
+ unsigned int getContentUpdates() { return m_contentUpdates; }
+ void clearContentUpdates() { m_contentUpdates = 0; }
+
+ void incDrawGLCount()
+ {
+ m_drawGLCount++;
+ }
+
+ unsigned long long getDrawGLCount()
+ {
+ return m_drawGLCount;
+ }
+
+private:
+ TilesManager();
+
+ void discardTexturesVector(unsigned long long sparedDrawCount,
+ WTF::Vector<TileTexture*>& textures,
+ bool deallocateGLTextures);
+
+ WTF::Vector<TileTexture*> m_textures;
+ WTF::Vector<TileTexture*> m_availableTextures;
+
+ WTF::Vector<TileTexture*> m_tilesTextures;
+ WTF::Vector<TileTexture*> m_availableTilesTextures;
+ bool m_layerTexturesRemain;
+
+ bool m_highEndGfx;
+ int m_maxTextureCount;
+ int m_maxLayerTextureCount;
+
+ bool m_generatorReady;
+
+ bool m_showVisualIndicator;
+ bool m_invertedScreen;
+
+ bool m_useMinimalMemory;
+
+ bool m_useDoubleBuffering;
+ unsigned int m_contentUpdates; // nr of successful tiled paints
+ unsigned int m_webkitContentUpdates; // nr of paints from webkit
+
+ sp<TexturesGenerator> m_pixmapsGenerationThread;
+
+ android::Mutex m_texturesLock;
+
+ static TilesManager* gInstance;
+
+ ShaderProgram m_shader;
+ TransferQueue* m_queue;
+
+ VideoLayerManager m_videoLayerManager;
+
+ TilesProfiler m_profiler;
+ unsigned long long m_drawGLCount;
+ double m_lastTimeLayersUsed;
+ bool m_hasLayerTextures;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // TilesManager_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesProfiler.cpp b/Source/WebCore/platform/graphics/android/rendering/TilesProfiler.cpp
new file mode 100644
index 0000000..4f0c6b5
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TilesProfiler.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2010, 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 "TilesProfiler"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TilesProfiler.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "Tile.h"
+#include "TilesManager.h"
+#include <wtf/CurrentTime.h>
+
+// Hard limit on amount of frames (and thus memory) profiling can take
+#define MAX_PROF_FRAMES 400
+#define INVAL_CODE -2
+
+namespace WebCore {
+TilesProfiler::TilesProfiler()
+ : m_enabled(false)
+{
+}
+
+void TilesProfiler::start()
+{
+ m_enabled = true;
+ m_goodTiles = 0;
+ m_badTiles = 0;
+ m_records.clear();
+ m_time = currentTimeMS();
+ ALOGV("initializing tileprofiling");
+}
+
+float TilesProfiler::stop()
+{
+ m_enabled = false;
+ ALOGV("completed tile profiling, observed %d frames", m_records.size());
+ return (1.0 * m_goodTiles) / (m_goodTiles + m_badTiles);
+}
+
+void TilesProfiler::clear()
+{
+ ALOGV("clearing tile profiling of its %d frames", m_records.size());
+ m_records.clear();
+}
+
+void TilesProfiler::nextFrame(int left, int top, int right, int bottom, float scale)
+{
+ if (!m_enabled || (m_records.size() > MAX_PROF_FRAMES))
+ return;
+
+ double currentTime = currentTimeMS();
+ double timeDelta = currentTime - m_time;
+ m_time = currentTime;
+
+#ifdef DEBUG
+ if (m_records.size() != 0) {
+ ALOGD("completed tile profiling frame, observed %d tiles. %f ms since last",
+ m_records[0].size(), timeDelta);
+ }
+#endif // DEBUG
+
+ m_records.append(WTF::Vector<TileProfileRecord>());
+
+ //first record designates viewport
+ m_records.last().append(TileProfileRecord(
+ left, top, right, bottom,
+ scale, true, (int)(timeDelta * 1000)));
+}
+
+void TilesProfiler::nextTile(Tile* tile, float scale, bool inView)
+{
+ if (!m_enabled || (m_records.size() > MAX_PROF_FRAMES) || (m_records.size() == 0))
+ return;
+
+ bool isReady = tile->isTileReady();
+ int left = tile->x() * TilesManager::tileWidth();
+ int top = tile->y() * TilesManager::tileWidth();
+ int right = left + TilesManager::tileWidth();
+ int bottom = top + TilesManager::tileWidth();
+
+ if (inView) {
+ if (isReady)
+ m_goodTiles++;
+ else
+ m_badTiles++;
+ }
+ m_records.last().append(TileProfileRecord(
+ left, top, right, bottom,
+ scale, isReady, (int)tile->drawCount()));
+ ALOGV("adding tile %d %d %d %d, scale %f", left, top, right, bottom, scale);
+}
+
+void TilesProfiler::nextInval(const SkIRect& rect, float scale)
+{
+ if (!m_enabled || (m_records.size() > MAX_PROF_FRAMES) || (m_records.size() == 0))
+ return;
+
+ m_records.last().append(TileProfileRecord(
+ rect.x(), rect.y(),
+ rect.right(), rect.bottom(), scale, false, INVAL_CODE));
+ ALOGV("adding inval region %d %d %d %d, scale %f", rect.x(), rect.y(),
+ rect.right(), rect.bottom(), scale);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesProfiler.h b/Source/WebCore/platform/graphics/android/rendering/TilesProfiler.h
new file mode 100644
index 0000000..b39ae2f
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TilesProfiler.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011, 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 TilesProfiler_h
+#define TilesProfiler_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "IntRect.h"
+#include "SkRect.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Tile;
+
+struct TileProfileRecord {
+ TileProfileRecord(int left, int top, int right, int bottom, float scale, int isReady, int level) {
+ this->left = left;
+ this->top = top;
+ this->right = right;
+ this->bottom = bottom;
+ this->scale = scale;
+ this->isReady = isReady;
+ this->level = level;
+ }
+ int left, top, right, bottom;
+ bool isReady;
+ int level;
+ float scale;
+};
+
+class TilesProfiler {
+public:
+ TilesProfiler();
+
+ void start();
+ float stop();
+ void clear();
+ void nextFrame(int left, int top, int right, int bottom, float scale);
+ void nextTile(Tile* tile, float scale, bool inView);
+ void nextInval(const SkIRect& rect, float scale);
+ int numFrames() {
+ return m_records.size();
+ };
+
+ int numTilesInFrame(int frame) {
+ return m_records[frame].size();
+ }
+
+ TileProfileRecord* getTile(int frame, int tile) {
+ return &m_records[frame][tile];
+ }
+
+ bool enabled() { return m_enabled; }
+
+private:
+ bool m_enabled;
+ unsigned int m_goodTiles;
+ unsigned int m_badTiles;
+ WTF::Vector<WTF::Vector<TileProfileRecord> > m_records;
+ double m_time;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // TilesProfiler_h
diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
new file mode 100644
index 0000000..ec0d9e7
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2011, 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 "TransferQueue"
+#define LOG_NDEBUG 1
+
+#include "config.h"
+#include "TransferQueue.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "AndroidLog.h"
+#include "DrawQuadData.h"
+#include "GLUtils.h"
+#include "Tile.h"
+#include "TileTexture.h"
+#include "TilesManager.h"
+#include <android/native_window.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+// For simple webView usage, MINIMAL_SIZE is recommended for memory saving.
+// In browser case, EFFICIENT_SIZE is preferred.
+#define MINIMAL_SIZE 1
+#define EFFICIENT_SIZE 6
+
+// Set this to 1 if we would like to take the new GpuUpload approach which
+// relied on the glCopyTexSubImage2D instead of a glDraw call
+#define GPU_UPLOAD_WITHOUT_DRAW 1
+
+namespace WebCore {
+
+TransferQueue::TransferQueue(bool useMinimalMem)
+ : m_eglSurface(EGL_NO_SURFACE)
+ , m_transferQueueIndex(0)
+ , m_fboID(0)
+ , m_sharedSurfaceTextureId(0)
+ , m_hasGLContext(true)
+ , m_interruptedByRemovingOp(false)
+ , m_currentDisplay(EGL_NO_DISPLAY)
+ , m_currentUploadType(DEFAULT_UPLOAD_TYPE)
+{
+ memset(&m_GLStateBeforeBlit, 0, sizeof(m_GLStateBeforeBlit));
+ m_transferQueueSize = useMinimalMem ? MINIMAL_SIZE : EFFICIENT_SIZE;
+ m_emptyItemCount = m_transferQueueSize;
+ m_transferQueue = new TileTransferData[m_transferQueueSize];
+}
+
+TransferQueue::~TransferQueue()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ cleanupGLResources();
+ delete[] m_transferQueue;
+}
+
+// This should be called within the m_transferQueueItemLocks.
+// Now only called by emptyQueue() and destructor.
+void TransferQueue::cleanupGLResources()
+{
+ if (m_sharedSurfaceTexture.get()) {
+ m_sharedSurfaceTexture->abandon();
+ m_sharedSurfaceTexture.clear();
+ }
+ if (m_fboID) {
+ glDeleteFramebuffers(1, &m_fboID);
+ m_fboID = 0;
+ }
+ if (m_sharedSurfaceTextureId) {
+ glDeleteTextures(1, &m_sharedSurfaceTextureId);
+ m_sharedSurfaceTextureId = 0;
+ }
+}
+
+void TransferQueue::initGLResources(int width, int height)
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ if (!m_sharedSurfaceTextureId) {
+ glGenTextures(1, &m_sharedSurfaceTextureId);
+ sp<BufferQueue> bufferQueue(new BufferQueue(true));
+ m_sharedSurfaceTexture =
+#if GPU_UPLOAD_WITHOUT_DRAW
+ new android::SurfaceTexture(m_sharedSurfaceTextureId, true,
+ GL_TEXTURE_2D, false, bufferQueue);
+#else
+ new android::SurfaceTexture(m_sharedSurfaceTextureId, true,
+ GL_TEXTURE_EXTERNAL_OES, true,
+ bufferQueue);
+#endif
+ m_ANW = new android::SurfaceTextureClient(m_sharedSurfaceTexture);
+ m_sharedSurfaceTexture->setSynchronousMode(true);
+
+ int extraBuffersNeeded = 0;
+ m_ANW->query(m_ANW.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &extraBuffersNeeded);
+ bufferQueue->setBufferCount(m_transferQueueSize + extraBuffersNeeded);
+
+ int result = native_window_set_buffers_geometry(m_ANW.get(),
+ width, height, HAL_PIXEL_FORMAT_RGBA_8888);
+ GLUtils::checkSurfaceTextureError("native_window_set_buffers_geometry", result);
+ result = native_window_set_usage(m_ANW.get(),
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ GLUtils::checkSurfaceTextureError("native_window_set_usage", result);
+ }
+
+ if (!m_fboID)
+ glGenFramebuffers(1, &m_fboID);
+}
+
+// When bliting, if the item from the transfer queue is mismatching b/t the
+// Tile and the content, then the item is considered as obsolete, and
+// the content is discarded.
+bool TransferQueue::checkObsolete(const TileTransferData* data)
+{
+ Tile* baseTilePtr = data->savedTilePtr;
+ if (!baseTilePtr) {
+ ALOGV("Invalid savedTilePtr , such that the tile is obsolete");
+ return true;
+ }
+
+ TileTexture* baseTileTexture = baseTilePtr->backTexture();
+ if (!baseTileTexture || baseTileTexture != data->savedTileTexturePtr) {
+ ALOGV("Invalid baseTileTexture %p (vs expected %p), such that the tile is obsolete",
+ baseTileTexture, data->savedTileTexturePtr);
+ return true;
+ }
+
+ return false;
+}
+
+void TransferQueue::blitTileFromQueue(GLuint fboID, TileTexture* destTex,
+ TileTexture* frontTex,
+ GLuint srcTexId, GLenum srcTexTarget,
+ int index)
+{
+#if GPU_UPLOAD_WITHOUT_DRAW
+ glBindFramebuffer(GL_FRAMEBUFFER, fboID);
+ glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId);
+
+ int textureWidth = destTex->getSize().width();
+ int textureHeight = destTex->getSize().height();
+
+ IntRect inval = m_transferQueue[index].invalRect;
+ bool partialInval = !inval.isEmpty();
+
+ if (partialInval && frontTex) {
+ // recopy the previous texture to the new one, as
+ // the partial update will not cover the entire texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ frontTex->m_ownTextureId,
+ 0);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
+ }
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ srcTexId,
+ 0);
+
+ if (!partialInval) {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0,
+ inval.width(), inval.height());
+ }
+
+#else
+ // Then set up the FBO and copy the SurfTex content in.
+ glBindFramebuffer(GL_FRAMEBUFFER, fboID);
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ destTex->m_ownTextureId,
+ 0);
+ setGLStateForCopy(destTex->getSize().width(),
+ destTex->getSize().height());
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGV("Error: glCheckFramebufferStatus failed");
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return;
+ }
+
+ // Use empty rect to set up the special matrix to draw.
+ SkRect rect = SkRect::MakeEmpty();
+
+ TextureQuadData data(srcTexId, GL_NEAREST, srcTexTarget, Blit, 0, 0, 1.0, false);
+ TilesManager::instance()->shader()->drawQuad(&data);
+
+ // To workaround a sync issue on some platforms, we should insert the sync
+ // here while in the current FBO.
+ // This will essentially kick off the GPU command buffer, and the Tex Gen
+ // thread will then have to wait for this buffer to finish before writing
+ // into the same memory.
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ if (m_currentDisplay != dpy)
+ m_currentDisplay = dpy;
+ if (m_currentDisplay != EGL_NO_DISPLAY) {
+ if (m_transferQueue[index].m_syncKHR != EGL_NO_SYNC_KHR)
+ eglDestroySyncKHR(m_currentDisplay, m_transferQueue[index].m_syncKHR);
+ m_transferQueue[index].m_syncKHR = eglCreateSyncKHR(m_currentDisplay,
+ EGL_SYNC_FENCE_KHR,
+ 0);
+ }
+ GLUtils::checkEglError("CreateSyncKHR");
+#endif
+}
+
+void TransferQueue::interruptTransferQueue(bool interrupt)
+{
+ m_transferQueueItemLocks.lock();
+ m_interruptedByRemovingOp = interrupt;
+ if (m_interruptedByRemovingOp)
+ m_transferQueueItemCond.signal();
+ m_transferQueueItemLocks.unlock();
+}
+
+// This function must be called inside the m_transferQueueItemLocks, for the
+// wait, m_interruptedByRemovingOp and getHasGLContext().
+// Only called by updateQueueWithBitmap() for now.
+bool TransferQueue::readyForUpdate()
+{
+ if (!getHasGLContext())
+ return false;
+ // Don't use a while loop since when the WebView tear down, the emptyCount
+ // will still be 0, and we bailed out b/c of GL context lost.
+ if (!m_emptyItemCount) {
+ if (m_interruptedByRemovingOp)
+ return false;
+ m_transferQueueItemCond.wait(m_transferQueueItemLocks);
+ if (m_interruptedByRemovingOp)
+ return false;
+ }
+
+ if (!getHasGLContext())
+ return false;
+
+ // Disable this wait until we figure out why this didn't work on some
+ // drivers b/5332112.
+#if 0
+ if (m_currentUploadType == GpuUpload
+ && m_currentDisplay != EGL_NO_DISPLAY) {
+ // Check the GPU fence
+ EGLSyncKHR syncKHR = m_transferQueue[getNextTransferQueueIndex()].m_syncKHR;
+ if (syncKHR != EGL_NO_SYNC_KHR)
+ eglClientWaitSyncKHR(m_currentDisplay,
+ syncKHR,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+ EGL_FOREVER_KHR);
+ }
+ GLUtils::checkEglError("WaitSyncKHR");
+#endif
+
+ return true;
+}
+
+// Both getHasGLContext and setHasGLContext should be called within the lock.
+bool TransferQueue::getHasGLContext()
+{
+ return m_hasGLContext;
+}
+
+void TransferQueue::setHasGLContext(bool hasContext)
+{
+ m_hasGLContext = hasContext;
+}
+
+void TransferQueue::setPendingDiscardWithLock()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ setPendingDiscard();
+}
+
+void TransferQueue::emptyQueue()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ setPendingDiscard();
+ cleanupPendingDiscard();
+ cleanupGLResources();
+}
+
+// Set all the content in the queue to pendingDiscard, after this, there will
+// be nothing added to the queue, and this can be called in any thread.
+// However, in order to discard the content in the Surface Texture using
+// updateTexImage, cleanupPendingDiscard need to be called on the UI thread.
+// Must be called within a m_transferQueueItemLocks.
+void TransferQueue::setPendingDiscard()
+{
+ for (int i = 0 ; i < m_transferQueueSize; i++)
+ if (m_transferQueue[i].status == pendingBlit)
+ m_transferQueue[i].status = pendingDiscard;
+
+ m_pureColorTileQueue.clear();
+
+ bool GLContextExisted = getHasGLContext();
+ // Unblock the Tex Gen thread first before Tile Page deletion.
+ // Otherwise, there will be a deadlock while removing operations.
+ setHasGLContext(false);
+
+ // Only signal once when GL context lost.
+ if (GLContextExisted)
+ m_transferQueueItemCond.signal();
+}
+
+void TransferQueue::updatePureColorTiles()
+{
+ for (unsigned int i = 0 ; i < m_pureColorTileQueue.size(); i++) {
+ TileTransferData* data = &m_pureColorTileQueue[i];
+ if (data->status == pendingBlit) {
+ TileTexture* destTexture = 0;
+ bool obsoleteTile = checkObsolete(data);
+ if (!obsoleteTile) {
+ destTexture = data->savedTilePtr->backTexture();
+ destTexture->setPureColor(data->pureColor);
+ destTexture->transferComplete();
+ }
+ } else if (data->status == emptyItem || data->status == pendingDiscard) {
+ // The queue should be clear instead of setting to different status.
+ ALOGV("Warning: Don't expect an emptyItem here.");
+ }
+ }
+ m_pureColorTileQueue.clear();
+}
+
+// Call on UI thread to copy from the shared Surface Texture to the Tile's texture.
+void TransferQueue::updateDirtyTiles()
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+
+ cleanupPendingDiscard();
+ if (!getHasGLContext())
+ setHasGLContext(true);
+
+ // Check the pure color tile first, since it is simpler.
+ updatePureColorTiles();
+
+ // Start from the oldest item, we call the updateTexImage to retrive
+ // the texture and blit that into each Tile's texture.
+ const int nextItemIndex = getNextTransferQueueIndex();
+ int index = nextItemIndex;
+ bool usedFboForUpload = false;
+ for (int k = 0; k < m_transferQueueSize ; k++) {
+ if (m_transferQueue[index].status == pendingBlit) {
+ bool obsoleteTile = checkObsolete(&m_transferQueue[index]);
+ // Save the needed info, update the Surf Tex, clean up the item in
+ // the queue. Then either move on to next item or copy the content.
+ TileTexture* destTexture = 0;
+ TileTexture* frontTexture = 0;
+ if (!obsoleteTile) {
+ destTexture = m_transferQueue[index].savedTilePtr->backTexture();
+ // while destTexture is guaranteed to not be null, frontTexture
+ // might be (first transfer)
+ frontTexture = m_transferQueue[index].savedTilePtr->frontTexture();
+ }
+
+ if (m_transferQueue[index].uploadType == GpuUpload) {
+ status_t result = m_sharedSurfaceTexture->updateTexImage();
+ if (result != OK)
+ ALOGE("unexpected error: updateTexImage return %d", result);
+ }
+ m_transferQueue[index].savedTilePtr = 0;
+ m_transferQueue[index].status = emptyItem;
+ if (obsoleteTile) {
+ ALOGV("Warning: the texture is obsolete for this baseTile");
+ index = (index + 1) % m_transferQueueSize;
+ continue;
+ }
+
+ // guarantee that we have a texture to blit into
+ destTexture->requireGLTexture();
+
+ if (m_transferQueue[index].uploadType == CpuUpload) {
+ // Here we just need to upload the bitmap content to the GL Texture
+ GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId,
+ *m_transferQueue[index].bitmap,
+ m_transferQueue[index].invalRect);
+ } else {
+ if (!usedFboForUpload) {
+ saveGLState();
+ usedFboForUpload = true;
+ }
+ blitTileFromQueue(m_fboID, destTexture, frontTexture,
+ m_sharedSurfaceTextureId,
+ m_sharedSurfaceTexture->getCurrentTextureTarget(),
+ index);
+ }
+
+ destTexture->setPure(false);
+ destTexture->transferComplete();
+
+ ALOGV("Blit tile x, y %d %d with dest texture %p to destTexture->m_ownTextureId %d",
+ m_transferQueue[index].savedTilePtr,
+ destTexture,
+ destTexture->m_ownTextureId);
+ }
+ index = (index + 1) % m_transferQueueSize;
+ }
+
+ // Clean up FBO setup. Doing this for both CPU/GPU upload can make the
+ // dynamic switch possible. Moving this out from the loop can save some
+ // milli-seconds.
+ if (usedFboForUpload) {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); // rebind the standard FBO
+ restoreGLState();
+ GLUtils::checkGlError("updateDirtyTiles");
+ }
+
+ m_emptyItemCount = m_transferQueueSize;
+ m_transferQueueItemCond.signal();
+}
+
+void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap)
+{
+ if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) {
+ // failed placing bitmap in queue, discard tile's texture so it will be
+ // re-enqueued (and repainted)
+ Tile* tile = renderInfo->baseTile;
+ if (tile)
+ tile->backTextureTransferFail();
+ }
+}
+
+bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap)
+{
+ // This lock need to cover the full update since it is possible that queue
+ // will be cleaned up in the middle of this update without the lock.
+ // The Surface Texture will not block us since the readyForUpdate will check
+ // availability of the slots in the queue first.
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ bool ready = readyForUpdate();
+ TextureUploadType currentUploadType = m_currentUploadType;
+ if (!ready) {
+ ALOGV("Quit bitmap update: not ready! for tile x y %d %d",
+ renderInfo->x, renderInfo->y);
+ return false;
+ }
+ if (currentUploadType == GpuUpload) {
+ // a) Dequeue the Surface Texture and write into the buffer
+ if (!m_ANW.get()) {
+ ALOGV("ERROR: ANW is null");
+ return false;
+ }
+
+ if (!GLUtils::updateSharedSurfaceTextureWithBitmap(m_ANW.get(), bitmap))
+ return false;
+ }
+
+ // b) After update the Surface Texture, now udpate the transfer queue info.
+ addItemInTransferQueue(renderInfo, currentUploadType, &bitmap);
+
+ ALOGV("Bitmap updated x, y %d %d, baseTile %p",
+ renderInfo->x, renderInfo->y, renderInfo->baseTile);
+ return true;
+}
+
+void TransferQueue::addItemInPureColorQueue(const TileRenderInfo* renderInfo)
+{
+ // The pure color tiles' queue will be read from UI thread and written in
+ // Tex Gen thread, thus we need to have a lock here.
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ TileTransferData data;
+ addItemCommon(renderInfo, GpuUpload, &data);
+ data.pureColor = renderInfo->pureColor;
+ m_pureColorTileQueue.append(data);
+}
+
+// Translates the info from TileRenderInfo and others to TileTransferData.
+// This is used by pure color tiles and normal tiles.
+void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo,
+ TextureUploadType type,
+ TileTransferData* data)
+{
+ data->savedTileTexturePtr = renderInfo->baseTile->backTexture();
+ data->savedTilePtr = renderInfo->baseTile;
+ data->status = pendingBlit;
+ data->uploadType = type;
+
+ IntRect inval(0, 0, 0, 0);
+ if (renderInfo->invalRect) {
+ inval.setX(renderInfo->invalRect->fLeft);
+ inval.setY(renderInfo->invalRect->fTop);
+ inval.setWidth(renderInfo->invalRect->width());
+ inval.setHeight(renderInfo->invalRect->height());
+ }
+ data->invalRect = inval;
+}
+
+// Note that there should be lock/unlock around this function call.
+// Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap.
+void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo,
+ TextureUploadType type,
+ const SkBitmap* bitmap)
+{
+ m_transferQueueIndex = (m_transferQueueIndex + 1) % m_transferQueueSize;
+
+ int index = m_transferQueueIndex;
+ if (m_transferQueue[index].savedTilePtr
+ || m_transferQueue[index].status != emptyItem) {
+ ALOGV("ERROR update a tile which is dirty already @ index %d", index);
+ }
+
+ TileTransferData* data = &m_transferQueue[index];
+ addItemCommon(renderInfo, type, data);
+ if (type == CpuUpload && bitmap) {
+ // Lazily create the bitmap
+ if (!m_transferQueue[index].bitmap) {
+ m_transferQueue[index].bitmap = new SkBitmap();
+ int w = bitmap->width();
+ int h = bitmap->height();
+ m_transferQueue[index].bitmap->setConfig(bitmap->config(), w, h);
+ }
+ bitmap->copyTo(m_transferQueue[index].bitmap, bitmap->config());
+ }
+
+ m_emptyItemCount--;
+}
+
+void TransferQueue::setTextureUploadType(TextureUploadType type)
+{
+ android::Mutex::Autolock lock(m_transferQueueItemLocks);
+ if (m_currentUploadType == type)
+ return;
+
+ setPendingDiscard();
+
+ m_currentUploadType = type;
+ ALOGD("Now we set the upload to %s", m_currentUploadType == GpuUpload ? "GpuUpload" : "CpuUpload");
+}
+
+// Note: this need to be called within the lock and on the UI thread.
+// Only called by updateDirtyTiles() and emptyQueue() for now
+void TransferQueue::cleanupPendingDiscard()
+{
+ int index = getNextTransferQueueIndex();
+
+ for (int i = 0 ; i < m_transferQueueSize; i++) {
+ if (m_transferQueue[index].status == pendingDiscard) {
+ // No matter what the current upload type is, as long as there has
+ // been a Surf Tex enqueue operation, this updateTexImage need to
+ // be called to keep things in sync.
+ if (m_transferQueue[index].uploadType == GpuUpload) {
+ status_t result = m_sharedSurfaceTexture->updateTexImage();
+ if (result != OK)
+ ALOGE("unexpected error: updateTexImage return %d", result);
+ }
+
+ // since tiles in the queue may be from another webview, remove
+ // their textures so that they will be repainted / retransferred
+ Tile* tile = m_transferQueue[index].savedTilePtr;
+ TileTexture* texture = m_transferQueue[index].savedTileTexturePtr;
+ if (tile && texture && texture->owner() == tile) {
+ // since tile destruction removes textures on the UI thread, the
+ // texture->owner ptr guarantees the tile is valid
+ tile->discardBackTexture();
+ ALOGV("transfer queue discarded tile %p, removed texture", tile);
+ }
+
+ m_transferQueue[index].savedTilePtr = 0;
+ m_transferQueue[index].savedTileTexturePtr = 0;
+ m_transferQueue[index].status = emptyItem;
+ }
+ index = (index + 1) % m_transferQueueSize;
+ }
+}
+
+void TransferQueue::saveGLState()
+{
+ glGetIntegerv(GL_VIEWPORT, m_GLStateBeforeBlit.viewport);
+ glGetBooleanv(GL_SCISSOR_TEST, m_GLStateBeforeBlit.scissor);
+ glGetBooleanv(GL_DEPTH_TEST, m_GLStateBeforeBlit.depth);
+#ifdef DEBUG
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, m_GLStateBeforeBlit.clearColor);
+#endif
+}
+
+void TransferQueue::setGLStateForCopy(int width, int height)
+{
+ // Need to match the texture size.
+ glViewport(0, 0, width, height);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_DEPTH_TEST);
+ // Clear the content is only for debug purpose.
+#ifdef DEBUG
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+#endif
+}
+
+void TransferQueue::restoreGLState()
+{
+ glViewport(m_GLStateBeforeBlit.viewport[0],
+ m_GLStateBeforeBlit.viewport[1],
+ m_GLStateBeforeBlit.viewport[2],
+ m_GLStateBeforeBlit.viewport[3]);
+
+ if (m_GLStateBeforeBlit.scissor[0])
+ glEnable(GL_SCISSOR_TEST);
+
+ if (m_GLStateBeforeBlit.depth[0])
+ glEnable(GL_DEPTH_TEST);
+#ifdef DEBUG
+ glClearColor(m_GLStateBeforeBlit.clearColor[0],
+ m_GLStateBeforeBlit.clearColor[1],
+ m_GLStateBeforeBlit.clearColor[2],
+ m_GLStateBeforeBlit.clearColor[3]);
+#endif
+}
+
+int TransferQueue::getNextTransferQueueIndex()
+{
+ return (m_transferQueueIndex + 1) % m_transferQueueSize;
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING
diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h
new file mode 100644
index 0000000..65ff116
--- /dev/null
+++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2011, 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 TransferQueue_h
+#define TransferQueue_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "GLUtils.h"
+#include "ShaderProgram.h"
+#include "SkBitmap.h"
+#include <utils/StrongPointer.h>
+#include <utils/threads.h>
+
+namespace WebCore {
+
+class Tile;
+class TileTexture;
+
+struct GLState {
+ GLint viewport[4];
+ GLboolean scissor[1];
+ GLboolean depth[1];
+ GLfloat clearColor[4];
+};
+
+
+// While in the queue, the Tile can be re-used, the updated bitmap
+// can be discarded. In order to track this obsolete base tiles, we save
+// the Tile's Info to make the comparison.
+// At the time of base tile's dtor or webview destroy, we want to discard
+// all the data in the queue. However, we have to do the Surface Texture
+// update in the same GL context as the UI thread. So we mark the status
+// as pendingDiscard, and delay the Surface Texture operation to the next
+// draw call.
+
+enum TransferItemStatus {
+ emptyItem = 0, // S.T. buffer ready for new content
+ pendingBlit = 1, // Ready for bliting into tile's GL Tex.
+ pendingDiscard = 2 // Waiting for the next draw call to discard
+};
+
+enum TextureUploadType {
+ CpuUpload = 0,
+ GpuUpload = 1
+};
+
+#define DEFAULT_UPLOAD_TYPE GpuUpload
+
+class TileTransferData {
+public:
+ TileTransferData()
+ : status(emptyItem)
+ , savedTilePtr(0)
+ , savedTileTexturePtr(0)
+ , uploadType(DEFAULT_UPLOAD_TYPE)
+ , bitmap(0)
+ , m_syncKHR(EGL_NO_SYNC_KHR)
+ {
+ }
+
+ ~TileTransferData()
+ {
+ // Bitmap will be created lazily, need to delete them at dtor.
+ delete bitmap;
+ }
+
+ TransferItemStatus status;
+ Tile* savedTilePtr;
+ TileTexture* savedTileTexturePtr;
+ IntRect invalRect;
+ TextureUploadType uploadType;
+ // This is only useful in Cpu upload code path, so it will be dynamically
+ // lazily allocated.
+ SkBitmap* bitmap;
+
+ // Specific data to the pure color tiles' queue.
+ Color pureColor;
+
+ // Sync object for GPU fence, this is the only the info passed from UI
+ // thread to Tex Gen thread. The reason of having this is due to the
+ // missing sync mechanism on Surface Texture on some vendor. b/5122031.
+ // Bascially the idea is that when UI thread utilize one buffer from
+ // the surface texture, we'll need to kick off the GPU commands, and only
+ // when those particular commands finish, we could write into this buffer
+ // again in Tex Gen thread.
+ EGLSyncKHR m_syncKHR;
+};
+
+class TransferQueue {
+public:
+ TransferQueue(bool useMinimalMem);
+ ~TransferQueue();
+
+ // This will be called by the browser through nativeSetProperty
+ void setTextureUploadType(TextureUploadType type);
+ void cleanupGLResources();
+ void updateDirtyTiles();
+
+ void initGLResources(int width, int height);
+
+ // insert the bitmap into the queue, mark the tile dirty if failing
+ void updateQueueWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap);
+
+ void addItemInTransferQueue(const TileRenderInfo* info,
+ TextureUploadType type,
+ const SkBitmap* bitmap);
+ // Check if the item @ index is ready for update.
+ // The lock will be done when returning true.
+ bool readyForUpdate();
+
+ void interruptTransferQueue(bool);
+
+ void lockQueue() { m_transferQueueItemLocks.lock(); }
+ void unlockQueue() { m_transferQueueItemLocks.unlock(); }
+
+ void addItemInPureColorQueue(const TileRenderInfo* renderInfo);
+
+ void setPendingDiscardWithLock();
+ void emptyQueue();
+
+ bool needsInit() { return !m_sharedSurfaceTextureId; }
+ // This queue can be accessed from UI and TexGen thread, therefore, we need
+ // a lock to protect its access
+ TileTransferData* m_transferQueue;
+
+ android::sp<ANativeWindow> m_ANW;
+
+ // EGL wrapper around m_ANW for use by the GaneshRenderer
+ EGLSurface m_eglSurface;
+
+private:
+ // return true if successfully inserted into queue
+ bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
+ const SkBitmap& bitmap);
+ bool getHasGLContext();
+ void setHasGLContext(bool hasContext);
+
+ int getNextTransferQueueIndex();
+
+ // Save and restore the GL State while switching from/to FBO.
+ void saveGLState();
+ void setGLStateForCopy(int width, int height);
+ void restoreGLState();
+
+ // Check the current transfer queue item is obsolete or not.
+ bool checkObsolete(const TileTransferData* data);
+
+ void setPendingDiscard();
+ // Before each draw call and the blit operation, clean up all the
+ // pendingDiscard items.
+ void cleanupPendingDiscard();
+
+ void blitTileFromQueue(GLuint fboID, TileTexture* destTex,
+ TileTexture* frontTex,
+ GLuint srcTexId, GLenum srcTexTarget,
+ int index);
+
+ void addItemCommon(const TileRenderInfo* renderInfo,
+ TextureUploadType type, TileTransferData* data);
+
+ void updatePureColorTiles();
+ // Note that the m_transferQueueIndex only changed in the TexGen thread
+ // where we are going to move on to update the next item in the queue.
+ int m_transferQueueIndex;
+
+ GLuint m_fboID; // The FBO used for copy the SurfTex to each tile
+
+ GLuint m_sharedSurfaceTextureId;
+
+ // GLContext can be lost when WebView destroyed.
+ bool m_hasGLContext;
+
+ GLState m_GLStateBeforeBlit;
+ android::sp<android::SurfaceTexture> m_sharedSurfaceTexture;
+
+ int m_emptyItemCount;
+
+ bool m_interruptedByRemovingOp;
+
+ // We are using wait/signal to handle our own queue sync.
+ // First of all, if we don't have our own lock, then while WebView is
+ // destroyed, the UI thread will wait for the Tex Gen to get out from
+ // dequeue operation, which will not succeed. B/c at this moment, we
+ // already lost the GL Context.
+ // Now we maintain a counter, which is m_emptyItemCount. When this reach
+ // 0, then we need the Tex Gen thread to wait. UI thread can signal this
+ // wait after calling updateTexImage at the draw call , or after WebView
+ // is destroyed.
+ android::Mutex m_transferQueueItemLocks;
+ android::Condition m_transferQueueItemCond;
+
+ EGLDisplay m_currentDisplay;
+
+ // This should be GpuUpload for production, but for debug purpose or working
+ // around driver/HW issue, we can set it to CpuUpload.
+ TextureUploadType m_currentUploadType;
+
+ // The non-pure-color tile are 1 to 1 mapping with Surface Texture which is
+ // resource limited. To get better performance, it is better to separate
+ // the pure color tile into another queue.
+ WTF::Vector<TileTransferData> m_pureColorTileQueue;
+
+ // The number of items transfer queue can buffer up.
+ int m_transferQueueSize;
+};
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING)
+#endif // TransferQueue_h