<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[81886] trunk/Source</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/81886">81886</a></dd>
<dt>Author</dt> <dd>benjamin.poulain@nokia.com</dd>
<dt>Date</dt> <dd>2011-03-24 12:34:51 -0700 (Thu, 24 Mar 2011)</dd>
</dl>

<h3>Log Message</h3>
<pre>2011-03-24  Benjamin Poulain  <benjamin.poulain@nokia.com>

        Reviewed by Kenneth Rohde Christiansen.

        [Qt] When we render WebGL offscreen, color conversion cost a lot of CPU cycles
        https://bugs.webkit.org/show_bug.cgi?id=40884

        The software fallback is now only needed for corner cases like a manual rendering
        of the page to QImage.

        Keeping the image with the last pixel values is no longer needed. Removing it reduce the
        performance for real-time rendering on software surface, but this case should no longer be
        supported.

        The conversion from OpenGL color space and coordinates is done manually for performance. This
        also fix the bug of the inverted X axis due to the transformation.

        The tests and benchmarks are done through Qt API tests.

        * platform/graphics/qt/GraphicsContext3DQt.cpp:
        (WebCore::swapBgrToRgb):
        (WebCore::GraphicsContext3DInternal::paint):
        (WebCore::GraphicsContext3D::reshape):
2011-03-24  Benjamin Poulain  <benjamin.poulain@nokia.com>

        Reviewed by Kenneth Rohde Christiansen.

        [Qt] When we render WebGL offscreen, color conversion cost a lot of CPU cycles
        https://bugs.webkit.org/show_bug.cgi?id=40884

        Add tests and benchmarks for the software fallback of WebGL.

        * tests/benchmarks/webgl/10000_triangles.html: Added.
        * tests/benchmarks/webgl/tst_webgl.cpp: Added.
        (GraphicsView::GraphicsView):
        (GraphicsView::resizeEvent):
        (tst_WebGlPerformance::init):
        (tst_WebGlPerformance::cleanup):
        (tst_WebGlPerformance::benchSoftwareFallbackRgb16):
        (tst_WebGlPerformance::benchSoftwareFallbackRgb32):
        (tst_WebGlPerformance::benchSoftwareFallbackArgb32):
        (tst_WebGlPerformance::benchSoftwareFallbackArgb32Premultiplied):
        (tst_WebGlPerformance::benchmarkFrameRenderingOnImage):
        * tests/benchmarks/webgl/tst_webgl.qrc: Added.
        * tests/benchmarks/webgl/webgl.pro: Added.
        * tests/qgraphicswebview/qgraphicswebview.pro:
        * tests/qgraphicswebview/resources/pointing_right.html: Added.
        * tests/qgraphicswebview/resources/pointing_up.html: Added.
        * tests/qgraphicswebview/tst_qgraphicswebview.cpp:
        (compareImagesFuzzyPixelCount):
        (GraphicsView::GraphicsView):
        (tst_QGraphicsWebView::webglSoftwareFallbackVerticalOrientation):
        (tst_QGraphicsWebView::webglSoftwareFallbackHorizontalOrientation):
        (tst_QGraphicsWebView::compareCanvasToImage):
        * tests/qgraphicswebview/tst_qgraphicswebview.qrc:
        * tests/tests.pro:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsqtGraphicsContext3DQtcpp">trunk/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp</a></li>
<li><a href="#trunkSourceWebKitqtChangeLog">trunk/Source/WebKit/qt/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitqttestsqgraphicswebviewqgraphicswebviewpro">trunk/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro</a></li>
<li><a href="#trunkSourceWebKitqttestsqgraphicswebviewtst_qgraphicswebviewcpp">trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp</a></li>
<li><a href="#trunkSourceWebKitqttestsqgraphicswebviewtst_qgraphicswebviewqrc">trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc</a></li>
<li><a href="#trunkSourceWebKitqtteststestspro">trunk/Source/WebKit/qt/tests/tests.pro</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/Source/WebKit/qt/tests/benchmarks/webgl/</li>
<li><a href="#trunkSourceWebKitqttestsbenchmarkswebgl10000_triangleshtml">trunk/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html</a></li>
<li><a href="#trunkSourceWebKitqttestsbenchmarkswebgltst_webglcpp">trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp</a></li>
<li><a href="#trunkSourceWebKitqttestsbenchmarkswebgltst_webglqrc">trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc</a></li>
<li><a href="#trunkSourceWebKitqttestsbenchmarkswebglwebglpro">trunk/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro</a></li>
<li><a href="#trunkSourceWebKitqttestsqgraphicswebviewresourcespointing_righthtml">trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html</a></li>
<li><a href="#trunkSourceWebKitqttestsqgraphicswebviewresourcespointing_uphtml">trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebCore/ChangeLog      2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2011-03-24  Benjamin Poulain  <benjamin.poulain@nokia.com>
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        [Qt] When we render WebGL offscreen, color conversion cost a lot of CPU cycles
+        https://bugs.webkit.org/show_bug.cgi?id=40884
+
+        The software fallback is now only needed for corner cases like a manual rendering
+        of the page to QImage.
+
+        Keeping the image with the last pixel values is no longer needed. Removing it reduce the
+        performance for real-time rendering on software surface, but this case should no longer be
+        supported.
+
+        The conversion from OpenGL color space and coordinates is done manually for performance. This
+        also fix the bug of the inverted X axis due to the transformation.
+
+        The tests and benchmarks are done through Qt API tests.
+
+        * platform/graphics/qt/GraphicsContext3DQt.cpp:
+        (WebCore::swapBgrToRgb):
+        (WebCore::GraphicsContext3DInternal::paint):
+        (WebCore::GraphicsContext3D::reshape):
+
</ins><span class="cx"> 2011-03-24  Nat Duca  <nduca@chromium.org>
</span><span class="cx"> 
</span><span class="cx">         Reviewed by James Robinson.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsqtGraphicsContext3DQtcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp        2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp   2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -263,7 +263,6 @@
</span><span class="cx">     GLuint m_mainFbo;
</span><span class="cx">     GLuint m_currentFbo;
</span><span class="cx">     GLuint m_depthBuffer;
</span><del>-    QImage m_pixels;
</del><span class="cx">     bool m_layerComposited;
</span><span class="cx">     ListHashSet<unsigned int> m_syntheticErrors;
</span><span class="cx"> 
</span><span class="lines">@@ -481,6 +480,11 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline quint32 swapBgrToRgb(quint32 pixel)
+{
+    return ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
+}
+
</ins><span class="cx"> void GraphicsContext3DInternal::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
</span><span class="cx"> {
</span><span class="cx">     Q_UNUSED(widget);
</span><span class="lines">@@ -496,11 +500,39 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Alternatively read pixels to a memory buffer.
</span><ins>+    QImage offscreenImage(rect.width(), rect.height(), QImage::Format_ARGB32);
+    quint32* imagePixels = reinterpret_cast<quint32*>(offscreenImage.bits());
+
</ins><span class="cx">     m_glWidget->makeCurrent();
</span><span class="cx">     bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_mainFbo);
</span><del>-    glReadPixels(/* x */ 0, /* y */ 0, rect.width(), rect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, m_pixels.bits());
-    painter->drawImage(/* x */ 0, /* y */ 0, m_pixels.rgbSwapped().transformed(QMatrix().rotate(180)));
</del><ins>+    glReadPixels(/* x */ 0, /* y */ 0, rect.width(), rect.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, imagePixels);
+
</ins><span class="cx">     bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_currentFbo);
</span><ins>+
+    // OpenGL gives us ABGR on 32 bits, and with the origin at the bottom left
+    // We need RGB32 or ARGB32_PM, with the origin at the top left.
+    quint32* pixelsSrc = imagePixels;
+    const int height = static_cast<int>(rect.height());
+    const int width = static_cast<int>(rect.width());
+    const int halfHeight = height / 2;
+    for (int row = 0; row < halfHeight; ++row) {
+        const int targetIdx = (height - 1 - row) * width;
+        quint32* pixelsDst = imagePixels + targetIdx;
+        for (int column = 0; column < width; ++column) {
+            quint32 tempPixel = *pixelsSrc;
+            *pixelsSrc = swapBgrToRgb(*pixelsDst);
+            *pixelsDst = swapBgrToRgb(tempPixel);
+            ++pixelsSrc;
+            ++pixelsDst;
+        }
+    }
+    if (static_cast<int>(height) % 2) {
+        for (int column = 0; column < width; ++column) {
+            *pixelsSrc = swapBgrToRgb(*pixelsSrc);
+            ++pixelsSrc;
+        }
+    }
+    painter->drawImage(/* x */ 0, /* y */ 0, offscreenImage);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> QRectF GraphicsContext3DInternal::boundingRect() const
</span><span class="lines">@@ -590,7 +622,6 @@
</span><span class="cx">     m_currentHeight = height;
</span><span class="cx"> 
</span><span class="cx">     m_internal->m_boundingRect = QRectF(QPointF(0, 0), QSizeF(width, height));
</span><del>-    m_internal->m_pixels = QImage(m_currentWidth, m_currentHeight, QImage::Format_ARGB32);
</del><span class="cx"> 
</span><span class="cx">     m_internal->m_glWidget->makeCurrent();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitqtChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/qt/ChangeLog (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/ChangeLog 2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebKit/qt/ChangeLog    2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -1,3 +1,37 @@
</span><ins>+2011-03-24  Benjamin Poulain  <benjamin.poulain@nokia.com>
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        [Qt] When we render WebGL offscreen, color conversion cost a lot of CPU cycles
+        https://bugs.webkit.org/show_bug.cgi?id=40884
+
+        Add tests and benchmarks for the software fallback of WebGL.
+
+        * tests/benchmarks/webgl/10000_triangles.html: Added.
+        * tests/benchmarks/webgl/tst_webgl.cpp: Added.
+        (GraphicsView::GraphicsView):
+        (GraphicsView::resizeEvent):
+        (tst_WebGlPerformance::init):
+        (tst_WebGlPerformance::cleanup):
+        (tst_WebGlPerformance::benchSoftwareFallbackRgb16):
+        (tst_WebGlPerformance::benchSoftwareFallbackRgb32):
+        (tst_WebGlPerformance::benchSoftwareFallbackArgb32):
+        (tst_WebGlPerformance::benchSoftwareFallbackArgb32Premultiplied):
+        (tst_WebGlPerformance::benchmarkFrameRenderingOnImage):
+        * tests/benchmarks/webgl/tst_webgl.qrc: Added.
+        * tests/benchmarks/webgl/webgl.pro: Added.
+        * tests/qgraphicswebview/qgraphicswebview.pro:
+        * tests/qgraphicswebview/resources/pointing_right.html: Added.
+        * tests/qgraphicswebview/resources/pointing_up.html: Added.
+        * tests/qgraphicswebview/tst_qgraphicswebview.cpp:
+        (compareImagesFuzzyPixelCount):
+        (GraphicsView::GraphicsView):
+        (tst_QGraphicsWebView::webglSoftwareFallbackVerticalOrientation):
+        (tst_QGraphicsWebView::webglSoftwareFallbackHorizontalOrientation):
+        (tst_QGraphicsWebView::compareCanvasToImage):
+        * tests/qgraphicswebview/tst_qgraphicswebview.qrc:
+        * tests/tests.pro:
+
</ins><span class="cx"> 2011-03-24  Kristian Amlie  <kristian.amlie@nokia.com>
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Benjamin Poulain.
</span></span></pre></div>
<a id="trunkSourceWebKitqttestsbenchmarkswebgl10000_triangleshtml"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html (0 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html                               (rev 0)
+++ trunk/Source/WebKit/qt/tests/benchmarks/webgl/10000_triangles.html  2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+<html>
+  <body style="margin: 0">
+    <canvas width="1000" height="1000"></canvas>
+  </body>
+</html>
+<script>
+    var canvas = document.getElementsByTagName("canvas")[0];
+    gl = canvas.getContext("experimental-webgl");
+    gl.clearColor(0.0, 1.0, 0.0, 1.0);
+    gl.viewport(0, 0, canvas.width, canvas.height);
+
+    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vertexShader, "attribute vec4 vPosition;\nvoid main() { gl_Position = vPosition; }");
+    gl.compileShader(vertexShader);
+
+    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fragmentShader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+    gl.compileShader(fragmentShader);
+
+    var shaderProgram = gl.createProgram();
+    gl.attachShader(shaderProgram, vertexShader);
+    gl.attachShader(shaderProgram, fragmentShader);
+    gl.bindAttribLocation(shaderProgram, 0, "vPosition");
+    gl.linkProgram(shaderProgram);
+
+    gl.useProgram(shaderProgram);
+
+    var buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+    var vertices = [];
+    var seedX = -1.0;
+    var seedY = 1.0;
+    for (var i = 1; i <= 10000; ++i) {
+        vertices.push(seedX);
+        vertices.push(seedY);
+        vertices.push(0);
+        seedX += 0.01;
+        vertices.push(seedX);
+        vertices.push(seedY - 0.02);
+        vertices.push(0);
+        seedX += 0.01;
+        vertices.push(seedX);
+        vertices.push(seedY);
+        vertices.push(0);
+        if (!(i % 100)) {
+            seedX = -1.0;
+            seedY -= 0.02;
+        }
+    }
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+
+    gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
+    gl.enableVertexAttribArray(0);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    gl.drawArrays(gl.TRIANGLES, 0, 30000);
+    gl.flush();
+</script>
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsbenchmarkswebgltst_webglcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp (0 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp                              (rev 0)
+++ trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.cpp 2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -0,0 +1,130 @@
</span><ins>+/*
+    Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+
+#include "../../util.h"
+#include <QGLWidget>
+#include <QGraphicsView>
+#include <QGraphicsWebView>
+#include <QScopedPointer>
+#include <QWebFrame>
+#include <QtTest/QtTest>
+
+class GraphicsView;
+
+class tst_WebGlPerformance : public QObject {
+    Q_OBJECT
+
+private slots:
+    void init();
+    void cleanup();
+
+    void benchSoftwareFallbackRgb16();
+    void benchSoftwareFallbackRgb32();
+    void benchSoftwareFallbackArgb32();
+    void benchSoftwareFallbackArgb32Premultiplied();
+
+private:
+    void benchmarkFrameRenderingOnImage(QImage::Format);
+
+    QScopedPointer<GraphicsView> m_view;
+};
+
+class GraphicsView : public QGraphicsView {
+public:
+    GraphicsView();
+    QGraphicsWebView* m_webView;
+
+protected:
+    void resizeEvent(QResizeEvent*);
+};
+
+GraphicsView::GraphicsView()
+{
+    QGraphicsScene* const scene = new QGraphicsScene(this);
+    setScene(scene);
+
+    m_webView = new QGraphicsWebView;
+    scene->addItem(m_webView);
+
+    m_webView->page()->settings()->setAttribute(QWebSettings::WebGLEnabled, true);
+
+    resize(800, 600);
+    setFrameShape(QFrame::NoFrame);
+    setViewport(new QGLWidget);
+}
+
+void GraphicsView::resizeEvent(QResizeEvent* event)
+{
+    QGraphicsView::resizeEvent(event);
+    QRectF rect(QPoint(0, 0), event->size());
+    m_webView->setGeometry(rect);
+    scene()->setSceneRect(rect);
+}
+
+void tst_WebGlPerformance::init()
+{
+    m_view.reset(new GraphicsView);
+    m_view->showMaximized();
+    QTest::qWaitForWindowShown(m_view.data());
+}
+
+void tst_WebGlPerformance::cleanup()
+{
+    m_view.reset();
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackRgb16()
+{
+    benchmarkFrameRenderingOnImage(QImage::Format_RGB16);
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackRgb32()
+{
+    benchmarkFrameRenderingOnImage(QImage::Format_RGB32);
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackArgb32()
+{
+    benchmarkFrameRenderingOnImage(QImage::Format_ARGB32);
+}
+
+void tst_WebGlPerformance::benchSoftwareFallbackArgb32Premultiplied()
+{
+    benchmarkFrameRenderingOnImage(QImage::Format_ARGB32_Premultiplied);
+}
+
+void tst_WebGlPerformance::benchmarkFrameRenderingOnImage(QImage::Format format)
+{
+    m_view->m_webView->load(QUrl(QLatin1String("qrc:///testcases/10000_triangles.html")));
+    const bool pageLoaded = waitForSignal(m_view->m_webView, SIGNAL(loadFinished(bool)));
+    Q_ASSERT(pageLoaded);
+    Q_UNUSED(pageLoaded);
+
+    QImage target(m_view->size(), format);
+    QBENCHMARK {
+        QPainter painter(&target);
+        m_view->render(&painter);
+        painter.end();
+    }
+}
+
+QTEST_MAIN(tst_WebGlPerformance)
+
+#include "tst_webgl.moc"
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsbenchmarkswebgltst_webglqrc"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc (0 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc                              (rev 0)
+++ trunk/Source/WebKit/qt/tests/benchmarks/webgl/tst_webgl.qrc 2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+<RCC>
+    <qresource prefix="/testcases">
+        <file>10000_triangles.html</file>
+    </qresource>
+</RCC>
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsbenchmarkswebglwebglpro"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro (0 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro                          (rev 0)
+++ trunk/Source/WebKit/qt/tests/benchmarks/webgl/webgl.pro     2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../../..
+include(../../tests.pri)
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
+QT += opengl
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsqgraphicswebviewqgraphicswebviewpro"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro       2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebKit/qt/tests/qgraphicswebview/qgraphicswebview.pro  2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -1,3 +1,6 @@
</span><span class="cx"> isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
</span><span class="cx"> include(../tests.pri)
</span><span class="cx"> exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
</span><ins>+contains(DEFINES, ENABLE_WEBGL=1) {
+    QT += opengl
+}
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsqgraphicswebviewresourcespointing_righthtml"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html (0 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html                              (rev 0)
+++ trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_right.html 2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+<html>
+  <body style="margin: 0">
+    <canvas width="100" height="100"></canvas>
+  </body>
+</html>
+<script>
+    var canvas = document.getElementsByTagName("canvas")[0];
+    gl = canvas.getContext("experimental-webgl");
+    gl.clearColor(0.0, 1.0, 0.0, 1.0);
+    gl.viewport(0, 0, canvas.width, canvas.height);
+
+    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vertexShader, "attribute vec4 vPosition;\nvoid main() { gl_Position = vPosition; }");
+    gl.compileShader(vertexShader);
+
+    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fragmentShader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+    gl.compileShader(fragmentShader);
+
+    var shaderProgram = gl.createProgram();
+    gl.attachShader(shaderProgram, vertexShader);
+    gl.attachShader(shaderProgram, fragmentShader);
+    gl.bindAttribLocation(shaderProgram, 0, "vPosition");
+    gl.linkProgram(shaderProgram);
+
+    gl.useProgram(shaderProgram);
+
+    var buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+    var vertices = [-1.0, -1.0,
+                    0.0, 0.0,
+                    -1.0, 1.0];
+    var seedX = -1.0;
+    var seedY = 1.0;
+    vertices
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+
+    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+    gl.enableVertexAttribArray(0);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+    gl.flush();
+</script>
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsqgraphicswebviewresourcespointing_uphtml"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html (0 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html                         (rev 0)
+++ trunk/Source/WebKit/qt/tests/qgraphicswebview/resources/pointing_up.html    2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+<html>
+  <body style="margin: 0">
+    <canvas width="100" height="100"></canvas>
+  </body>
+</html>
+<script>
+    var canvas = document.getElementsByTagName("canvas")[0];
+    gl = canvas.getContext("experimental-webgl");
+    gl.clearColor(0.0, 1.0, 0.0, 1.0);
+    gl.viewport(0, 0, canvas.width, canvas.height);
+
+    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+    gl.shaderSource(vertexShader, "attribute vec4 vPosition;\nvoid main() { gl_Position = vPosition; }");
+    gl.compileShader(vertexShader);
+
+    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fragmentShader, "void main() { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }");
+    gl.compileShader(fragmentShader);
+
+    var shaderProgram = gl.createProgram();
+    gl.attachShader(shaderProgram, vertexShader);
+    gl.attachShader(shaderProgram, fragmentShader);
+    gl.bindAttribLocation(shaderProgram, 0, "vPosition");
+    gl.linkProgram(shaderProgram);
+
+    gl.useProgram(shaderProgram);
+
+    var buffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+
+    var vertices = [-1.0, -1.0,
+                    0.0, 0.0,
+                    1.0, -1.0];
+    var seedX = -1.0;
+    var seedY = 1.0;
+    vertices
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+
+    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+    gl.enableVertexAttribArray(0);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+    gl.drawArrays(gl.TRIANGLES, 0, 3);
+    gl.flush();
+    gl.finish();
+</script>
</ins></span></pre></div>
<a id="trunkSourceWebKitqttestsqgraphicswebviewtst_qgraphicswebviewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp   2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.cpp      2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -25,6 +25,10 @@
</span><span class="cx"> #include <qwebpage.h>
</span><span class="cx"> #include <qwebframe.h>
</span><span class="cx"> 
</span><ins>+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+#include <QGLWidget>
+#endif
+
</ins><span class="cx"> class tst_QGraphicsWebView : public QObject
</span><span class="cx"> {
</span><span class="cx">     Q_OBJECT
</span><span class="lines">@@ -39,6 +43,14 @@
</span><span class="cx">     void setPalette_data();
</span><span class="cx">     void setPalette();
</span><span class="cx">     void renderHints();
</span><ins>+
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+    void webglSoftwareFallbackVerticalOrientation();
+    void webglSoftwareFallbackHorizontalOrientation();
+
+private:
+    void compareCanvasToImage(const QUrl&, const QImage&);
+#endif
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> void tst_QGraphicsWebView::qgraphicswebview()
</span><span class="lines">@@ -444,6 +456,112 @@
</span><span class="cx">     QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+class GraphicsView : public QGraphicsView {
+public:
+    GraphicsView();
+    QGraphicsWebView* m_webView;
+};
+
+#if defined(ENABLE_WEBGL) && ENABLE_WEBGL
+bool compareImagesFuzzyPixelCount(const QImage& image1, const QImage& image2, qreal tolerance = 0.05)
+{
+    if (image1.size() != image2.size())
+        return false;
+
+    unsigned diffPixelCount = 0;
+    for (int row = 0; row < image1.size().width(); ++row) {
+        for (int column = 0; column < image1.size().height(); ++column)
+            if (image1.pixel(row, column) != image2.pixel(row, column))
+                ++diffPixelCount;
+    }
+
+    if (diffPixelCount > (image1.size().width() * image1.size().height()) * tolerance)
+        return false;
+
+    return true;
+}
+
+GraphicsView::GraphicsView()
+{
+    QGraphicsScene* const scene = new QGraphicsScene(this);
+    setScene(scene);
+
+    m_webView = new QGraphicsWebView;
+    scene->addItem(m_webView);
+
+    m_webView->page()->settings()->setAttribute(QWebSettings::WebGLEnabled, true);
+    m_webView->setResizesToContents(true);
+
+    setFrameShape(QFrame::NoFrame);
+    setViewport(new QGLWidget);
+}
+
+void tst_QGraphicsWebView::webglSoftwareFallbackVerticalOrientation()
+{
+    QSize canvasSize(100, 100);
+    QImage reference(canvasSize, QImage::Format_ARGB32);
+    reference.fill(0xFF00FF00);
+    { // Reference.
+        QPainter painter(&reference);
+        QPolygonF triangleUp;
+        triangleUp << QPointF(0, canvasSize.height())
+                   << QPointF(canvasSize.width(), canvasSize.height())
+                   << QPointF(canvasSize.width() / 2.0, canvasSize.height() / 2.0);
+        painter.setPen(Qt::NoPen);
+        painter.setBrush(Qt::red);
+        painter.drawPolygon(triangleUp);
+    }
+
+    compareCanvasToImage(QUrl(QLatin1String("qrc:///resources/pointing_up.html")), reference);
+}
+
+void tst_QGraphicsWebView::webglSoftwareFallbackHorizontalOrientation()
+{
+    QSize canvasSize(100, 100);
+    QImage reference(canvasSize, QImage::Format_ARGB32);
+    reference.fill(0xFF00FF00);
+    { // Reference.
+        QPainter painter(&reference);
+        QPolygonF triangleUp;
+        triangleUp << QPointF(0, 0)
+                   << QPointF(0, canvasSize.height())
+                   << QPointF(canvasSize.width() / 2.0, canvasSize.height() / 2.0);
+        painter.setPen(Qt::NoPen);
+        painter.setBrush(Qt::red);
+        painter.drawPolygon(triangleUp);
+    }
+
+    compareCanvasToImage(QUrl(QLatin1String("qrc:///resources/pointing_right.html")), reference);
+}
+
+void tst_QGraphicsWebView::compareCanvasToImage(const QUrl& url, const QImage& reference)
+{
+    GraphicsView view;
+    view.show();
+    QTest::qWaitForWindowShown(&view);
+
+    QGraphicsWebView* const graphicsWebView = view.m_webView;
+    graphicsWebView->load(url);
+    QVERIFY(waitForSignal(graphicsWebView, SIGNAL(loadFinished(bool))));
+    { // Force a render, to create the accelerated compositing tree.
+        QPixmap pixmap(view.size());
+        QPainter painter(&pixmap);
+        view.render(&painter);
+    }
+    QApplication::syncX();
+
+    const QSize imageSize = reference.size();
+
+    QImage target(imageSize, QImage::Format_ARGB32);
+    { // Web page content.
+        QPainter painter(&target);
+        QRectF renderRect(0, 0, imageSize.width(), imageSize.height());
+        view.scene()->render(&painter, renderRect, renderRect);
+    }
+    QVERIFY(compareImagesFuzzyPixelCount(target, reference, 0.01));
+}
+#endif
+
</ins><span class="cx"> QTEST_MAIN(tst_QGraphicsWebView)
</span><span class="cx"> 
</span><span class="cx"> #include "tst_qgraphicswebview.moc"
</span></span></pre></div>
<a id="trunkSourceWebKitqttestsqgraphicswebviewtst_qgraphicswebviewqrc"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc   2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebKit/qt/tests/qgraphicswebview/tst_qgraphicswebview.qrc      2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -1,6 +1,7 @@
</span><del>-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
-    <file>resources/input_types.html</file>
-</qresource>
</del><ins>+<RCC>
+    <qresource prefix="/">
+        <file>resources/input_types.html</file>
+        <file>resources/pointing_right.html</file>
+        <file>resources/pointing_up.html</file>
+    </qresource>
</ins><span class="cx"> </RCC>
</span><del>-
</del></span></pre></div>
<a id="trunkSourceWebKitqtteststestspro"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/qt/tests/tests.pro (81885 => 81886)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/qt/tests/tests.pro   2011-03-24 19:30:38 UTC (rev 81885)
+++ trunk/Source/WebKit/qt/tests/tests.pro      2011-03-24 19:34:51 UTC (rev 81886)
</span><span class="lines">@@ -3,3 +3,6 @@
</span><span class="cx"> SUBDIRS = qwebframe qwebpage qwebelement qgraphicswebview qwebhistoryinterface qwebview qwebhistory qwebinspector hybridPixmap
</span><span class="cx"> contains(QT_CONFIG, declarative): SUBDIRS += qdeclarativewebview
</span><span class="cx"> SUBDIRS += benchmarks/painting benchmarks/loading
</span><ins>+contains(DEFINES, ENABLE_WEBGL=1) {
+    SUBDIRS += benchmarks/webgl
+}
</ins></span></pre>
</div>
</div>

</body>
</html>