Canvas/GLES/Wayland: Use a textured gl surface to represent a 2D canvas. 56/12656/2
authorZhigang Gong <zhigang.gong@intel.com>
Wed, 16 Oct 2013 09:48:52 +0000 (17:48 +0800)
committerJoone Hur <joone.hur@intel.com>
Thu, 21 Nov 2013 05:43:45 +0000 (21:43 -0800)
Actually, the 2D canvas is required to be shared between the WebProcess
and the UIProcess. On X platform, it's naturally implemented by the
global PIXMAP ID. On the other hand, it becomes different under Wayland.
It uses an EGL window buffer, which is indeed a double buffer. Each time
it  calls eglSwapBuffer, the UIProcess can get the correct buffer to be
used for the rest compositing.

However, it causes the following problem:
1. All canvases are created from EGL surfaces. The type of
those surfaces can't be treated as a source to render to other surface.
So it is very expensive (more than 10x slow) when we copy one canvas to
another.

2. Sometimes, for a static canvas, we only paint once in the WebProcess
, but may share it with the UIProcess several times.
Then, when we call eglSwapBuffers at the even time, we just pass the
wrong buffer to the UIProcess.

The ideal solution is to find another clean way to share buffers
on wayland platform rather than use this way. Before that, this
patch implemented a trade off solution to fix the above problem
partly, because it uses two cairo gl surface to represent one canvas:
the first is a pure gl surface for texture and the second is an EGL gl
surface. We do all canvas related painting on the first gl
surface thus we can avoid the first problem. And then, every time
we need to share the canvas to the UIProcess, we leverage cairo
to paint the first gl surface to the second EGL gl surface,
thus we always pass the correct content to the UIProcess. The side
effect is that we introduce one more copy and we use the required
gpu memory two times. The one more copy is not expensive, because
we do it on GPU side.

This solution could just solve the problem partly. As one big assumption
of this solution is that the WebProcess never use the rendering result
from the UIProcess.

After this patch, GUIMARK3 cache version and Penguin works fine.

Change-Id: Ie4b49e7190f241669332d296ab831a773df5ad1a
Signed-off-by: Zhigang Gong <zhigang.gong@intel.com>
Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
Source/WebCore/platform/graphics/cairo/ImageBufferDataCairo.h

index 7ba49d0..d8a2927 100755 (executable)
@@ -171,18 +171,38 @@ ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, Color
 #if ENABLE(TIZEN_CANVAS_CAIRO_GLES_RENDERING)
     if (m_isLockable || renderingMode == Unaccelerated)
         m_data.m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height());
-    else
-        m_data.m_surface = cairo_gl_surface_create_for_egl(static_cast<cairo_device_t*>(g_sharedCairoDevice), m_offScreenSurface->drawable(), size.width(), size.height());
+    else {
+#if PLATFORM(WAYLAND)
+       // FIXME: On Wayland platform, we cannot simply share a single buffer (like pixmap)
+       // with the UI process. We have to use one gl surface for texture to represent the
+       // canvas content. Then, when we need to share it with the web process
+       // (at swapPlatformSurfaces), we copy it to the shared window buffer. This is inefficient
+       // indeed, but this is the only way to fix some weird issues when we use a double buffer
+       // window as a single pixmap.
+        m_data.m_surface = cairo_gl_surface_create(static_cast<cairo_device_t*>(g_sharedCairoDevice),
+                                                   CAIRO_CONTENT_COLOR_ALPHA, size.width(), size.height());
+        if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS)
+            return;
+        m_data.m_shared_surface = cairo_gl_surface_create_for_egl(static_cast<cairo_device_t*>(g_sharedCairoDevice),
+                                                                  m_offScreenSurface->drawable(), size.width(), size.height());
+        if (cairo_surface_status(m_data.m_shared_surface) != CAIRO_STATUS_SUCCESS) {
+#if ENABLE(TIZEN_DLOG_SUPPORT)
+            TIZEN_LOGE("cairo_gl_surface_create_for_egl() failed!\n");
+#endif
+            cairo_surface_destroy(m_data.m_surface);
+            m_data.m_surface = NULL;
+        }
+#else
+        m_data.m_surface = cairo_gl_surface_create_for_egl(static_cast<cairo_device_t*>(g_sharedCairoDevice),
+                                                           m_offScreenSurface->drawable(), size.width(), size.height());
+#endif
+    }
 #else
     m_data.m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), size.height());
 #endif
 
-    if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS) {
-#if ENABLE(TIZEN_DLOG_SUPPORT)
-        TIZEN_LOGE("cairo_gl_surface_create_for_egl() failed!\n");
-#endif
+    if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS)
         return;  // create will notice we didn't set m_initialized and fail.
-    }
 
     RefPtr<cairo_t> cr = adoptRef(cairo_create(m_data.m_surface));
     m_data.m_platformContext.setCr(cr.get());
@@ -222,17 +242,31 @@ ImageBuffer::~ImageBuffer()
             glFlush();
         }
 #endif
+
+#if PLATFORM(WAYLAND)
+        if (m_data.m_shared_surface)
+            cairo_surface_destroy(m_data.m_shared_surface);
+#endif
         destroy();
     }
 #endif
 
-    cairo_surface_destroy(m_data.m_surface);
+    if (m_data.m_surface)
+        cairo_surface_destroy(m_data.m_surface);
 }
 
 #if ENABLE(TIZEN_CANVAS_CAIRO_GLES_RENDERING) || ENABLE(TIZEN_CANVAS_SURFACE_LOCKING)
 void ImageBuffer::swapPlatformSurfaces()
 {
 #if PLATFORM(WAYLAND)
+    cairo_t *cr = cairo_create(m_data.m_shared_surface);
+    cairo_set_source_surface(cr, m_data.m_surface, 0, 0);
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint(cr);
+    cairo_destroy(cr);
+    cairo_surface_flush(m_data.m_shared_surface);
+    glFlush();
+
     m_offScreenContext->makeCurrent(m_offScreenSurface.get());
     m_offScreenSurface->swapBuffers();
 #else
index 5ca7262..9980e25 100644 (file)
@@ -36,6 +36,9 @@ public:
     ImageBufferData(const IntSize&);
 
     cairo_surface_t* m_surface;
+#if PLATFORM(WAYLAND)
+    cairo_surface_t* m_shared_surface;
+#endif
     PlatformContextCairo m_platformContext;
 };