diff --git a/ext/wpe/WPEThreadedView.cpp b/ext/wpe/WPEThreadedView.cpp index 98a54e6206..4c8047bcb4 100644 --- a/ext/wpe/WPEThreadedView.cpp +++ b/ext/wpe/WPEThreadedView.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) <2018> Philippe Normand +/* Copyright (C) <2018, 2019, 2020> Philippe Normand * Copyright (C) <2018> Žan Doberšek * * This library is free software; you can redistribute it and/or @@ -62,54 +62,33 @@ private: GMutex& m; }; -WPEThreadedView::WPEThreadedView() +static WPEContextThread *s_view = NULL; + +WPEContextThread& WPEContextThread::singleton() +{ + if (!s_view) + s_view = new WPEContextThread; + + return *s_view; +} + +WPEContextThread::WPEContextThread() { g_mutex_init(&threading.mutex); g_cond_init(&threading.cond); g_mutex_init(&threading.ready_mutex); g_cond_init(&threading.ready_cond); - g_mutex_init(&images_mutex); - { GMutexHolder lock(threading.mutex); - threading.thread = g_thread_new("WPEThreadedView", - s_viewThread, this); + threading.thread = g_thread_new("WPEContextThread", s_viewThread, this); g_cond_wait(&threading.cond, &threading.mutex); GST_DEBUG("thread spawned"); } } -WPEThreadedView::~WPEThreadedView() +WPEContextThread::~WPEContextThread() { - { - GMutexHolder lock(images_mutex); - - if (egl.pending) { - gst_egl_image_unref(egl.pending); - egl.pending = nullptr; - } - if (egl.committed) { - gst_egl_image_unref(egl.committed); - egl.committed = nullptr; - } - } - - { - GMutexHolder lock(threading.mutex); - wpe_view_backend_exportable_fdo_destroy(wpe.exportable); - } - - if (gst.display) { - gst_object_unref(gst.display); - gst.display = nullptr; - } - - if (gst.context) { - gst_object_unref(gst.context); - gst.context = nullptr; - } - if (threading.thread) { g_thread_unref(threading.thread); threading.thread = nullptr; @@ -119,12 +98,41 @@ WPEThreadedView::~WPEThreadedView() g_cond_clear(&threading.cond); g_mutex_clear(&threading.ready_mutex); g_cond_clear(&threading.ready_cond); - g_mutex_clear(&images_mutex); } -gpointer WPEThreadedView::s_viewThread(gpointer data) +template +void WPEContextThread::dispatch(Function func) { - auto& view = *static_cast(data); + struct Payload { + Function& func; + }; + struct Payload payload { func }; + + GSource* source = g_idle_source_new(); + g_source_set_callback(source, [](gpointer data) -> gboolean { + auto& view = WPEContextThread::singleton(); + GMutexHolder lock(view.threading.mutex); + + auto* payload = static_cast(data); + payload->func(); + + g_cond_signal(&view.threading.cond); + return G_SOURCE_REMOVE; + }, &payload, nullptr); + g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); + + { + GMutexHolder lock(threading.mutex); + g_source_attach(source, glib.context); + g_cond_wait(&threading.cond, &threading.mutex); + } + + g_source_unref(source); +} + +gpointer WPEContextThread::s_viewThread(gpointer data) +{ + auto& view = *static_cast(data); view.glib.context = g_main_context_new(); view.glib.loop = g_main_loop_new(view.glib.context, FALSE); @@ -135,7 +143,7 @@ gpointer WPEThreadedView::s_viewThread(gpointer data) GSource* source = g_idle_source_new(); g_source_set_callback(source, [](gpointer data) -> gboolean { - auto& view = *static_cast(data); + auto& view = *static_cast(data); GMutexHolder lock(view.threading.mutex); g_cond_signal(&view.threading.cond); return G_SOURCE_REMOVE; @@ -150,52 +158,13 @@ gpointer WPEThreadedView::s_viewThread(gpointer data) g_main_loop_unref(view.glib.loop); view.glib.loop = nullptr; - if (view.webkit.view) { - g_object_unref(view.webkit.view); - view.webkit.view = nullptr; - } - if (view.webkit.uri) { - g_free(view.webkit.uri); - view.webkit.uri = nullptr; - } - g_main_context_pop_thread_default(view.glib.context); g_main_context_unref(view.glib.context); view.glib.context = nullptr; return nullptr; } -struct wpe_view_backend* WPEThreadedView::backend() const -{ - return wpe.exportable ? wpe_view_backend_exportable_fdo_get_view_backend(wpe.exportable) : nullptr; -} - -struct InitializeContext { - GstWpeSrc* src; - WPEThreadedView& view; - GstGLContext* context; - GstGLDisplay* display; - EGLDisplay eglDisplay; - int width; - int height; - bool result; - gulong loadFailedHandler; -}; - -void WPEThreadedView::s_loadFailed(WebKitWebView*, WebKitLoadEvent event, gchar *failing_uri, GError *error, gpointer data) -{ - InitializeContext *ctx = (InitializeContext*) data; - GMutexHolder lock(ctx->view.threading.ready_mutex); - - - GST_ERROR_OBJECT (ctx->src, "Failed to load %s (%s)", failing_uri, error->message); - ctx->result = false; - - ctx->view.threading.ready = true; - g_cond_signal(&ctx->view.threading.ready_cond); -} - -bool WPEThreadedView::initialize(GstWpeSrc* src, GstGLContext* context, GstGLDisplay* display, int width, int height) +WPEView* WPEContextThread::createWPEView(GstWpeSrc* src, GstGLContext* context, GstGLDisplay* display, int width, int height) { GST_DEBUG("context %p display %p, size (%d,%d)", context, display, width, height); threading.ready = FALSE; @@ -208,105 +177,143 @@ bool WPEThreadedView::initialize(GstWpeSrc* src, GstGLContext* context, GstGLDis #endif }); - EGLDisplay eglDisplay = EGL_NO_DISPLAY; - if (context && display) - eglDisplay = gst_gl_display_egl_get_from_native(GST_GL_DISPLAY_TYPE_WAYLAND, - gst_gl_display_get_handle(display)); - GST_DEBUG("eglDisplay %p", eglDisplay); + WPEView* view = nullptr; + dispatch([&]() mutable { + if (!glib.web_context) { + auto* manager = webkit_website_data_manager_new_ephemeral(); + glib.web_context = webkit_web_context_new_with_website_data_manager(manager); + g_object_unref(manager); + } - struct InitializeContext initializeContext { src, *this, context, display, eglDisplay, width, height, FALSE, 0 }; + view = new WPEView(glib.web_context, src, context, display, width, height); + }); - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - GST_DEBUG("on view thread"); - auto& initializeContext = *static_cast(data); - auto& view = initializeContext.view; - - GMutexHolder lock(view.threading.mutex); - - if (initializeContext.context) - view.gst.context = GST_GL_CONTEXT(gst_object_ref(initializeContext.context)); - if (initializeContext.display) - view.gst.display = GST_GL_DISPLAY(gst_object_ref(initializeContext.display)); - - view.wpe.width = initializeContext.width; - view.wpe.height = initializeContext.height; - - if (initializeContext.eglDisplay) { - initializeContext.result = wpe_fdo_initialize_for_egl_display(initializeContext.eglDisplay); - GST_DEBUG("FDO EGL display initialisation result: %d", initializeContext.result); - } else { -#if ENABLE_SHM_BUFFER_SUPPORT - initializeContext.result = wpe_fdo_initialize_shm(); - GST_DEBUG("FDO SHM initialisation result: %d", initializeContext.result); -#else - GST_WARNING("FDO SHM support is available only in WPEBackend-FDO 1.7.0"); -#endif - } - if (!initializeContext.result) { - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - } - - if (initializeContext.eglDisplay) { - view.wpe.exportable = wpe_view_backend_exportable_fdo_egl_create(&s_exportableEGLClient, - &view, view.wpe.width, view.wpe.height); - } else { -#if ENABLE_SHM_BUFFER_SUPPORT - view.wpe.exportable = wpe_view_backend_exportable_fdo_create(&s_exportableClient, - &view, view.wpe.width, view.wpe.height); -#endif - } - auto* wpeViewBackend = wpe_view_backend_exportable_fdo_get_view_backend(view.wpe.exportable); - auto* viewBackend = webkit_web_view_backend_new(wpeViewBackend, nullptr, nullptr); -#if defined(WPE_BACKEND_CHECK_VERSION) && WPE_BACKEND_CHECK_VERSION(1, 1, 0) - wpe_view_backend_add_activity_state(wpeViewBackend, wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window); -#endif - - view.webkit.view = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "backend", viewBackend, nullptr)); - - gst_wpe_src_configure_web_view(initializeContext.src, view.webkit.view); - - initializeContext.loadFailedHandler = g_signal_connect(view.webkit.view, - "load-failed", G_CALLBACK(s_loadFailed), &initializeContext); - - const gchar* location; - gboolean drawBackground = TRUE; - g_object_get(initializeContext.src, "location", &location, "draw-background", &drawBackground, nullptr); - view.setDrawBackground(drawBackground); - if (location) - view.loadUriUnlocked(location); - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - &initializeContext, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - } - - g_source_unref(source); - - if (initializeContext.result && webkit.uri) { + if (view && view->hasUri()) { GST_DEBUG("waiting load to finish"); GMutexHolder lock(threading.ready_mutex); while (!threading.ready) - g_cond_wait(&threading.ready_cond, &threading.ready_mutex); + g_cond_wait(&threading.ready_cond, &threading.ready_mutex); GST_DEBUG("done"); } - if (initializeContext.loadFailedHandler) - g_signal_handler_disconnect (webkit.view, initializeContext.loadFailedHandler); - - return initializeContext.result; + return view; } -GstEGLImage* WPEThreadedView::image() +void WPEContextThread::notifyLoadFinished() +{ + GMutexHolder lock(threading.ready_mutex); + if (!threading.ready) { + threading.ready = TRUE; + g_cond_signal(&threading.ready_cond); + } +} + +static gboolean s_loadFailed(WebKitWebView*, WebKitLoadEvent, gchar* failing_uri, GError* error, gpointer data) +{ + GstWpeSrc* src = GST_WPE_SRC(data); + GST_ELEMENT_ERROR (GST_ELEMENT_CAST(src), RESOURCE, FAILED, (NULL), ("Failed to load %s (%s)", failing_uri, error->message)); + return FALSE; +} + +WPEView::WPEView(WebKitWebContext* web_context, GstWpeSrc* src, GstGLContext* context, GstGLDisplay* display, int width, int height) +{ + g_mutex_init(&images_mutex); + if (context) + gst.context = GST_GL_CONTEXT(gst_object_ref(context)); + if (display) + gst.display = GST_GL_DISPLAY(gst_object_ref(display)); + + wpe.width = width; + wpe.height = height; + + EGLDisplay eglDisplay = EGL_NO_DISPLAY; + if (context && display) + eglDisplay = gst_gl_display_egl_get_from_native(GST_GL_DISPLAY_TYPE_WAYLAND, gst_gl_display_get_handle(display)); + GST_DEBUG("eglDisplay %p", eglDisplay); + + if (eglDisplay) { + m_isValid = wpe_fdo_initialize_for_egl_display(eglDisplay); + GST_DEBUG("FDO EGL display initialisation result: %d", m_isValid); + } else { +#if ENABLE_SHM_BUFFER_SUPPORT + m_isValid = wpe_fdo_initialize_shm(); + GST_DEBUG("FDO SHM initialisation result: %d", m_isValid); +#else + GST_WARNING("FDO SHM support is available only in WPEBackend-FDO 1.7.0"); +#endif + } + if (!m_isValid) + return; + + if (eglDisplay) { + wpe.exportable = wpe_view_backend_exportable_fdo_egl_create(&s_exportableEGLClient, this, wpe.width, wpe.height); + } else { +#if ENABLE_SHM_BUFFER_SUPPORT + wpe.exportable = wpe_view_backend_exportable_fdo_create(&s_exportableClient, this, wpe.width, wpe.height); +#endif + } + + auto* wpeViewBackend = wpe_view_backend_exportable_fdo_get_view_backend(wpe.exportable); + auto* viewBackend = webkit_web_view_backend_new(wpeViewBackend, (GDestroyNotify) wpe_view_backend_exportable_fdo_destroy, wpe.exportable); +#if defined(WPE_BACKEND_CHECK_VERSION) && WPE_BACKEND_CHECK_VERSION(1, 1, 0) + wpe_view_backend_add_activity_state(wpeViewBackend, wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window); +#endif + + webkit.view = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", web_context, "backend", viewBackend, nullptr)); + + g_signal_connect(webkit.view, "load-failed", G_CALLBACK(s_loadFailed), src); + g_signal_connect(webkit.view, "load-failed-with-tls-errors", G_CALLBACK(s_loadFailed), src); + + gst_wpe_src_configure_web_view(src, webkit.view); + + const gchar* location; + gboolean drawBackground = TRUE; + g_object_get(src, "location", &location, "draw-background", &drawBackground, nullptr); + setDrawBackground(drawBackground); + if (location) + loadUriUnlocked(location); +} + +WPEView::~WPEView() +{ + { + GMutexHolder lock(images_mutex); + + if (egl.pending) { + gst_egl_image_unref(egl.pending); + egl.pending = nullptr; + } + if (egl.committed) { + gst_egl_image_unref(egl.committed); + egl.committed = nullptr; + } + } + + WPEContextThread::singleton().dispatch([&]() { + if (webkit.view) { + g_object_unref(webkit.view); + webkit.view = nullptr; + } + }); + + if (gst.display) { + gst_object_unref(gst.display); + gst.display = nullptr; + } + + if (gst.context) { + gst_object_unref(gst.context); + gst.context = nullptr; + } + if (webkit.uri) { + g_free(webkit.uri); + webkit.uri = nullptr; + } + + g_mutex_clear(&images_mutex); +} + +GstEGLImage* WPEView::image() { GstEGLImage* ret = nullptr; bool dispatchFrameComplete = false; @@ -339,7 +346,7 @@ GstEGLImage* WPEThreadedView::image() return ret; } -GstBuffer* WPEThreadedView::buffer() +GstBuffer* WPEView::buffer() { GstBuffer* ret = nullptr; bool dispatchFrameComplete = false; @@ -372,66 +379,28 @@ GstBuffer* WPEThreadedView::buffer() return ret; } -void WPEThreadedView::resize(int width, int height) +void WPEView::resize(int width, int height) { GST_DEBUG("resize to %dx%d", width, height); wpe.width = width; wpe.height = height; - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - auto& view = *static_cast(data); - GMutexHolder lock(view.threading.mutex); - - GST_DEBUG("dispatching"); - if (view.wpe.exportable && wpe_view_backend_exportable_fdo_get_view_backend(view.wpe.exportable)) - wpe_view_backend_dispatch_set_size(wpe_view_backend_exportable_fdo_get_view_backend(view.wpe.exportable), view.wpe.width, view.wpe.height); - - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - this, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - } - - g_source_unref(source); + s_view->dispatch([&]() { + if (wpe.exportable && wpe_view_backend_exportable_fdo_get_view_backend(wpe.exportable)) + wpe_view_backend_dispatch_set_size(wpe_view_backend_exportable_fdo_get_view_backend(wpe.exportable), wpe.width, wpe.height); + }); } -void WPEThreadedView::frameComplete() +void WPEView::frameComplete() { GST_TRACE("frame complete"); - - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - auto& view = *static_cast(data); - GMutexHolder lock(view.threading.mutex); - - GST_TRACE("dispatching"); - wpe_view_backend_exportable_fdo_dispatch_frame_complete(view.wpe.exportable); - - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - this, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - } - - g_source_unref(source); + s_view->dispatch([&]() { + GST_TRACE("dispatching"); + wpe_view_backend_exportable_fdo_dispatch_frame_complete(wpe.exportable); + }); } -void WPEThreadedView::loadUriUnlocked(const gchar* uri) +void WPEView::loadUriUnlocked(const gchar* uri) { if (webkit.uri) g_free(webkit.uri); @@ -441,74 +410,22 @@ void WPEThreadedView::loadUriUnlocked(const gchar* uri) webkit_web_view_load_uri(webkit.view, webkit.uri); } -void WPEThreadedView::loadUri(const gchar* uri) +void WPEView::loadUri(const gchar* uri) { - struct UriContext { - WPEThreadedView& view; - const gchar* uri; - } uriContext { *this, uri }; - - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - GST_DEBUG("on view thread"); - auto& uriContext = *static_cast(data); - auto& view = uriContext.view; - GMutexHolder lock(view.threading.mutex); - - view.loadUriUnlocked(uriContext.uri); - - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - &uriContext, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - GST_DEBUG("done"); - } - - g_source_unref(source); + s_view->dispatch([&]() { + loadUriUnlocked(uri); + }); } -void WPEThreadedView::loadData(GBytes* bytes) +void WPEView::loadData(GBytes* bytes) { - struct DataContext { - WPEThreadedView& view; - GBytes* bytes; - } dataContext { *this, g_bytes_ref(bytes) }; - - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - GST_DEBUG("on view thread"); - auto& dataContext = *static_cast(data); - auto& view = dataContext.view; - GMutexHolder lock(view.threading.mutex); - - webkit_web_view_load_bytes(view.webkit.view, dataContext.bytes, nullptr, nullptr, nullptr); - g_bytes_unref(dataContext.bytes); - - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - &dataContext, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - GST_DEBUG("done"); - } - - g_source_unref(source); + s_view->dispatch([this, bytes = g_bytes_ref(bytes)]() { + webkit_web_view_load_bytes(webkit.view, bytes, nullptr, nullptr, nullptr); + g_bytes_unref(bytes); + }); } -void WPEThreadedView::setDrawBackground(gboolean drawsBackground) +void WPEView::setDrawBackground(gboolean drawsBackground) { #if WEBKIT_CHECK_VERSION(2, 24, 0) GST_DEBUG("%s background rendering", drawsBackground ? "Enabling" : "Disabling"); @@ -520,49 +437,26 @@ void WPEThreadedView::setDrawBackground(gboolean drawsBackground) #endif } -void WPEThreadedView::releaseImage(gpointer imagePointer) +void WPEView::releaseImage(gpointer imagePointer) { - struct ReleaseImageContext { - WPEThreadedView& view; - gpointer imagePointer; - } releaseImageContext{ *this, imagePointer }; - - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - auto& releaseImageContext = *static_cast(data); - auto& view = releaseImageContext.view; - GMutexHolder lock(view.threading.mutex); - - GST_TRACE("Dispatch release exported image %p", releaseImageContext.imagePointer); + s_view->dispatch([&]() { + GST_TRACE("Dispatch release exported image %p", imagePointer); #if USE_DEPRECATED_FDO_EGL_IMAGE - wpe_view_backend_exportable_fdo_egl_dispatch_release_image(releaseImageContext.view.wpe.exportable, - static_cast(releaseImageContext.imagePointer)); + wpe_view_backend_exportable_fdo_egl_dispatch_release_image(wpe.exportable, + static_cast(imagePointer)); #else - wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(releaseImageContext.view.wpe.exportable, - static_cast(releaseImageContext.imagePointer)); + wpe_view_backend_exportable_fdo_egl_dispatch_release_exported_image(wpe.exportable, + static_cast(imagePointer)); #endif - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - &releaseImageContext, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - } - - g_source_unref(source); + }); } struct ImageContext { - WPEThreadedView* view; + WPEView* view; gpointer image; }; -void WPEThreadedView::handleExportedImage(gpointer image) +void WPEView::handleExportedImage(gpointer image) { ImageContext* imageContext = g_slice_new(ImageContext); imageContext->view = this; @@ -581,63 +475,34 @@ void WPEThreadedView::handleExportedImage(gpointer image) GST_TRACE("EGLImage %p wrapped in GstEGLImage %" GST_PTR_FORMAT, eglImage, gstImage); egl.pending = gstImage; - { - GMutexHolder lock(threading.ready_mutex); - if (!threading.ready) { - threading.ready = TRUE; - g_cond_signal(&threading.ready_cond); - } - } + s_view->notifyLoadFinished(); } } #if ENABLE_SHM_BUFFER_SUPPORT struct SHMBufferContext { - WPEThreadedView* view; - struct wpe_fdo_shm_exported_buffer* buffer; + WPEView* view; + struct wpe_fdo_shm_exported_buffer* buffer; }; -void WPEThreadedView::releaseSHMBuffer(gpointer data) +void WPEView::releaseSHMBuffer(gpointer data) { SHMBufferContext* context = static_cast(data); - struct ReleaseBufferContext { - WPEThreadedView& view; - SHMBufferContext* context; - } releaseImageContext{ *this, context }; - - GSource* source = g_idle_source_new(); - g_source_set_callback(source, - [](gpointer data) -> gboolean { - auto& releaseBufferContext = *static_cast(data); - auto& view = releaseBufferContext.view; - GMutexHolder lock(view.threading.mutex); - - struct wpe_fdo_shm_exported_buffer* buffer = static_cast(releaseBufferContext.context->buffer); - GST_TRACE("Dispatch release exported buffer %p", buffer); - wpe_view_backend_exportable_fdo_dispatch_release_shm_exported_buffer(view.wpe.exportable, buffer); - g_cond_signal(&view.threading.cond); - return G_SOURCE_REMOVE; - }, - &releaseImageContext, nullptr); - g_source_set_priority(source, WPE_GLIB_SOURCE_PRIORITY); - - { - GMutexHolder lock(threading.mutex); - g_source_attach(source, glib.context); - g_cond_wait(&threading.cond, &threading.mutex); - } - - g_source_unref(source); + s_view->dispatch([&]() { + auto* buffer = static_cast(context->buffer); + GST_TRACE("Dispatch release exported buffer %p", buffer); + wpe_view_backend_exportable_fdo_dispatch_release_shm_exported_buffer(wpe.exportable, buffer); + }); } -void WPEThreadedView::s_releaseSHMBuffer(gpointer data) +void WPEView::s_releaseSHMBuffer(gpointer data) { SHMBufferContext* context = static_cast(data); context->view->releaseSHMBuffer(data); g_slice_free(SHMBufferContext, context); } -void WPEThreadedView::handleExportedBuffer(struct wpe_fdo_shm_exported_buffer* buffer) +void WPEView::handleExportedBuffer(struct wpe_fdo_shm_exported_buffer* buffer) { struct wl_shm_buffer* shmBuffer = wpe_fdo_shm_exported_buffer_get_shm_buffer(buffer); auto format = wl_shm_buffer_get_format(shmBuffer); @@ -667,22 +532,16 @@ void WPEThreadedView::handleExportedBuffer(struct wpe_fdo_shm_exported_buffer* b GMutexHolder lock(images_mutex); GST_TRACE("SHM buffer %p wrapped in buffer %" GST_PTR_FORMAT, buffer, gstBuffer); shm.pending = gstBuffer; - { - GMutexHolder lock(threading.ready_mutex); - if (!threading.ready) { - threading.ready = TRUE; - g_cond_signal(&threading.ready_cond); - } - } + s_view->notifyLoadFinished(); } } #endif -struct wpe_view_backend_exportable_fdo_egl_client WPEThreadedView::s_exportableEGLClient = { +struct wpe_view_backend_exportable_fdo_egl_client WPEView::s_exportableEGLClient = { #if USE_DEPRECATED_FDO_EGL_IMAGE // export_egl_image [](void* data, EGLImageKHR image) { - auto& view = *static_cast(data); + auto& view = *static_cast(data); view.handleExportedImage(static_cast(image)); }, nullptr, nullptr, @@ -690,7 +549,7 @@ struct wpe_view_backend_exportable_fdo_egl_client WPEThreadedView::s_exportableE // export_egl_image nullptr, [](void* data, struct wpe_fdo_egl_exported_image* image) { - auto& view = *static_cast(data); + auto& view = *static_cast(data); view.handleExportedImage(static_cast(image)); }, nullptr, @@ -700,12 +559,12 @@ struct wpe_view_backend_exportable_fdo_egl_client WPEThreadedView::s_exportableE }; #if ENABLE_SHM_BUFFER_SUPPORT -struct wpe_view_backend_exportable_fdo_client WPEThreadedView::s_exportableClient = { +struct wpe_view_backend_exportable_fdo_client WPEView::s_exportableClient = { nullptr, nullptr, // export_shm_buffer [](void* data, struct wpe_fdo_shm_exported_buffer* buffer) { - auto& view = *static_cast(data); + auto& view = *static_cast(data); view.handleExportedBuffer(buffer); }, nullptr, @@ -713,9 +572,35 @@ struct wpe_view_backend_exportable_fdo_client WPEThreadedView::s_exportableClien }; #endif -void WPEThreadedView::s_releaseImage(GstEGLImage* image, gpointer data) +void WPEView::s_releaseImage(GstEGLImage* image, gpointer data) { ImageContext* context = static_cast(data); context->view->releaseImage(context->image); g_slice_free(ImageContext, context); } + +struct wpe_view_backend* WPEView::backend() const +{ + return wpe.exportable ? wpe_view_backend_exportable_fdo_get_view_backend(wpe.exportable) : nullptr; +} + +void WPEView::dispatchKeyboardEvent(struct wpe_input_keyboard_event& wpe_event) +{ + s_view->dispatch([&]() { + wpe_view_backend_dispatch_keyboard_event(backend(), &wpe_event); + }); +} + +void WPEView::dispatchPointerEvent(struct wpe_input_pointer_event& wpe_event) +{ + s_view->dispatch([&]() { + wpe_view_backend_dispatch_pointer_event(backend(), &wpe_event); + }); +} + +void WPEView::dispatchAxisEvent(struct wpe_input_axis_event& wpe_event) +{ + s_view->dispatch([&]() { + wpe_view_backend_dispatch_axis_event(backend(), &wpe_event); + }); +} diff --git a/ext/wpe/WPEThreadedView.h b/ext/wpe/WPEThreadedView.h index ca5a66dbea..359e80ea94 100644 --- a/ext/wpe/WPEThreadedView.h +++ b/ext/wpe/WPEThreadedView.h @@ -37,22 +37,28 @@ typedef struct _GstEGLImage GstEGLImage; #define ENABLE_SHM_BUFFER_SUPPORT 0 #endif -class WPEThreadedView { +class WPEView { public: - WPEThreadedView(); - ~WPEThreadedView(); + WPEView(WebKitWebContext*, GstWpeSrc*, GstGLContext*, GstGLDisplay*, int width, int height); + ~WPEView(); - bool initialize(GstWpeSrc*, GstGLContext*, GstGLDisplay*, int width, int height); + bool operator!() const { return m_isValid; } + /* Used by wpesrc */ void resize(int width, int height); void loadUri(const gchar*); void loadData(GBytes*); void setDrawBackground(gboolean); - GstEGLImage* image(); GstBuffer* buffer(); - struct wpe_view_backend* backend() const; + void dispatchKeyboardEvent(struct wpe_input_keyboard_event&); + void dispatchPointerEvent(struct wpe_input_pointer_event&); + void dispatchAxisEvent(struct wpe_input_axis_event&); + + /* Used by WPEContextThread */ + bool hasUri() const { return webkit.uri; } + void disconnectLoadFailedSignal(); protected: void handleExportedImage(gpointer); @@ -61,6 +67,7 @@ protected: #endif private: + struct wpe_view_backend* backend() const; void frameComplete(); void loadUriUnlocked(const gchar*); @@ -70,23 +77,6 @@ private: static void s_releaseSHMBuffer(gpointer); #endif - static void s_loadFailed(WebKitWebView*, WebKitLoadEvent, gchar*, GError*, gpointer); - - static gpointer s_viewThread(gpointer); - struct { - GMutex mutex; - GCond cond; - GMutex ready_mutex; - GCond ready_cond; - gboolean ready; - GThread* thread { nullptr }; - } threading; - - struct { - GMainContext* context; - GMainLoop* loop; - } glib { nullptr, nullptr }; - struct { GstGLContext* context; GstGLDisplay* display; @@ -109,6 +99,8 @@ private: WebKitWebView* view; } webkit = { nullptr, nullptr }; + bool m_isValid { false }; + // This mutex guards access to either egl or shm resources declared below, // depending on the runtime behavior. GMutex images_mutex; @@ -122,4 +114,37 @@ private: GstBuffer* pending; GstBuffer* committed; } shm { nullptr, nullptr }; + +}; + +class WPEContextThread { +public: + static WPEContextThread& singleton(); + + WPEContextThread(); + ~WPEContextThread(); + + WPEView* createWPEView(GstWpeSrc*, GstGLContext*, GstGLDisplay*, int width, int height); + + template + void dispatch(Function); + + void notifyLoadFinished(); + +private: + static gpointer s_viewThread(gpointer); + struct { + GMutex mutex; + GCond cond; + GMutex ready_mutex; + GCond ready_cond; + gboolean ready; + GThread* thread { nullptr }; + } threading; + + struct { + GMainContext* context; + GMainLoop* loop; + WebKitWebContext* web_context; + } glib { nullptr, nullptr, nullptr }; }; diff --git a/ext/wpe/gstwpesrc.cpp b/ext/wpe/gstwpesrc.cpp index 0670983d39..f303a3da8d 100644 --- a/ext/wpe/gstwpesrc.cpp +++ b/ext/wpe/gstwpesrc.cpp @@ -108,8 +108,6 @@ struct _GstWpeSrc { GstGLBaseSrc parent; - WPEThreadedView *view; - /* properties */ gchar *location; gboolean draw_background; @@ -118,6 +116,8 @@ struct _GstWpeSrc gboolean gl_enabled; gint64 n_frames; /* total frames sent */ + + WPEView *view; }; static void gst_wpe_src_uri_handler_init (gpointer iface, gpointer data); @@ -237,7 +237,6 @@ static gboolean gst_wpe_src_gl_start (GstGLBaseSrc * base_src) { GstWpeSrc *src = GST_WPE_SRC (base_src); - gboolean result = TRUE; GstCapsFeatures *caps_features; GstGLContext *context = NULL; GstGLDisplay *display = NULL; @@ -256,10 +255,17 @@ gst_wpe_src_gl_start (GstGLBaseSrc * base_src) GST_DEBUG_OBJECT (src, "Will fill GLMemories: %d\n", src->gl_enabled); - src->view = new WPEThreadedView; - result = src->view->initialize (src, context, display, - GST_VIDEO_INFO_WIDTH (&base_src->out_info), - GST_VIDEO_INFO_HEIGHT (&base_src->out_info)); + auto & thread = WPEContextThread::singleton (); + src->view = thread.createWPEView (src, context, display, + GST_VIDEO_INFO_WIDTH (&base_src->out_info), + GST_VIDEO_INFO_HEIGHT (&base_src->out_info)); + + if (!src->view) { + GST_OBJECT_UNLOCK (src); + GST_ELEMENT_ERROR (src, RESOURCE, FAILED, + ("WPEBackend-FDO EGL display initialisation failed"), (NULL)); + return FALSE; + } if (src->bytes != NULL) { src->view->loadData (src->bytes); @@ -268,13 +274,8 @@ gst_wpe_src_gl_start (GstGLBaseSrc * base_src) } src->n_frames = 0; - GST_OBJECT_UNLOCK (src); - if (!result) { - GST_ELEMENT_ERROR (src, RESOURCE, FAILED, - ("WPEBackend-FDO EGL display initialisation failed"), (NULL)); - } - return result; + return TRUE; } static void @@ -441,8 +442,7 @@ gst_wpe_src_event (GstPad * pad, GstObject * parent, GstEvent * event) wpe_event.pressed = gst_navigation_event_get_type (event) == GST_NAVIGATION_EVENT_KEY_PRESS; - wpe_view_backend_dispatch_keyboard_event (src->view->backend (), - &wpe_event); + src->view->dispatchKeyboardEvent (wpe_event); ret = TRUE; } break; @@ -470,8 +470,7 @@ gst_wpe_src_event (GstPad * pad, GstObject * parent, GstEvent * event) wpe_event.state = gst_navigation_event_get_type (event) == GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS; - wpe_view_backend_dispatch_pointer_event (src->view->backend (), - &wpe_event); + src->view->dispatchPointerEvent (wpe_event); ret = TRUE; } break; @@ -482,8 +481,7 @@ gst_wpe_src_event (GstPad * pad, GstObject * parent, GstEvent * event) wpe_event.type = wpe_input_pointer_event_type_motion; wpe_event.x = (int) x; wpe_event.y = (int) y; - wpe_view_backend_dispatch_pointer_event (src->view->backend (), - &wpe_event); + src->view->dispatchPointerEvent (wpe_event); ret = TRUE; } break; @@ -500,12 +498,12 @@ gst_wpe_src_event (GstPad * pad, GstObject * parent, GstEvent * event) wpe_event.base.time = GST_TIME_AS_MSECONDS (GST_EVENT_TIMESTAMP (event)); wpe_event.base.type = - static_cast(wpe_input_axis_event_type_mask_2d | + static_cast < wpe_input_axis_event_type > + (wpe_input_axis_event_type_mask_2d | wpe_input_axis_event_type_motion_smooth); wpe_event.base.x = (int) x; wpe_event.base.y = (int) y; - wpe_view_backend_dispatch_axis_event (src->view->backend (), - &wpe_event.base); + src->view->dispatchAxisEvent (wpe_event.base); #else struct wpe_input_axis_event wpe_event; if (delta_x) { @@ -519,8 +517,7 @@ gst_wpe_src_event (GstPad * pad, GstObject * parent, GstEvent * event) wpe_event.type = wpe_input_axis_event_type_motion; wpe_event.x = (int) x; wpe_event.y = (int) y; - wpe_view_backend_dispatch_axis_event (src->view->backend (), - &wpe_event); + src->view->dispatchAxisEvent (wpe_event); #endif ret = TRUE; }