commit 56ba5001437fe16c76bb718206e88ad6813018a9
parent f44ef8ec3aa76761928fbc90dfeb8a59a95c7910
Author: Martin Stransky <stransky@redhat.com>
Date: Fri, 5 Dec 2025 13:44:40 +0000
Bug 2004002 [Wayland] Delay EGL window changes to OpenGL rendering to avoid artifacts r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D275055
Diffstat:
7 files changed, 67 insertions(+), 23 deletions(-)
diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp
@@ -742,6 +742,12 @@ Maybe<IntRect> CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
MakeCurrent(ForceMakeCurrent);
mWidgetSize = LayoutDeviceIntSize::FromUnknownSize(rect.Size());
+#ifdef MOZ_WAYLAND
+ if (mWidget && mWidget->AsGTK()) {
+ // Set correct window size to avoid rendering artifacts.
+ mWidget->AsGTK()->SetEGLNativeWindowSize(mWidgetSize);
+ }
+#endif
} else {
MakeCurrent();
}
diff --git a/gfx/webrender_bindings/RenderCompositorEGL.cpp b/gfx/webrender_bindings/RenderCompositorEGL.cpp
@@ -88,7 +88,11 @@ bool RenderCompositorEGL::BeginFrame() {
<< "We don't have EGLSurface to draw into. Called too early?";
return false;
}
-
+#ifdef MOZ_WAYLAND
+ if (auto* gtkWidget = mWidget->AsGTK()) {
+ gtkWidget->SetEGLNativeWindowSize(GetBufferSize());
+ }
+#endif
if (!MakeCurrent()) {
gfxCriticalNote << "Failed to make render context current, can't draw.";
return false;
diff --git a/widget/gtk/GtkCompositorWidget.cpp b/widget/gtk/GtkCompositorWidget.cpp
@@ -122,6 +122,16 @@ EGLNativeWindowType GtkCompositorWidget::GetEGLNativeWindow() {
return window;
}
+void GtkCompositorWidget::SetEGLNativeWindowSize(
+ const LayoutDeviceIntSize& aEGLWindowSize) {
+#if defined(MOZ_WAYLAND)
+ // We explicitly need to set EGL window size on Wayland only.
+ if (mWidget && mWidget->GetWaylandSurface()) {
+ mWidget->GetWaylandSurface()->ApplyEGLWindowSize(aEGLWindowSize);
+ }
+#endif
+}
+
LayoutDeviceIntRegion GtkCompositorWidget::GetTransparentRegion() {
LayoutDeviceIntRegion fullRegion(
LayoutDeviceIntRect(LayoutDeviceIntPoint(), GetClientSize()));
diff --git a/widget/gtk/GtkCompositorWidget.h b/widget/gtk/GtkCompositorWidget.h
@@ -79,6 +79,9 @@ class GtkCompositorWidget : public CompositorWidget,
// Resume rendering with to given aXWindow (X11) or nsWindow (Wayland).
void SetRenderingSurface(const uintptr_t aXWindow) override;
+ // Set EGLWindow size to avoid rendering artifacts
+ void SetEGLNativeWindowSize(const LayoutDeviceIntSize& aEGLWindowSize);
+
#if defined(MOZ_X11)
Window XWindow() const { return mProvider.GetXWindow(); }
#endif
@@ -91,8 +94,6 @@ class GtkCompositorWidget : public CompositorWidget,
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
void NotifyFullscreenChanged(bool aIsFullscreen) override;
- GtkCompositorWidget* AsGtkCompositorWidget() override { return this; }
-
UniquePtr<WaylandSurfaceLock> LockSurface();
private:
diff --git a/widget/gtk/WaylandSurface.cpp b/widget/gtk/WaylandSurface.cpp
@@ -792,20 +792,6 @@ void WaylandSurface::SetCeiledScaleLocked(
}
}
-void WaylandSurface::SetRenderingSizeLocked(
- const WaylandSurfaceLock& aProofOfLock, DesktopIntSize aSize) {
- MOZ_DIAGNOSTIC_ASSERT(&aProofOfLock == mSurfaceLock);
- LOGVERBOSE("WaylandSurface::SetRenderingSizeLocked(): size [%d x %d]",
- aSize.width, aSize.height);
- mSize = aSize;
-
- // non-EGL rendering changes are applied at WaylandSurface::AttachLocked().
- // We want to sync size changes with matching buffer.
- if (mViewportFollowsSizeChanges && mEGLWindow) {
- SetViewPortDestLocked(aProofOfLock, aSize);
- }
-}
-
void WaylandSurface::SetViewPortDestLocked(
const WaylandSurfaceLock& aProofOfLock, DesktopIntSize aDestSize) {
MOZ_DIAGNOSTIC_ASSERT(&aProofOfLock == mSurfaceLock);
@@ -972,6 +958,7 @@ wl_egl_window* WaylandSurface::GetEGLWindow(DesktopIntSize aSize) {
WaylandSurfaceLock lock(this);
MOZ_DIAGNOSTIC_ASSERT(mSurface, "Missing wl_surface!");
+ mSize = aSize;
auto scaledSize = GetScaledSize(aSize);
if (!mEGLWindow) {
@@ -990,13 +977,13 @@ wl_egl_window* WaylandSurface::GetEGLWindow(DesktopIntSize aSize) {
wl_egl_window_resize(mEGLWindow, scaledSize.width, scaledSize.height, 0, 0);
}
- SetRenderingSizeLocked(lock, aSize);
return mEGLWindow;
}
void WaylandSurface::SetSize(DesktopIntSize aSize) {
WaylandSurfaceLock lock(this);
+ mSize = aSize;
auto scaledSize = GetScaledSize(aSize);
LOGVERBOSE(
@@ -1004,11 +991,36 @@ void WaylandSurface::SetSize(DesktopIntSize aSize) {
"scale %f scaled [%d x %d]",
aSize.width, aSize.height, GetScale(), scaledSize.width,
scaledSize.height);
+}
+
+void WaylandSurface::ApplyEGLWindowSize(LayoutDeviceIntSize aEGLWindowSize) {
+ WaylandSurfaceLock lock(this);
+
+ auto scale = GetScale();
+ auto surfaceSize = GetScaledSize(mSize);
+ bool sizeMatches = aEGLWindowSize == surfaceSize;
+ LOGWAYLAND(
+ "WaylandSurface::ApplyEGLWindowSize()"
+ " EGL window size [%d x %d] surface (scaled) size [%d x %d] "
+ "fractional scale %f matches %d",
+ aEGLWindowSize.width, aEGLWindowSize.height, surfaceSize.width,
+ surfaceSize.height, scale, sizeMatches);
+
+ if (mViewportFollowsSizeChanges) {
+ DesktopIntSize viewportSize;
+ if (!sizeMatches) {
+ viewportSize = DesktopIntSize::Round(aEGLWindowSize /
+ DesktopToLayoutDeviceScale(scale));
+ } else {
+ viewportSize = mSize;
+ }
+ SetViewPortDestLocked(lock, viewportSize);
+ }
if (mEGLWindow) {
- wl_egl_window_resize(mEGLWindow, scaledSize.width, scaledSize.height, 0, 0);
+ wl_egl_window_resize(mEGLWindow, aEGLWindowSize.width,
+ aEGLWindowSize.height, 0, 0);
}
- SetRenderingSizeLocked(lock, aSize);
}
void WaylandSurface::InvalidateRegionLocked(
diff --git a/widget/gtk/WaylandSurface.h b/widget/gtk/WaylandSurface.h
@@ -74,6 +74,15 @@ class WaylandSurface final {
// Set WaylandSurface target size (viewport & ELG surface if it's present).
void SetSize(DesktopIntSize aSize);
+ // Apply changes to EGLWindow size set by SetSize().
+ // ApplyEGLWindowSize() is called from compostor thread
+ // right before GL rendering to set EGLWindow size / viewport size
+ // for actual back buffer.
+ //
+ // aEGLWindowSize is scaled backbuffer size and it's used similary
+ // as WaylandBuffer size at Attach().
+ void ApplyEGLWindowSize(LayoutDeviceIntSize aEGLWindowSize);
+
// Mapped means we have all internals created.
bool IsMapped() const { return mIsMapped; }
@@ -279,9 +288,6 @@ class WaylandSurface final {
WaylandSurfaceLock* aParentWaylandSurfaceLock,
DesktopIntPoint aSubsurfacePosition, bool aSubsurfaceDesync);
- void SetRenderingSizeLocked(const WaylandSurfaceLock& aProofOfLock,
- DesktopIntSize aSize);
-
wl_surface* Lock(WaylandSurfaceLock* aWaylandSurfaceLock);
void Unlock(struct wl_surface** aSurface,
WaylandSurfaceLock* aWaylandSurfaceLock);
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
@@ -345,6 +345,11 @@ class nsWindow final : public nsIWidget {
GdkWindow* GetToplevelGdkWindow() const;
GtkWidget* GetGtkWidget() const { return mShell; }
nsWindow* GetEffectiveParent();
+#ifdef MOZ_WAYLAND
+ RefPtr<mozilla::widget::WaylandSurface> GetWaylandSurface() {
+ return mSurface;
+ }
+#endif
bool IsDestroyed() const { return mIsDestroyed; }
bool IsPopup() const;
bool IsWaylandPopup() const;