<!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>[193748] trunk/Source/WebCore</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/193748">193748</a></dd>
<dt>Author</dt> <dd>yoon@igalia.com</dd>
<dt>Date</dt> <dd>2015-12-08 06:20:28 -0800 (Tue, 08 Dec 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ThreadedCompositor] Add support for Cairo GL-backed ImageBuffer.
https://bugs.webkit.org/show_bug.cgi?id=151986

Reviewed by Žan Doberšek.

This patch adds a support for accelerated 2d canvas which uses cairo-gl as its
backend to the threaded compositor. Basically, it applies same way to support
WebGL for the threaded compositor.

Unfortunately, we cannot swap the buffer for the accelerated 2d canvas because
it should preserve the buffer of the previous frame when drawing new contents.
Because of that, the surface of the accelerated 2d canvas will be copied for
each frame.

* platform/graphics/cairo/ImageBufferCairo.cpp:
(WebCore::ImageBufferData::ImageBufferData):
(WebCore::ImageBufferData::createCompositorBuffer): Prepare a texture
surface to push the rendered result to the compositing thread.
(WebCore::ImageBufferData::swapBuffersIfNeeded): Copies the contents
of the canvas's surface to the compositing texture.
(WebCore::ImageBufferData::createCairoGLSurface): Moved to the inside
of ImageBufferData.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscairoImageBufferCairocpp">trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscairoImageBufferDataCairoh">trunk/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (193747 => 193748)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-12-08 11:18:12 UTC (rev 193747)
+++ trunk/Source/WebCore/ChangeLog        2015-12-08 14:20:28 UTC (rev 193748)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2015-12-08  Gwang Yoon Hwang  &lt;yoon@igalia.com&gt;
+
+        [ThreadedCompositor] Add support for Cairo GL-backed ImageBuffer.
+        https://bugs.webkit.org/show_bug.cgi?id=151986
+
+        Reviewed by Žan Doberšek.
+
+        This patch adds a support for accelerated 2d canvas which uses cairo-gl as its
+        backend to the threaded compositor. Basically, it applies same way to support
+        WebGL for the threaded compositor.
+
+        Unfortunately, we cannot swap the buffer for the accelerated 2d canvas because
+        it should preserve the buffer of the previous frame when drawing new contents.
+        Because of that, the surface of the accelerated 2d canvas will be copied for
+        each frame.
+
+        * platform/graphics/cairo/ImageBufferCairo.cpp:
+        (WebCore::ImageBufferData::ImageBufferData):
+        (WebCore::ImageBufferData::createCompositorBuffer): Prepare a texture
+        surface to push the rendered result to the compositing thread.
+        (WebCore::ImageBufferData::swapBuffersIfNeeded): Copies the contents
+        of the canvas's surface to the compositing texture.
+        (WebCore::ImageBufferData::createCairoGLSurface): Moved to the inside
+        of ImageBufferData.
+
</ins><span class="cx"> 2015-12-08  Joanmarie Diggs  &lt;jdiggs@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] 15 accessibility tests fail since r186692.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscairoImageBufferCairocpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp (193747 => 193748)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp        2015-12-08 11:18:12 UTC (rev 193747)
+++ trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp        2015-12-08 14:20:28 UTC (rev 193748)
</span><span class="lines">@@ -53,6 +53,7 @@
</span><span class="cx"> #include &quot;TextureMapperGL.h&quot;
</span><span class="cx"> #include &lt;cairo-gl.h&gt;
</span><span class="cx"> #if USE(COORDINATED_GRAPHICS_THREADED)
</span><ins>+#include &quot;TextureMapperPlatformLayerBuffer.h&quot;
</ins><span class="cx"> #include &quot;TextureMapperPlatformLayerProxy.h&quot;
</span><span class="cx"> #endif
</span><span class="cx"> #endif
</span><span class="lines">@@ -65,12 +66,58 @@
</span><span class="cx">     : m_platformContext(0)
</span><span class="cx">     , m_size(size)
</span><span class="cx"> #if ENABLE(ACCELERATED_2D_CANVAS)
</span><ins>+#if USE(COORDINATED_GRAPHICS_THREADED)
+    , m_platformLayerProxy(adoptRef(new TextureMapperPlatformLayerProxy))
+    , m_compositorTexture(0)
+#endif
</ins><span class="cx">     , m_texture(0)
</span><span class="cx"> #endif
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ACCELERATED_2D_CANVAS)
</span><ins>+#if USE(COORDINATED_GRAPHICS_THREADED)
+void ImageBufferData::createCompositorBuffer()
+{
+    GLContext::sharingContext()-&gt;makeContextCurrent();
+
+    glGenTextures(1, &amp;m_compositorTexture);
+    glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glTexImage2D(GL_TEXTURE_2D, 0 , GL_RGBA, m_size.width(), m_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+    cairo_device_t* device = GLContext::sharingContext()-&gt;cairoDevice();
+    m_compositorSurface = adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, m_compositorTexture, m_size.width(), m_size.height()));
+    m_compositorCr = adoptRef(cairo_create(m_compositorSurface.get()));
+    cairo_set_antialias(m_compositorCr.get(), CAIRO_ANTIALIAS_NONE);
+}
+
+void ImageBufferData::swapBuffersIfNeeded()
+{
+    GLContext* previousActiveContext = GLContext::getCurrent();
+
+    if (!m_compositorTexture) {
+        createCompositorBuffer();
+        LockHolder holder(m_platformLayerProxy-&gt;lock());
+        m_platformLayerProxy-&gt;pushNextBuffer(std::make_unique&lt;TextureMapperPlatformLayerBuffer&gt;(m_compositorTexture, m_size, TextureMapperGL::ShouldBlend));
+    }
+
+    // It would be great if we could just swap the buffers here as we do with webgl, but that breaks the cases
+    // where one frame uses the content already rendered in the previous frame. So we just copy the content
+    // into the compositor buffer.
+    cairo_set_source_surface(m_compositorCr.get(), m_surface.get(), 0, 0);
+    cairo_set_operator(m_compositorCr.get(), CAIRO_OPERATOR_SOURCE);
+    cairo_paint(m_compositorCr.get());
+
+    if (previousActiveContext)
+        previousActiveContext-&gt;makeContextCurrent();
+}
+#endif
+
</ins><span class="cx"> void clearSurface(cairo_surface_t* surface)
</span><span class="cx"> {
</span><span class="cx">     if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
</span><span class="lines">@@ -81,14 +128,14 @@
</span><span class="cx">     cairo_paint(cr.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-PassRefPtr&lt;cairo_surface_t&gt; createCairoGLSurface(const FloatSize&amp; size, uint32_t&amp; texture)
</del><ins>+void ImageBufferData::createCairoGLSurface()
</ins><span class="cx"> {
</span><span class="cx">     GLContext::sharingContext()-&gt;makeContextCurrent();
</span><span class="cx"> 
</span><span class="cx">     // We must generate the texture ourselves, because there is no Cairo API for extracting it
</span><span class="cx">     // from a pre-existing surface.
</span><del>-    glGenTextures(1, &amp;texture);
-    glBindTexture(GL_TEXTURE_2D, texture);
</del><ins>+    glGenTextures(1, &amp;m_texture);
+    glBindTexture(GL_TEXTURE_2D, m_texture);
</ins><span class="cx">     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
</span><span class="cx">     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
</span><span class="cx">     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
</span><span class="lines">@@ -96,7 +143,7 @@
</span><span class="cx"> 
</span><span class="cx">     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
</span><span class="cx"> 
</span><del>-    glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA8, size.width(), size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0);
</del><ins>+    glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, m_size.width(), m_size.height(), 0 /* border */, GL_RGBA, GL_UNSIGNED_BYTE, 0);
</ins><span class="cx"> 
</span><span class="cx">     GLContext* context = GLContext::sharingContext();
</span><span class="cx">     cairo_device_t* device = context-&gt;cairoDevice();
</span><span class="lines">@@ -104,9 +151,8 @@
</span><span class="cx">     // Thread-awareness is a huge performance hit on non-Intel drivers.
</span><span class="cx">     cairo_gl_device_set_thread_aware(device, FALSE);
</span><span class="cx"> 
</span><del>-    auto surface = adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, texture, size.width(), size.height()));
-    clearSurface(surface.get());
-    return surface;
</del><ins>+    m_surface = adoptRef(cairo_gl_surface_create_for_texture(device, CAIRO_CONTENT_COLOR_ALPHA, m_texture, m_size.width(), m_size.height()));
+    clearSurface(m_surface.get());
</ins><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -121,7 +167,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ACCELERATED_2D_CANVAS)
</span><span class="cx">     if (renderingMode == Accelerated) {
</span><del>-        m_data.m_surface = createCairoGLSurface(size, m_data.m_texture);
</del><ins>+        m_data.createCairoGLSurface();
</ins><span class="cx">         if (!m_data.m_surface || cairo_surface_status(m_data.m_surface.get()) != CAIRO_STATUS_SUCCESS)
</span><span class="cx">             renderingMode = Unaccelerated; // If allocation fails, fall back to non-accelerated path.
</span><span class="cx">     }
</span><span class="lines">@@ -411,14 +457,7 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-#if ENABLE(ACCELERATED_2D_CANVAS)
-#if USE(COORDINATED_GRAPHICS_THREADED)
-RefPtr&lt;TextureMapperPlatformLayerProxy&gt; ImageBufferData::proxy() const
-{
-    notImplemented();
-    return nullptr;
-}
-#else
</del><ins>+#if ENABLE(ACCELERATED_2D_CANVAS) &amp;&amp; !USE(COORDINATED_GRAPHICS_THREADED)
</ins><span class="cx"> void ImageBufferData::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect&amp; targetRect, const TransformationMatrix&amp; matrix, float opacity)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_texture);
</span><span class="lines">@@ -431,7 +470,6 @@
</span><span class="cx">     static_cast&lt;TextureMapperGL*&gt;(textureMapper)-&gt;drawTexture(m_texture, TextureMapperGL::ShouldBlend, m_size, targetRect, matrix, opacity);
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx"> PlatformLayer* ImageBuffer::platformLayer() const
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscairoImageBufferDataCairoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h (193747 => 193748)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h        2015-12-08 11:18:12 UTC (rev 193747)
+++ trunk/Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h        2015-12-08 14:20:28 UTC (rev 193748)
</span><span class="lines">@@ -62,9 +62,17 @@
</span><span class="cx">     IntSize m_size;
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ACCELERATED_2D_CANVAS)
</span><ins>+    void createCairoGLSurface();
+
</ins><span class="cx"> #if USE(COORDINATED_GRAPHICS_THREADED)
</span><del>-    virtual RefPtr&lt;TextureMapperPlatformLayerProxy&gt; proxy() const override;
-    virtual void swapBuffersIfNeeded() override { };
</del><ins>+    virtual RefPtr&lt;TextureMapperPlatformLayerProxy&gt; proxy() const override { return m_platformLayerProxy.copyRef(); }
+    virtual void swapBuffersIfNeeded() override;
+    void createCompositorBuffer();
+
+    RefPtr&lt;TextureMapperPlatformLayerProxy&gt; m_platformLayerProxy;
+    RefPtr&lt;cairo_surface_t&gt; m_compositorSurface;
+    uint32_t m_compositorTexture;
+    RefPtr&lt;cairo_t&gt; m_compositorCr;
</ins><span class="cx"> #else
</span><span class="cx">     virtual void paintToTextureMapper(TextureMapper*, const FloatRect&amp; target, const TransformationMatrix&amp;, float opacity);
</span><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>