Modified: trunk/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreWayland.cpp (264167 => 264168)
--- trunk/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreWayland.cpp 2020-07-09 14:02:14 UTC (rev 264167)
+++ trunk/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreWayland.cpp 2020-07-09 14:10:06 UTC (rev 264168)
@@ -51,6 +51,10 @@
#if USE(WPE_RENDERER)
#include <wpe/fdo-egl.h>
+#if WPE_FDO_CHECK_VERSION(1, 7, 0)
+#include <wayland-server.h>
+#include <wpe/unstable/fdo-shm.h>
+#endif
#else
#include "WaylandCompositor.h"
#endif
@@ -66,7 +70,11 @@
namespace WebKit {
using namespace WebCore;
-bool isEGLImageAvailable(bool useIndexedGetString)
+enum class WaylandImpl { Unsupported, EGL, SHM };
+static Optional<WaylandImpl> s_waylandImpl;
+
+#if USE(WPE_RENDERER)
+static bool isEGLImageAvailable(bool useIndexedGetString)
{
#if USE(OPENGL_ES)
UNUSED_PARAM(useIndexedGetString);
@@ -92,42 +100,71 @@
return false;
}
-bool AcceleratedBackingStoreWayland::checkRequirements()
+static bool tryInitializeEGL()
{
-#if USE(WPE_RENDERER)
- if (!glImageTargetTexture2D) {
- auto* eglDisplay = PlatformDisplay::sharedDisplay().eglDisplay();
- const char* extensions = eglQueryString(eglDisplay, EGL_EXTENSIONS);
- if (!GLContext::isExtensionSupported(extensions, "EGL_WL_bind_wayland_display"))
- return false;
+ auto* eglDisplay = PlatformDisplay::sharedDisplay().eglDisplay();
+ const char* extensions = eglQueryString(eglDisplay, EGL_EXTENSIONS);
+ if (!GLContext::isExtensionSupported(extensions, "EGL_WL_bind_wayland_display"))
+ return false;
- if (!wpe_fdo_initialize_for_egl_display(eglDisplay))
- return false;
+ if (!wpe_fdo_initialize_for_egl_display(eglDisplay))
+ return false;
- std::unique_ptr<WebCore::GLContext> eglContext = GLContext::createOffscreenContext();
- if (!eglContext)
- return false;
+ std::unique_ptr<WebCore::GLContext> eglContext = GLContext::createOffscreenContext();
+ if (!eglContext)
+ return false;
- if (!eglContext->makeContextCurrent())
- return false;
+ if (!eglContext->makeContextCurrent())
+ return false;
#if USE(OPENGL_ES)
- if (isEGLImageAvailable(false))
+ if (isEGLImageAvailable(false))
#else
- if (isEGLImageAvailable(GLContext::current()->version() >= 320))
+ if (isEGLImageAvailable(GLContext::current()->version() >= 320))
#endif
- glImageTargetTexture2D = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
- }
+ glImageTargetTexture2D = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
- if (!glImageTargetTexture2D) {
- WTFLogAlways("AcceleratedBackingStoreWPE requires glEGLImageTargetTexture2D.");
+ if (!glImageTargetTexture2D)
return false;
- }
+ s_waylandImpl = WaylandImpl::EGL;
return true;
+}
+
+static bool tryInitializeSHM()
+{
+#if WPE_FDO_CHECK_VERSION(1, 7, 0)
+ if (!wpe_fdo_initialize_shm())
+ return false;
+#endif
+
+ s_waylandImpl = WaylandImpl::SHM;
+ return true;
+}
+#endif // USE(WPE_RENDERER)
+
+bool AcceleratedBackingStoreWayland::checkRequirements()
+{
+#if USE(WPE_RENDERER)
+ if (s_waylandImpl)
+ return s_waylandImpl.value() != WaylandImpl::Unsupported;
+
+ if (tryInitializeEGL())
+ return true;
+
+ if (tryInitializeSHM())
+ return true;
+
+ WTFLogAlways("AcceleratedBackingStoreWayland requires glEGLImageTargetTexture2D or shm interface");
#else
- return WaylandCompositor::singleton().isRunning();
+ if (WaylandCompositor::singleton().isRunning()) {
+ s_waylandImpl = WaylandImpl::EGL;
+ return true;
+ }
#endif
+
+ s_waylandImpl = WaylandImpl::Unsupported;
+ return false;
}
std::unique_ptr<AcceleratedBackingStoreWayland> AcceleratedBackingStoreWayland::create(WebPageProxy& webPage)
@@ -140,20 +177,48 @@
: AcceleratedBackingStore(webPage)
{
#if USE(WPE_RENDERER)
- static struct wpe_view_backend_exportable_fdo_egl_client exportableClient = {
+ static struct wpe_view_backend_exportable_fdo_egl_client exportableEGLClient = {
// export_egl_image
nullptr,
// export_fdo_egl_image
[](void* data, struct wpe_fdo_egl_exported_image* image)
{
- static_cast<AcceleratedBackingStoreWayland*>(data)->displayBuffer(image);
+ static_cast<AcceleratedBackingStoreWayland*>(data)->displayImage(image);
},
// padding
nullptr, nullptr, nullptr
};
+#if WPE_FDO_CHECK_VERSION(1, 7, 0)
+ static struct wpe_view_backend_exportable_fdo_client exportableClient = {
+ nullptr,
+ nullptr,
+ // export_shm_buffer
+ [](void* data, struct wpe_fdo_shm_exported_buffer* buffer)
+ {
+ static_cast<AcceleratedBackingStoreWayland*>(data)->displayBuffer(buffer);
+ },
+ nullptr,
+ nullptr,
+ };
+#endif
+
auto viewSize = webPage.viewSize();
- m_exportable = wpe_view_backend_exportable_fdo_egl_create(&exportableClient, this, viewSize.width(), viewSize.height());
+ switch (s_waylandImpl.value()) {
+ case WaylandImpl::EGL:
+ m_exportable = wpe_view_backend_exportable_fdo_egl_create(&exportableEGLClient, this, viewSize.width(), viewSize.height());
+ break;
+ case WaylandImpl::SHM:
+#if WPE_FDO_CHECK_VERSION(1, 7, 0)
+ m_exportable = wpe_view_backend_exportable_fdo_create(&exportableClient, this, viewSize.width(), viewSize.height());
+ break;
+#else
+ FALLTHROUGH;
+#endif
+ case WaylandImpl::Unsupported:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
wpe_view_backend_initialize(wpe_view_backend_exportable_fdo_get_view_backend(m_exportable));
#else
WaylandCompositor::singleton().registerWebPage(m_webPage);
@@ -163,13 +228,15 @@
AcceleratedBackingStoreWayland::~AcceleratedBackingStoreWayland()
{
#if USE(WPE_RENDERER)
- if (m_pendingImage)
- wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_pendingImage);
- if (m_committedImage)
- wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_committedImage);
- if (m_viewTexture) {
- if (makeContextCurrent())
- glDeleteTextures(1, &m_viewTexture);
+ if (s_waylandImpl.value() == WaylandImpl::EGL) {
+ if (m_egl.pendingImage)
+ wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_egl.pendingImage);
+ if (m_egl.committedImage)
+ wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_egl.committedImage);
+ if (m_egl.viewTexture) {
+ if (makeContextCurrent())
+ glDeleteTextures(1, &m_egl.viewTexture);
+ }
}
wpe_view_backend_exportable_fdo_destroy(m_exportable);
#else
@@ -193,10 +260,12 @@
return;
#if USE(WPE_RENDERER)
- if (m_viewTexture) {
- if (makeContextCurrent())
- glDeleteTextures(1, &m_viewTexture);
- m_viewTexture = 0;
+ if (s_waylandImpl.value() == WaylandImpl::EGL) {
+ if (m_egl.viewTexture) {
+ if (makeContextCurrent())
+ glDeleteTextures(1, &m_egl.viewTexture);
+ m_egl.viewTexture = 0;
+ }
}
#else
WaylandCompositor::singleton().unbindWebPage(m_webPage);
@@ -214,6 +283,9 @@
return;
m_glContextInitialized = true;
+ if (s_waylandImpl.value() != WaylandImpl::EGL)
+ return;
+
GUniqueOutPtr<GError> error;
#if USE(GTK4)
m_gdkGLContext = adoptGRef(gdk_surface_create_gl_context(gtk_native_get_surface(gtk_widget_get_native(m_webPage.viewWidget())), &error.outPtr()));
@@ -252,10 +324,26 @@
return;
m_surfaceID = context.contextID;
- if (m_pendingImage) {
- wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
- wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_pendingImage);
- m_pendingImage = nullptr;
+ switch (s_waylandImpl.value()) {
+ case WaylandImpl::EGL:
+ if (m_egl.pendingImage) {
+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
+ wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_egl.pendingImage);
+ m_egl.pendingImage = nullptr;
+ }
+ break;
+ case WaylandImpl::SHM:
+#if WPE_FDO_CHECK_VERSION(1, 7, 0)
+ if (m_shm.pendingFrame) {
+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
+ m_shm.pendingFrame = false;
+ }
+ break;
+#else
+ FALLTHROUGH;
+#endif
+ case WaylandImpl::Unsupported:
+ RELEASE_ASSERT_NOT_REACHED();
}
}
@@ -264,54 +352,108 @@
return wpe_view_backend_get_renderer_host_fd(wpe_view_backend_exportable_fdo_get_view_backend(m_exportable));
}
-void AcceleratedBackingStoreWayland::displayBuffer(struct wpe_fdo_egl_exported_image* image)
+void AcceleratedBackingStoreWayland::displayImage(struct wpe_fdo_egl_exported_image* image)
{
+ ASSERT(s_waylandImpl.value() == WaylandImpl::EGL);
if (!m_surfaceID) {
wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
- if (image != m_committedImage)
+ if (image != m_egl.committedImage)
wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, image);
return;
}
- if (m_pendingImage)
- wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_pendingImage);
- m_pendingImage = image;
+ if (m_egl.pendingImage)
+ wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_egl.pendingImage);
+ m_egl.pendingImage = image;
m_webPage.setViewNeedsDisplay(IntRect(IntPoint::zero(), m_webPage.viewSize()));
}
+
+#if WPE_FDO_CHECK_VERSION(1, 7, 0)
+void AcceleratedBackingStoreWayland::displayBuffer(struct wpe_fdo_shm_exported_buffer* buffer)
+{
+ ASSERT(s_waylandImpl.value() == WaylandImpl::SHM);
+ if (!m_surfaceID) {
+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
+ wpe_view_backend_exportable_fdo_dispatch_release_shm_exported_buffer(m_exportable, buffer);
+ return;
+ }
+
+ m_shm.pendingFrame = true;
+
+ struct wl_shm_buffer* shmBuffer = wpe_fdo_shm_exported_buffer_get_shm_buffer(buffer);
+ auto format = wl_shm_buffer_get_format(shmBuffer);
+ if (format != WL_SHM_FORMAT_ARGB8888 && format != WL_SHM_FORMAT_XRGB8888) {
+ wpe_view_backend_exportable_fdo_dispatch_release_shm_exported_buffer(m_exportable, buffer);
+ return;
+ }
+
+ int32_t width = wl_shm_buffer_get_width(shmBuffer);
+ int32_t height = wl_shm_buffer_get_height(shmBuffer);
+ int32_t stride = wl_shm_buffer_get_stride(shmBuffer);
+ int32_t surfaceStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
+ if (!m_surface || cairo_image_surface_get_width(m_surface.get()) != width || cairo_image_surface_get_height(m_surface.get()) != height) {
+ auto* surfaceData = fastZeroedMalloc(height * surfaceStride);
+ m_surface = adoptRef(cairo_image_surface_create_for_data(static_cast<unsigned char*>(surfaceData), CAIRO_FORMAT_ARGB32, width, height, surfaceStride));
+ static cairo_user_data_key_t s_surfaceDataKey;
+ cairo_surface_set_user_data(m_surface.get(), &s_surfaceDataKey, surfaceData, [](void* data) {
+ fastFree(data);
+ });
+ cairoSurfaceSetDeviceScale(m_surface.get(), m_webPage.deviceScaleFactor(), m_webPage.deviceScaleFactor());
+ }
+
+ unsigned char* surfaceData = cairo_image_surface_get_data(m_surface.get());
+ wl_shm_buffer_begin_access(shmBuffer);
+ auto* data = "" char*>(wl_shm_buffer_get_data(shmBuffer));
+ for (int32_t y = 0; y < height; ++y) {
+ for (int32_t x = 0; x < width; ++x) {
+ surfaceData[surfaceStride * y + 4 * x + 0] = data[stride * y + 4 * x + 0];
+ surfaceData[surfaceStride * y + 4 * x + 1] = data[stride * y + 4 * x + 1];
+ surfaceData[surfaceStride * y + 4 * x + 2] = data[stride * y + 4 * x + 2];
+ surfaceData[surfaceStride * y + 4 * x + 3] = data[stride * y + 4 * x + 3];
+ }
+ }
+ wl_shm_buffer_end_access(shmBuffer);
+ wpe_view_backend_exportable_fdo_dispatch_release_shm_exported_buffer(m_exportable, buffer);
+
+ cairo_surface_mark_dirty(m_surface.get());
+ m_webPage.setViewNeedsDisplay(IntRect(IntPoint::zero(), m_webPage.viewSize()));
+}
#endif
+#endif
bool AcceleratedBackingStoreWayland::tryEnsureTexture(unsigned& texture, IntSize& textureSize)
{
+ ASSERT(s_waylandImpl.value() == WaylandImpl::EGL);
#if USE(WPE_RENDERER)
if (!makeContextCurrent())
return false;
- if (m_pendingImage) {
+ if (m_egl.pendingImage) {
wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
- if (m_committedImage)
- wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_committedImage);
- m_committedImage = m_pendingImage;
- m_pendingImage = nullptr;
+ if (m_egl.committedImage)
+ wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(m_exportable, m_egl.committedImage);
+ m_egl.committedImage = m_egl.pendingImage;
+ m_egl.pendingImage = nullptr;
}
- if (!m_committedImage)
+ if (!m_egl.committedImage)
return false;
- if (!m_viewTexture) {
- glGenTextures(1, &m_viewTexture);
- glBindTexture(GL_TEXTURE_2D, m_viewTexture);
+ if (!m_egl.viewTexture) {
+ glGenTextures(1, &m_egl.viewTexture);
+ glBindTexture(GL_TEXTURE_2D, m_egl.viewTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
- glBindTexture(GL_TEXTURE_2D, m_viewTexture);
- glImageTargetTexture2D(GL_TEXTURE_2D, wpe_fdo_egl_exported_image_get_egl_image(m_committedImage));
+ glBindTexture(GL_TEXTURE_2D, m_egl.viewTexture);
+ glImageTargetTexture2D(GL_TEXTURE_2D, wpe_fdo_egl_exported_image_get_egl_image(m_egl.committedImage));
- texture = m_viewTexture;
- textureSize = { static_cast<int>(wpe_fdo_egl_exported_image_get_width(m_committedImage)), static_cast<int>(wpe_fdo_egl_exported_image_get_height(m_committedImage)) };
+ texture = m_egl.viewTexture;
+ textureSize = { static_cast<int>(wpe_fdo_egl_exported_image_get_width(m_egl.committedImage)), static_cast<int>(wpe_fdo_egl_exported_image_get_height(m_egl.committedImage)) };
#else
if (!WaylandCompositor::singleton().getTexture(m_webPage, texture, textureSize))
return false;
@@ -322,6 +464,7 @@
void AcceleratedBackingStoreWayland::downloadTexture(unsigned texture, const IntSize& textureSize)
{
+ ASSERT(s_waylandImpl.value() == WaylandImpl::EGL);
ASSERT(m_glContext);
if (!m_surface || cairo_image_surface_get_width(m_surface.get()) != textureSize.width() || cairo_image_surface_get_height(m_surface.get()) != textureSize.height())
@@ -367,25 +510,45 @@
#if USE(GTK4)
void AcceleratedBackingStoreWayland::snapshot(GtkSnapshot* gtkSnapshot)
{
- GLuint texture;
- IntSize textureSize;
- if (!tryEnsureTexture(texture, textureSize))
- return;
+ switch (s_waylandImpl.value()) {
+ case WaylandImpl::EGL: {
+ GLuint texture;
+ IntSize textureSize;
+ if (!tryEnsureTexture(texture, textureSize))
+ return;
- graphene_rect_t bounds = GRAPHENE_RECT_INIT(0, 0, static_cast<float>(textureSize.width()), static_cast<float>(textureSize.height()));
- if (m_gdkGLContext) {
- GRefPtr<GdkTexture> gdkTexture = adoptGRef(gdk_gl_texture_new(m_gdkGLContext.get(), texture, textureSize.width(), textureSize.height(), nullptr, nullptr));
- gtk_snapshot_append_texture(gtkSnapshot, gdkTexture.get(), &bounds);
- return;
+ graphene_rect_t bounds = GRAPHENE_RECT_INIT(0, 0, static_cast<float>(textureSize.width()), static_cast<float>(textureSize.height()));
+ if (m_gdkGLContext) {
+ GRefPtr<GdkTexture> gdkTexture = adoptGRef(gdk_gl_texture_new(m_gdkGLContext.get(), texture, textureSize.width(), textureSize.height(), nullptr, nullptr));
+ gtk_snapshot_append_texture(gtkSnapshot, gdkTexture.get(), &bounds);
+ return;
+ }
+
+ downloadTexture(texture, textureSize);
+ break;
}
+ case WaylandImpl::SHM:
+#if USE(WPE_RENDERER) && WPE_FDO_CHECK_VERSION(1, 7, 0)
+ if (m_shm.pendingFrame) {
+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
+ m_shm.pendingFrame = false;
+ }
- downloadTexture(texture, textureSize);
+ if (!m_surface)
+ return;
+ break;
+#else
+ FALLTHROUGH;
+#endif
+ case WaylandImpl::Unsupported:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
RefPtr<cairo_t> cr = adoptRef(gtk_snapshot_append_cairo(gtkSnapshot, &bounds));
// The compositor renders the texture flipped for gdk, fix that here.
cairo_matrix_t transform;
- cairo_matrix_init(&transform, 1, 0, 0, -1, 0, textureSize.height() / m_webPage.deviceScaleFactor());
+ cairo_matrix_init(&transform, 1, 0, 0, -1, 0, cairo_image_surface_get_height(m_surface.get()) / m_webPage.deviceScaleFactor());
cairo_transform(cr.get(), &transform);
cairo_set_source_surface(cr.get(), m_surface.get(), 0, 0);
@@ -395,24 +558,46 @@
#else
bool AcceleratedBackingStoreWayland::paint(cairo_t* cr, const IntRect& clipRect)
{
- GLuint texture;
- IntSize textureSize;
- if (!tryEnsureTexture(texture, textureSize))
- return true;
+ switch (s_waylandImpl.value()) {
+ case WaylandImpl::EGL: {
+ GLuint texture;
+ IntSize textureSize;
+ if (!tryEnsureTexture(texture, textureSize))
+ return true;
- cairo_save(cr);
+ cairo_save(cr);
- if (m_gdkGLContext) {
- gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(m_webPage.viewWidget()), texture, GL_TEXTURE, m_webPage.deviceScaleFactor(), 0, 0, textureSize.width(), textureSize.height());
- cairo_restore(cr);
- return true;
+ if (m_gdkGLContext) {
+ gdk_cairo_draw_from_gl(cr, gtk_widget_get_window(m_webPage.viewWidget()), texture, GL_TEXTURE, m_webPage.deviceScaleFactor(), 0, 0, textureSize.width(), textureSize.height());
+ cairo_restore(cr);
+ return true;
+ }
+
+ downloadTexture(texture, textureSize);
+ break;
}
+ case WaylandImpl::SHM:
+#if USE(WPE_RENDERER) && WPE_FDO_CHECK_VERSION(1, 7, 0)
+ if (m_shm.pendingFrame) {
+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(m_exportable);
+ m_shm.pendingFrame = false;
+ }
- downloadTexture(texture, textureSize);
+ if (!m_surface)
+ return true;
+ cairo_save(cr);
+ break;
+#else
+ FALLTHROUGH;
+#endif
+ case WaylandImpl::Unsupported:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
// The compositor renders the texture flipped for gdk_cairo_draw_from_gl, fix that here.
cairo_matrix_t transform;
- cairo_matrix_init(&transform, 1, 0, 0, -1, 0, textureSize.height() / m_webPage.deviceScaleFactor());
+ cairo_matrix_init(&transform, 1, 0, 0, -1, 0, cairo_image_surface_get_height(m_surface.get()) / m_webPage.deviceScaleFactor());
cairo_transform(cr, &transform);
cairo_rectangle(cr, clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());