diff --git a/widget/gtk/MozContainerWayland.h b/widget/gtk/MozContainerWayland.h --- a/widget/gtk/MozContainerWayland.h +++ b/widget/gtk/MozContainerWayland.h @@ -76,13 +76,17 @@ struct wl_egl_window* moz_container_wayland_get_egl_window( MozContainer* container, double scale); gboolean moz_container_wayland_has_egl_window(MozContainer* container); void moz_container_wayland_egl_window_set_size(MozContainer* container, - int width, int height); + nsIntSize aSize); +bool moz_container_wayland_egl_window_needs_size_update(MozContainer* container, + nsIntSize aSize, + int scale); void moz_container_wayland_set_scale_factor(MozContainer* container); -void moz_container_wayland_set_scale_factor_locked(MozContainer* container); +void moz_container_wayland_set_scale_factor_locked( + const mozilla::MutexAutoLock& aProofOfLock, MozContainer* container); void moz_container_wayland_add_initial_draw_callback_locked( MozContainer* container, const std::function& initial_draw_cb); void moz_container_wayland_add_or_fire_initial_draw_callback( MozContainer* container, const std::function& initial_draw_cb); diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp --- a/widget/gtk/MozContainerWayland.cpp +++ b/widget/gtk/MozContainerWayland.cpp @@ -108,13 +108,11 @@ mSurface = moz_container_wayland_surface_lock(aContainer); } MozContainerSurfaceLock::~MozContainerSurfaceLock() { moz_container_wayland_surface_unlock(mContainer, &mSurface); } -struct wl_surface* MozContainerSurfaceLock::GetSurface() { - return mSurface; -} +struct wl_surface* MozContainerSurfaceLock::GetSurface() { return mSurface; } // Imlemented in MozContainer.cpp void moz_container_realize(GtkWidget* widget); // Invalidate gtk wl_surface to commit changes to wl_subsurface. @@ -163,15 +161,16 @@ // This is called from layout/compositor code only with // size equal to GL rendering context. Otherwise there are // rendering artifacts as wl_egl_window size does not match // GL rendering pipeline setup. void moz_container_wayland_egl_window_set_size(MozContainer* container, - int width, int height) { + nsIntSize aSize) { MozContainerWayland* wl_container = &container->wl_container; MutexAutoLock lock(*wl_container->container_lock); if (wl_container->eglwindow) { - wl_egl_window_resize(wl_container->eglwindow, width, height, 0, 0); + wl_egl_window_resize(wl_container->eglwindow, aSize.width, aSize.height, 0, + 0); } } void moz_container_wayland_class_init(MozContainerClass* klass) { /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass); @@ -432,11 +431,11 @@ MOZ_CONTAINER(widget))) { return FALSE; } } - moz_container_wayland_set_scale_factor_locked(MOZ_CONTAINER(widget)); + moz_container_wayland_set_scale_factor_locked(lock, MOZ_CONTAINER(widget)); moz_container_wayland_set_opaque_region_locked(lock, MOZ_CONTAINER(widget)); moz_container_clear_input_region(MOZ_CONTAINER(widget)); moz_container_wayland_invalidate(MOZ_CONTAINER(widget)); return FALSE; } @@ -487,11 +486,11 @@ if (!container->wl_container.surface) { if (!moz_container_wayland_surface_create_locked(lock, container)) { return; } } - moz_container_wayland_set_scale_factor_locked(container); + moz_container_wayland_set_scale_factor_locked(lock, container); moz_container_wayland_set_opaque_region_locked(lock, container); moz_container_wayland_move_locked(lock, container, allocation->x, allocation->y); moz_container_clear_input_region(container); moz_container_wayland_invalidate(MOZ_CONTAINER(widget)); @@ -542,55 +541,61 @@ if (wl_container->surface) { moz_container_wayland_set_opaque_region_locked(lock, container); } } -void moz_container_wayland_set_scale_factor_locked(MozContainer* container) { +static void moz_container_wayland_surface_set_scale_locked( + const MutexAutoLock& aProofOfLock, MozContainerWayland* wl_container, + int scale) { + if (wl_container->buffer_scale == scale) { + return; + } + + LOGCONTAINER("%s scale %d\n", __FUNCTION__, scale); + + // There is a chance that the attached wl_buffer has not yet been doubled + // on the main thread when scale factor changed to 2. This leads to + // crash with the following message: + // Buffer size (AxB) must be an integer multiple of the buffer_scale (2) + // Removing the possibly wrong wl_buffer to prevent that crash: + wl_surface_attach(wl_container->surface, nullptr, 0, 0); + wl_surface_set_buffer_scale(wl_container->surface, scale); + wl_container->buffer_scale = scale; +} + +void moz_container_wayland_set_scale_factor_locked( + const MutexAutoLock& aProofOfLock, MozContainer* container) { if (gfx::gfxVars::UseWebRenderCompositor()) { // the compositor backend handles scaling itself return; } MozContainerWayland* wl_container = &container->wl_container; wl_container->container_lock->AssertCurrentThreadOwns(); nsWindow* window = moz_container_get_nsWindow(container); - - if (window && window->UseFractionalScale()) { + MOZ_DIAGNOSTIC_ASSERT(window); + if (window->UseFractionalScale()) { if (!wl_container->viewport) { wl_container->viewport = wp_viewporter_get_viewport( WaylandDisplayGet()->GetViewporter(), wl_container->surface); } GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(container)); wp_viewport_set_destination(wl_container->viewport, gdk_window_get_width(gdkWindow), gdk_window_get_height(gdkWindow)); } else { - int scale = window ? window->GdkCeiledScaleFactor() : 1; - - if (scale == wl_container->buffer_scale) { - return; - } - - LOGCONTAINER("%s [%p] scale %d\n", __FUNCTION__, - (void*)moz_container_get_nsWindow(container), scale); - // There is a chance that the attached wl_buffer has not yet been doubled - // on the main thread when scale factor changed to 2. This leads to - // crash with the following message: - // Buffer size (AxB) must be an integer multiple of the buffer_scale (2) - // Removing the possibly wrong wl_buffer to prevent that crash: - wl_surface_attach(wl_container->surface, nullptr, 0, 0); - wl_surface_set_buffer_scale(wl_container->surface, scale); - wl_container->buffer_scale = scale; + moz_container_wayland_surface_set_scale_locked( + aProofOfLock, wl_container, window->GdkCeiledScaleFactor()); } } void moz_container_wayland_set_scale_factor(MozContainer* container) { MutexAutoLock lock(*container->wl_container.container_lock); if (container->wl_container.surface) { - moz_container_wayland_set_scale_factor_locked(container); + moz_container_wayland_set_scale_factor_locked(lock, container); } } static bool moz_container_wayland_surface_create_locked( const MutexAutoLock& aProofOfLock, MozContainer* container) { @@ -598,10 +603,12 @@ LOGWAYLAND("%s [%p]\n", __FUNCTION__, (void*)moz_container_get_nsWindow(container)); GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container)); + MOZ_DIAGNOSTIC_ASSERT(window); + wl_surface* parent_surface = gdk_wayland_window_get_wl_surface(window); if (!parent_surface) { LOGWAYLAND(" Failed - missing parent surface!"); return false; } @@ -691,36 +698,65 @@ *surface = nullptr; } container->wl_container.container_lock->Unlock(); } +bool moz_container_wayland_egl_window_needs_size_update(MozContainer* container, + nsIntSize aSize, + int aScale) { + MozContainerWayland* wl_container = &container->wl_container; + if (wl_container->buffer_scale != aScale) { + return true; + } + nsIntSize recentSize; + wl_egl_window_get_attached_size(wl_container->eglwindow, &recentSize.width, + &recentSize.height); + return aSize != recentSize; +} + struct wl_egl_window* moz_container_wayland_get_egl_window( MozContainer* container, double scale) { MozContainerWayland* wl_container = &container->wl_container; - LOGCONTAINER("%s [%p] eglwindow %p\n", __FUNCTION__, + LOGCONTAINER("%s [%p] eglwindow %p scale %d\n", __FUNCTION__, (void*)moz_container_get_nsWindow(container), - (void*)wl_container->eglwindow); + (void*)wl_container->eglwindow, (int)scale); MutexAutoLock lock(*wl_container->container_lock); if (!wl_container->surface || !wl_container->ready_to_draw) { - LOGWAYLAND( + LOGCONTAINER( " quit, wl_container->surface %p wl_container->ready_to_draw %d\n", wl_container->surface, wl_container->ready_to_draw); return nullptr; } + + GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container)); + nsIntSize requestedSize((int)round(gdk_window_get_width(window) * scale), + (int)round(gdk_window_get_height(window) * scale)); + if (!wl_container->eglwindow) { - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container)); wl_container->eglwindow = wl_egl_window_create( - wl_container->surface, (int)round(gdk_window_get_width(window) * scale), - (int)round(gdk_window_get_height(window) * scale)); + wl_container->surface, requestedSize.width, requestedSize.height); - LOGCONTAINER("%s [%p] created eglwindow %p size %d x %d scale %f\n", + LOGCONTAINER("%s [%p] created eglwindow %p size %d x %d (with scale %f)\n", __FUNCTION__, (void*)moz_container_get_nsWindow(container), - (void*)wl_container->eglwindow, gdk_window_get_width(window), - gdk_window_get_height(window), scale); + (void*)wl_container->eglwindow, requestedSize.width, + requestedSize.height, scale); + } else { + nsIntSize recentSize; + wl_egl_window_get_attached_size(wl_container->eglwindow, &recentSize.width, + &recentSize.height); + if (requestedSize != recentSize) { + LOGCONTAINER("%s [%p] resized to %d x %d (with scale %f)\n", __FUNCTION__, + (void*)moz_container_get_nsWindow(container), + requestedSize.width, requestedSize.height, scale); + wl_egl_window_resize(wl_container->eglwindow, requestedSize.width, + requestedSize.height, 0, 0); + } } + moz_container_wayland_surface_set_scale_locked(lock, wl_container, + static_cast(scale)); return wl_container->eglwindow; } gboolean moz_container_wayland_has_egl_window(MozContainer* container) { return container->wl_container.eglwindow != nullptr; diff --git a/widget/gtk/WindowSurfaceWaylandMultiBuffer.cpp b/widget/gtk/WindowSurfaceWaylandMultiBuffer.cpp --- a/widget/gtk/WindowSurfaceWaylandMultiBuffer.cpp +++ b/widget/gtk/WindowSurfaceWaylandMultiBuffer.cpp @@ -301,11 +301,11 @@ LayoutDeviceIntRect r = iter.Get(); wl_surface_damage_buffer(waylandSurface, r.x, r.y, r.width, r.height); } } - moz_container_wayland_set_scale_factor_locked(container); + moz_container_wayland_set_scale_factor_locked(aProofOfLock, container); mInProgressBuffer->AttachAndCommit(waylandSurface); mInProgressBuffer->ResetBufferAge(); mFrontBuffer = mInProgressBuffer; mFrontBufferInvalidRegion = aInvalidRegion; diff --git a/widget/gtk/mozwayland/mozwayland.c b/widget/gtk/mozwayland/mozwayland.c --- a/widget/gtk/mozwayland/mozwayland.c +++ b/widget/gtk/mozwayland/mozwayland.c @@ -186,10 +186,13 @@ MOZ_EXPORT void wl_egl_window_destroy(struct wl_egl_window* egl_window) {} MOZ_EXPORT void wl_egl_window_resize(struct wl_egl_window* egl_window, int width, int height, int dx, int dy) {} +MOZ_EXPORT void wl_egl_window_get_attached_size( + struct wl_egl_window* egl_window, int* width, int* height) {} + MOZ_EXPORT void wl_list_init(struct wl_list* list) {} MOZ_EXPORT void wl_list_insert(struct wl_list* list, struct wl_list* elm) {} MOZ_EXPORT void wl_list_remove(struct wl_list* elm) {} diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -9816,13 +9816,18 @@ void nsWindow::SetEGLNativeWindowSize( const LayoutDeviceIntSize& aEGLWindowSize) { if (!mContainer || !GdkIsWaylandDisplay()) { return; } - moz_container_wayland_egl_window_set_size(mContainer, aEGLWindowSize.width, - aEGLWindowSize.height); - moz_container_wayland_set_scale_factor(mContainer); + if (moz_container_wayland_egl_window_needs_size_update( + mContainer, aEGLWindowSize.ToUnknownSize(), GdkCeiledScaleFactor())) { + LOG("nsWindow::SetEGLNativeWindowSize() %d x %d", aEGLWindowSize.width, + aEGLWindowSize.height); + moz_container_wayland_egl_window_set_size(mContainer, + aEGLWindowSize.ToUnknownSize()); + moz_container_wayland_set_scale_factor(mContainer); + } } #endif LayoutDeviceIntSize nsWindow::GetMozContainerSize() { LayoutDeviceIntSize size(0, 0);