Bug 1489902 - [Wayland/OpenGL] Don't draw to wl_surface owned by GtkWidget (mozcontainer) until it's commited, r=jhorak

Use frame callback to determine if we can draw to wl_surface owned by GtkWidget and use it as a base for EGL Window.

Differential Revision: https://phabricator.services.mozilla.com/D13722

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Martin Stransky 2018-12-06 11:02:46 +00:00
Родитель 3c70e0c917
Коммит 45555dc042
3 изменённых файлов: 46 добавлений и 62 удалений

Просмотреть файл

@ -147,55 +147,48 @@ void moz_container_init(MozContainer *container) {
container->surface = nullptr;
container->subsurface = nullptr;
container->eglwindow = nullptr;
container->frame_callback_handler = nullptr;
container->ready_to_draw = false;
container->surface_needs_clear = true;
#endif
}
#if defined(MOZ_WAYLAND)
static void moz_on_frame_clock_after_paint(GdkFrameClock *clock,
MozContainer *container) {
container->ready_to_draw = true;
g_signal_handler_disconnect(clock,
container->frame_clock_after_paint_handler);
container->frame_clock_after_paint_handler = 0;
}
static void moz_container_map_wayland(MozContainer *container) {
MOZ_ASSERT(!container->ready_to_draw, "MozContainer is already mapped.");
MOZ_ASSERT(!container->frame_clock_after_paint_handler,
"Repeated gdk_window_get_frame_clock() request?");
GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
if (GDK_IS_X11_DISPLAY(display)) return;
container->surface_needs_clear = true;
static auto sGdkWindowGetFrameClock = (GdkFrameClock * (*)(GdkWindow *))
dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
static wl_surface *moz_container_get_gtk_container_surface(
MozContainer *container) {
static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *))
dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
container->frame_clock_after_paint_handler = g_signal_connect_after(
clock, "after-paint", G_CALLBACK(moz_on_frame_clock_after_paint),
container);
return sGdkWaylandWindowGetWlSurface(window);
}
static void frame_callback_handler(void *data, struct wl_callback *callback,
uint32_t time) {
MozContainer *container = MOZ_CONTAINER(data);
g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
container->ready_to_draw = true;
}
static const struct wl_callback_listener frame_listener = {
frame_callback_handler};
static void moz_container_map_wayland(MozContainer *container) {
container->surface_needs_clear = true;
container->ready_to_draw = false;
static wl_surface *gtk_container_surface =
moz_container_get_gtk_container_surface(container);
container->frame_callback_handler = wl_surface_frame(gtk_container_surface);
wl_callback_add_listener(container->frame_callback_handler, &frame_listener,
container);
}
static void moz_container_unmap_wayland(MozContainer *container) {
g_clear_pointer(&container->eglwindow, wl_egl_window_destroy);
g_clear_pointer(&container->subsurface, wl_subsurface_destroy);
g_clear_pointer(&container->surface, wl_surface_destroy);
if (container->frame_clock_after_paint_handler) {
static auto sGdkWindowGetFrameClock = (GdkFrameClock * (*)(GdkWindow *))
dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
g_signal_handler_disconnect(clock,
container->frame_clock_after_paint_handler);
container->frame_clock_after_paint_handler = 0;
}
g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
container->ready_to_draw = false;
}
#endif
@ -223,7 +216,9 @@ void moz_container_map(GtkWidget *widget) {
if (gtk_widget_get_has_window(widget)) {
gdk_window_show(gtk_widget_get_window(widget));
#if defined(MOZ_WAYLAND)
moz_container_map_wayland(MOZ_CONTAINER(widget));
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
moz_container_map_wayland(MOZ_CONTAINER(widget));
}
#endif
}
}
@ -236,7 +231,9 @@ void moz_container_unmap(GtkWidget *widget) {
if (gtk_widget_get_has_window(widget)) {
gdk_window_hide(gtk_widget_get_window(widget));
#if defined(MOZ_WAYLAND)
moz_container_unmap_wayland(MOZ_CONTAINER(widget));
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
moz_container_unmap_wayland(MOZ_CONTAINER(widget));
}
#endif
}
}
@ -429,34 +426,27 @@ static void moz_container_add(GtkContainer *container, GtkWidget *widget) {
#ifdef MOZ_WAYLAND
struct wl_surface *moz_container_get_wl_surface(MozContainer *container) {
// We're not mapped yet.
if (!container->ready_to_draw) return nullptr;
if (!container->surface) {
if (!container->ready_to_draw) {
return nullptr;
}
GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlCompositor =
(wl_compositor * (*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *))
dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym(
RTLD_DEFAULT, "gdk_window_get_scale_factor");
GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
struct wl_compositor *compositor =
sGdkWaylandDisplayGetWlCompositor(display);
container->surface = wl_compositor_create_surface(compositor);
wl_surface *parent_surface = sGdkWaylandWindowGetWlSurface(window);
nsWaylandDisplay *waylandDisplay = WaylandDisplayGet(display);
wl_subcompositor *subcompositor = waylandDisplay->GetSubcompositor();
container->subsurface = wl_subcompositor_get_subsurface(
subcompositor, container->surface, parent_surface);
waylandDisplay->GetSubcompositor(), container->surface,
moz_container_get_gtk_container_surface(container));
WaylandDisplayRelease(waylandDisplay);
GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
gint x, y;
gdk_window_get_position(window, &x, &y);
wl_subsurface_set_position(container->subsurface, x, y);
@ -468,8 +458,8 @@ struct wl_surface *moz_container_get_wl_surface(MozContainer *container) {
wl_surface_set_input_region(container->surface, region);
wl_region_destroy(region);
container->surface_needs_clear = true;
static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym(
RTLD_DEFAULT, "gdk_window_get_scale_factor");
if (sGdkWindowGetScaleFactorPtr) {
gint scaleFactor = (*sGdkWindowGetScaleFactorPtr)(window);
wl_surface_set_buffer_scale(container->surface, scaleFactor);

Просмотреть файл

@ -75,9 +75,9 @@ struct _MozContainer {
struct wl_surface *surface;
struct wl_subsurface *subsurface;
struct wl_egl_window *eglwindow;
struct wl_callback *frame_callback_handler;
gboolean surface_needs_clear;
gboolean ready_to_draw;
gulong frame_clock_after_paint_handler;
#endif
};
@ -93,6 +93,7 @@ void moz_container_put(MozContainer *container, GtkWidget *child_widget, gint x,
#ifdef MOZ_WAYLAND
struct wl_surface *moz_container_get_wl_surface(MozContainer *container);
struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container);
gboolean moz_container_has_wl_egl_window(MozContainer *container);
gboolean moz_container_surface_needs_clear(MozContainer *container);
#endif

Просмотреть файл

@ -1870,13 +1870,6 @@ gboolean nsWindow::OnExposeEvent(cairo_t *cr) {
// Windows that are not visible will be painted after they become visible.
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel) return FALSE;
#ifdef MOZ_WAYLAND
// Window does not have visible MozContainer/wl_surface yet.
if (!mIsX11Display && (!mContainer || !mContainer->ready_to_draw)) {
return FALSE;
}
#endif
nsIWidgetListener *listener = GetListener();
if (!listener) return FALSE;