Backed out 7 changesets (bug 1882779) for causing perma mda failures @ test_getUserMedia_basicScreenshare.html

Backed out changeset c7d6f5ba608c (bug 1882779)
Backed out changeset d343fe633520 (bug 1882779)
Backed out changeset dcc81c544c72 (bug 1882779)
Backed out changeset f36a7bafc019 (bug 1882779)
Backed out changeset c621729acdc4 (bug 1882779)
Backed out changeset 5692d5a1b237 (bug 1882779)
Backed out changeset ae204d74a9f7 (bug 1882779)
This commit is contained in:
Sandor Molnar 2024-03-19 16:51:55 +02:00
parent 24246bd5c0
commit 9c939cb9a0
14 changed files with 255 additions and 199 deletions

View File

@ -336,29 +336,23 @@ EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
}
MOZ_ASSERT(aCompositorWidget);
#ifdef MOZ_WAYLAND
// RenderCompositorEGL does not like EGL_NO_SURFACE as it fallbacks
// to SW rendering or claims itself as paused.
// In case we're missing valid native window because aCompositorWidget hidden,
// just create a fallback EGLSurface.
// Actual EGLSurface will be created by widget code later when
// aCompositorWidget becomes visible.
if (widget::GdkIsWaylandDisplay() && aCompositorWidget->IsHidden()) {
mozilla::gfx::IntSize pbSize(16, 16);
return CreateWaylandOffscreenSurface(*egl, aConfig, pbSize);
}
#endif
EGLNativeWindowType window =
GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
if (!window) {
#ifdef MOZ_WIDGET_GTK
// RenderCompositorEGL does not like EGL_NO_SURFACE as it fallbacks
// to SW rendering or claims itself as paused.
// In case we're missing valid native window because aCompositorWidget
// hidden, just create a fallback EGLSurface. Actual EGLSurface will be
// created by widget code later when aCompositorWidget becomes visible.
mozilla::gfx::IntSize pbSize(16, 16);
# ifdef MOZ_WAYLAND
if (GdkIsWaylandDisplay()) {
return CreateWaylandOffscreenSurface(*egl, aConfig, pbSize);
} else
# endif
{
return CreatePBufferSurfaceTryingPowerOfTwo(*egl, aConfig, LOCAL_EGL_NONE,
pbSize);
}
#else
gfxCriticalNote << "window is null";
return EGL_NO_SURFACE;
#endif
}
return mozilla::gl::CreateSurfaceFromNativeWindow(*egl, window, aConfig);
@ -492,6 +486,16 @@ bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
EGLNativeWindowType nativeWindow =
GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
#ifdef MOZ_WAYLAND
// In case we're missing native window on Wayland CompositorWidget is hidden.
// Don't create a fallback EGL surface but fails here.
// We need to repeat RenewSurface() when native window is available
// (CompositorWidget becomes visible).
if (GdkIsWaylandDisplay()) {
NS_WARNING("Failed to get native window");
return false;
}
#endif
if (nativeWindow) {
mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(*mEgl, nativeWindow,
mSurfaceConfig);

View File

@ -38,13 +38,13 @@ void CompositorWidgetChild::NotifyClientSizeChanged(
Unused << SendNotifyClientSizeChanged(aClientSize);
}
void CompositorWidgetChild::CleanupResources() {
Unused << SendCleanupResources();
void CompositorWidgetChild::DisableRendering() {
Unused << SendDisableRendering();
}
void CompositorWidgetChild::SetRenderingSurface(const uintptr_t aXWindow,
const bool aShaped) {
Unused << SendSetRenderingSurface(aXWindow, aShaped);
void CompositorWidgetChild::EnableRendering(const uintptr_t aXWindow,
const bool aShaped) {
Unused << SendEnableRendering(aXWindow, aShaped);
}
} // namespace widget

View File

@ -27,9 +27,8 @@ class CompositorWidgetChild final : public PCompositorWidgetChild,
mozilla::ipc::IPCResult RecvUnobserveVsync() override;
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
void CleanupResources() override;
void SetRenderingSurface(const uintptr_t aXWindow,
const bool aShaped) override;
void DisableRendering() override;
void EnableRendering(const uintptr_t aXWindow, const bool aShaped) override;
private:
RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;

View File

@ -40,14 +40,14 @@ mozilla::ipc::IPCResult CompositorWidgetParent::RecvNotifyClientSizeChanged(
return IPC_OK();
}
mozilla::ipc::IPCResult CompositorWidgetParent::RecvCleanupResources() {
CleanupResources();
mozilla::ipc::IPCResult CompositorWidgetParent::RecvDisableRendering() {
DisableRendering();
return IPC_OK();
}
mozilla::ipc::IPCResult CompositorWidgetParent::RecvSetRenderingSurface(
mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnableRendering(
const uintptr_t& aXWindow, const bool& aShaped) {
SetRenderingSurface(aXWindow, aShaped);
EnableRendering(aXWindow, aShaped);
return IPC_OK();
}

View File

@ -28,9 +28,9 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
mozilla::ipc::IPCResult RecvNotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) override;
mozilla::ipc::IPCResult RecvCleanupResources() override;
mozilla::ipc::IPCResult RecvSetRenderingSurface(const uintptr_t& aXWindow,
const bool& aShaped) override;
mozilla::ipc::IPCResult RecvDisableRendering() override;
mozilla::ipc::IPCResult RecvEnableRendering(const uintptr_t& aXWindow,
const bool& aShaped) override;
private:
RefPtr<VsyncObserver> mVsyncObserver;

View File

@ -40,22 +40,25 @@ GtkCompositorWidget::GtkCompositorWidget(
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
ConfigureX11Backend((Window)aInitData.XWindow(), aInitData.Shaped());
LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p\n",
(void*)mWidget.get(), (void*)aInitData.XWindow());
LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p "
"mIsRenderingSuspended %d\n",
(void*)mWidget.get(), (void*)aInitData.XWindow(),
!!mIsRenderingSuspended);
}
#endif
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
ConfigureWaylandBackend();
LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mWidget %p\n",
(void*)mWidget.get(), (void*)mWidget);
LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mWidget %p "
"mIsRenderingSuspended %d\n",
(void*)mWidget.get(), (void*)mWidget, !!mIsRenderingSuspended);
}
#endif
}
GtkCompositorWidget::~GtkCompositorWidget() {
LOG("GtkCompositorWidget::~GtkCompositorWidget [%p]\n", (void*)mWidget.get());
CleanupResources();
DisableRendering();
RefPtr<nsIWidget> widget = mWidget.forget();
NS_ReleaseOnMainThread("GtkCompositorWidget::mWidget", widget.forget());
}
@ -166,47 +169,57 @@ GtkCompositorWidget::GetNativeLayerRoot() {
}
#endif
void GtkCompositorWidget::CleanupResources() {
LOG("GtkCompositorWidget::CleanupResources [%p]\n", (void*)mWidget.get());
void GtkCompositorWidget::DisableRendering() {
LOG("GtkCompositorWidget::DisableRendering [%p]\n", (void*)mWidget.get());
mIsRenderingSuspended = true;
mProvider.CleanupResources();
}
#if defined(MOZ_WAYLAND)
void GtkCompositorWidget::ConfigureWaylandBackend() {
bool GtkCompositorWidget::ConfigureWaylandBackend() {
mProvider.Initialize(this);
return true;
}
#endif
#if defined(MOZ_X11)
void GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
bool GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
// We don't have X window yet.
if (!aXWindow) {
mProvider.CleanupResources();
return;
mIsRenderingSuspended = true;
return false;
}
// Initialize the window surface provider
mProvider.Initialize(aXWindow, aShaped);
return mProvider.Initialize(aXWindow, aShaped);
}
#endif
void GtkCompositorWidget::SetRenderingSurface(const uintptr_t aXWindow,
const bool aShaped) {
LOG("GtkCompositorWidget::SetRenderingSurface() [%p]\n", mWidget.get());
void GtkCompositorWidget::EnableRendering(const uintptr_t aXWindow,
const bool aShaped) {
LOG("GtkCompositorWidget::EnableRendering() [%p]\n", mWidget.get());
if (!mIsRenderingSuspended) {
LOG(" quit, mIsRenderingSuspended = false\n");
return;
}
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
LOG(" configure widget %p\n", mWidget.get());
ConfigureWaylandBackend();
if (!ConfigureWaylandBackend()) {
return;
}
}
#endif
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
LOG(" configure XWindow %p shaped %d\n", (void*)aXWindow, aShaped);
ConfigureX11Backend((Window)aXWindow, aShaped);
if (!ConfigureX11Backend((Window)aXWindow, aShaped)) {
return;
}
}
#endif
mIsRenderingSuspended = false;
}
#ifdef MOZ_LOGGING
bool GtkCompositorWidget::IsPopup() {
return mWidget ? mWidget->IsPopup() : false;

View File

@ -28,9 +28,9 @@ class PlatformCompositorWidgetDelegate : public CompositorWidgetDelegate {
const LayoutDeviceIntSize& aClientSize) = 0;
virtual GtkCompositorWidget* AsGtkCompositorWidget() { return nullptr; };
virtual void CleanupResources() = 0;
virtual void SetRenderingSurface(const uintptr_t aXWindow,
const bool aShaped) = 0;
virtual void DisableRendering() = 0;
virtual void EnableRendering(const uintptr_t aXWindow,
const bool aShaped) = 0;
// CompositorWidgetDelegate Overrides
@ -74,11 +74,10 @@ class GtkCompositorWidget : public CompositorWidget,
// Suspend rendering of this remote widget and clear all resources.
// Can be used when underlying window is hidden/unmapped.
void CleanupResources() override;
void DisableRendering() override;
// Resume rendering with to given aXWindow (X11) or nsWindow (Wayland).
void SetRenderingSurface(const uintptr_t aXWindow,
const bool aShaped) override;
void EnableRendering(const uintptr_t aXWindow, const bool aShaped) override;
// If we fail to set window size (due to different screen scale or so)
// we can't paint the frame by compositor.
@ -91,6 +90,11 @@ class GtkCompositorWidget : public CompositorWidget,
RefPtr<mozilla::layers::NativeLayerRoot> GetNativeLayerRoot() override;
#endif
bool PreRender(WidgetRenderingContext* aContext) override {
return !mIsRenderingSuspended;
}
bool IsHidden() const override { return mIsRenderingSuspended; }
// PlatformCompositorWidgetDelegate Overrides
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
@ -98,10 +102,10 @@ class GtkCompositorWidget : public CompositorWidget,
private:
#if defined(MOZ_WAYLAND)
void ConfigureWaylandBackend();
bool ConfigureWaylandBackend();
#endif
#if defined(MOZ_X11)
void ConfigureX11Backend(Window aXWindow, bool aShaped);
bool ConfigureX11Backend(Window aXWindow, bool aShaped);
#endif
#ifdef MOZ_LOGGING
bool IsPopup();
@ -125,6 +129,7 @@ class GtkCompositorWidget : public CompositorWidget,
#ifdef MOZ_WAYLAND
RefPtr<mozilla::layers::NativeLayerRootWayland> mNativeLayerRoot;
#endif
Atomic<bool> mIsRenderingSuspended{true};
};
} // namespace widget

View File

@ -87,18 +87,19 @@ void moz_container_class_init(MozContainerClass* klass) {
GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->map = moz_container_map;
widget_class->realize = moz_container_realize;
widget_class->unrealize = moz_container_unrealize;
widget_class->destroy = moz_container_destroy;
#ifdef MOZ_WAYLAND
if (mozilla::widget::GdkIsWaylandDisplay()) {
widget_class->map = moz_container_wayland_map;
widget_class->size_allocate = moz_container_wayland_size_allocate;
widget_class->map_event = moz_container_wayland_map_event;
widget_class->unmap = moz_container_wayland_unmap;
} else {
#endif
widget_class->map = moz_container_map;
widget_class->size_allocate = moz_container_size_allocate;
widget_class->unmap = moz_container_unmap;
#ifdef MOZ_WAYLAND
@ -129,10 +130,6 @@ void moz_container_map(GtkWidget* widget) {
if (gtk_widget_get_has_window(widget)) {
gdk_window_show(gtk_widget_get_window(widget));
}
// Enable rendering to nsWindow/MozContainer
nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget));
window->OnMap();
}
void moz_container_unmap(GtkWidget* widget) {
@ -141,9 +138,9 @@ void moz_container_unmap(GtkWidget* widget) {
LOGCONTAINER(("moz_container_unmap() [%p]",
(void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget))));
// Disable rendering to nsWindow/MozContainer before we really unmap it.
// Disable rendering to MozContainer before we unmap it.
nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget));
window->OnUnmap();
window->DisableRendering();
gtk_widget_set_mapped(widget, FALSE);

View File

@ -419,6 +419,21 @@ gboolean moz_container_wayland_map_event(GtkWidget* widget,
return FALSE;
}
void moz_container_wayland_map(GtkWidget* widget) {
LOGCONTAINER("%s [%p]\n", __FUNCTION__,
(void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)));
g_return_if_fail(IS_MOZ_CONTAINER(widget));
// We need to mark MozContainer as mapped to make sure
// moz_container_wayland_unmap() is called on hide/withdraw.
gtk_widget_set_mapped(widget, TRUE);
if (gtk_widget_get_has_window(widget)) {
gdk_window_show(gtk_widget_get_window(widget));
}
}
void moz_container_wayland_size_allocate(GtkWidget* widget,
GtkAllocation* allocation) {
GtkAllocation tmp_allocation;

View File

@ -22,8 +22,8 @@ parent:
async __delete__();
async NotifyClientSizeChanged(LayoutDeviceIntSize aClientSize);
async CleanupResources();
async SetRenderingSurface(uintptr_t aXWindow, bool aShaped);
async DisableRendering();
async EnableRendering(uintptr_t aXWindow, bool aShaped);
child:

View File

@ -11,7 +11,6 @@
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsWindow.h"
#include "mozilla/ScopeExit.h"
#ifdef MOZ_WAYLAND
# include "mozilla/StaticPrefs_widget.h"
@ -130,13 +129,13 @@ RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
// 2. XPutImage
# ifdef MOZ_HAVE_SHMIMAGE
if (!mIsShaped && nsShmImage::UseShm()) {
LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", (Window)mXWindow));
LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", mXWindow));
return MakeRefPtr<WindowSurfaceX11SHM>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth);
}
# endif // MOZ_HAVE_SHMIMAGE
LOG(("Drawing to Window 0x%lx will use XPutImage\n", (Window)mXWindow));
LOG(("Drawing to Window 0x%lx will use XPutImage\n", mXWindow));
return MakeRefPtr<WindowSurfaceX11Image>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth, mIsShaped);
}
@ -144,11 +143,6 @@ RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
MOZ_RELEASE_ASSERT(false);
}
// We need to ignore thread safety checks here. We need to hold mMutex
// between StartRemoteDrawingInRegion()/EndRemoteDrawingInRegion() calls
// which confuses it.
MOZ_PUSH_IGNORE_THREAD_SAFETY
already_AddRefed<gfx::DrawTarget>
WindowSurfaceProvider::StartRemoteDrawingInRegion(
const LayoutDeviceIntRegion& aInvalidRegion,
@ -157,13 +151,7 @@ WindowSurfaceProvider::StartRemoteDrawingInRegion(
return nullptr;
}
// We return a reference to mWindowSurface inside draw target so we need to
// hold the mutex untill EndRemoteDrawingInRegion() call where draw target
// is returned.
// If we return null dt, EndRemoteDrawingInRegion() won't be called to
// release mutex.
mMutex.Lock();
auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
MutexAutoLock lock(mMutex);
if (!mWindowSurfaceValid) {
mWindowSurface = nullptr;
@ -190,20 +178,12 @@ WindowSurfaceProvider::StartRemoteDrawingInRegion(
dt = mWindowSurface->Lock(aInvalidRegion);
}
#endif
if (dt) {
// We have valid dt, mutex will be released in EndRemoteDrawingInRegion().
unlockMutex.release();
}
return dt.forget();
}
void WindowSurfaceProvider::EndRemoteDrawingInRegion(
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
// Unlock mutex from StartRemoteDrawingInRegion().
mMutex.AssertCurrentThreadOwns();
auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
MutexAutoLock lock(mMutex);
// Commit to mWindowSurface only if we have a valid one.
if (!mWindowSurface || !mWindowSurfaceValid) {
return;
@ -238,7 +218,5 @@ void WindowSurfaceProvider::EndRemoteDrawingInRegion(
mWindowSurface->Commit(aInvalidRegion);
}
MOZ_POP_THREAD_SAFETY
} // namespace widget
} // namespace mozilla

View File

@ -81,7 +81,7 @@ class WindowSurfaceProvider final {
*/
mozilla::Mutex mMutex MOZ_UNANNOTATED;
// WindowSurface needs to be re-created as underlying window was changed.
bool mWindowSurfaceValid;
mozilla::Atomic<bool> mWindowSurfaceValid;
#ifdef MOZ_WAYLAND
RefPtr<nsWindow> mWidget;
// WindowSurfaceProvider is owned by GtkCompositorWidget so we don't need
@ -91,12 +91,7 @@ class WindowSurfaceProvider final {
#ifdef MOZ_X11
bool mIsShaped;
int mXDepth;
// Make mXWindow atomic to allow it read from different threads
// and make tsan happy.
// We don't care much about actual mXWindow value (it may be valid XWindow or
// nullptr) because we invalidate mXWindow at compositor/renderer thread
// before it's release in unmap handler.
Atomic<Window, Relaxed> mXWindow;
Window mXWindow;
Visual* mXVisual;
#endif
};

View File

@ -187,6 +187,8 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor);
/* callbacks from widgets */
static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
static gboolean configure_event_cb(GtkWidget* widget, GdkEventConfigure* event);
static void widget_map_cb(GtkWidget* widget);
static void widget_unmap_cb(GtkWidget* widget);
static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation);
static void toplevel_window_size_allocate_cb(GtkWidget* widget,
GtkAllocation* allocation);
@ -390,11 +392,11 @@ static void GtkWindowSetTransientFor(GtkWindow* aWindow, GtkWindow* aParent) {
nsWindow::nsWindow()
: mTitlebarRectMutex("nsWindow::mTitlebarRectMutex"),
mWindowVisibilityMutex("nsWindow::mWindowVisibilityMutex"),
mIsMapped(false),
mDestroyMutex("nsWindow::mDestroyMutex"),
mIsDestroyed(false),
mIsShown(false),
mNeedsShow(false),
mIsMapped(false),
mEnabled(true),
mCreated(false),
mHandleTouchEvent(false),
@ -579,6 +581,7 @@ void nsWindow::Destroy() {
LOG("nsWindow::Destroy\n");
MutexAutoLock lock(mDestroyMutex);
mIsDestroyed = true;
mCreated = false;
@ -609,9 +612,6 @@ void nsWindow::Destroy() {
NativeShow(false);
MOZ_ASSERT(!gtk_widget_get_mapped(mShell));
MOZ_ASSERT(!gtk_widget_get_mapped(GTK_WIDGET(mContainer)));
ClearTransparencyBitmap();
DestroyLayerManager();
@ -3397,12 +3397,17 @@ void* nsWindow::GetNativeData(uint32_t aDataType) {
case NS_NATIVE_EGL_WINDOW: {
void* eglWindow = nullptr;
// We're called from OnMap() / OnUnmap() handlers,
// disable rendering to missing native widget then.
if (mWindowVisibilityMutex.TryLock()) {
// We don't have native window to render to,
// GL backend will create offscreen buffer for it.
if (mIsMapped) {
// We can't block on mutex here as it leads to a deadlock:
// 1) mutex is taken at nsWindow::Destroy()
// 2) NS_NATIVE_EGL_WINDOW is called from compositor/rendering thread,
// blocking on mutex.
// 3) DestroyCompositor() is called by nsWindow::Destroy(). As a sync
// call it waits to compositor/rendering threads,
// but they're blocked at 2).
// It's fine if we return null EGL window during DestroyCompositor(),
// in such case compositor painting is skipped.
if (mDestroyMutex.TryLock()) {
if (mGdkWindow && !mIsDestroyed) {
#ifdef MOZ_X11
if (GdkIsX11Display()) {
eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow);
@ -3410,13 +3415,20 @@ void* nsWindow::GetNativeData(uint32_t aDataType) {
#endif
#ifdef MOZ_WAYLAND
if (GdkIsWaylandDisplay()) {
eglWindow = moz_container_wayland_get_egl_window(
mContainer, FractionalScaleFactor());
bool hiddenWindow =
mCompositorWidgetDelegate &&
mCompositorWidgetDelegate->AsGtkCompositorWidget() &&
mCompositorWidgetDelegate->AsGtkCompositorWidget()->IsHidden();
if (!hiddenWindow) {
eglWindow = moz_container_wayland_get_egl_window(
mContainer, FractionalScaleFactor());
}
}
#endif
}
mWindowVisibilityMutex.Unlock();
mDestroyMutex.Unlock();
}
LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p",
mGdkWindow, eglWindow);
return eglWindow;
@ -4091,6 +4103,41 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
return FALSE;
}
void nsWindow::OnMap() {
LOG("nsWindow::OnMap");
// Gtk mapped widget to screen. Configure underlying GdkWindow properly
// as our rendering target.
// This call means we have X11 (or Wayland) window we can render to by GL
// so we need to notify compositor about it.
mIsMapped = true;
ConfigureGdkWindow();
}
void nsWindow::OnUnmap() {
LOG("nsWindow::OnUnmap");
mIsMapped = false;
if (mSourceDragContext) {
static auto sGtkDragCancel =
(void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
if (sGtkDragCancel) {
sGtkDragCancel(mSourceDragContext);
mSourceDragContext = nullptr;
}
}
// We don't have valid XWindow any more,
// so clear stored ones at GtkCompositorWidget() for OMTC rendering
// and mSurfaceProvider for legacy rendering.
if (GdkIsX11Display()) {
mSurfaceProvider.CleanupResources();
if (mCompositorWidgetDelegate) {
mCompositorWidgetDelegate->DisableRendering();
}
}
}
void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) {
LOG("nsWindow::OnSizeAllocate %d,%d -> %d x %d\n", aAllocation->x,
aAllocation->y, aAllocation->width, aAllocation->height);
@ -5778,8 +5825,8 @@ bool nsWindow::GetShapedState() {
}
void nsWindow::ConfigureCompositor() {
MOZ_DIAGNOSTIC_ASSERT(mIsMapped);
MOZ_DIAGNOSTIC_ASSERT(mCompositorState == COMPOSITOR_ENABLED);
MOZ_DIAGNOSTIC_ASSERT(mIsMapped);
LOG("nsWindow::ConfigureCompositor()");
auto startCompositing = [self = RefPtr{this}, this]() -> void {
@ -5788,8 +5835,8 @@ void nsWindow::ConfigureCompositor() {
// too late
if (mIsDestroyed || !mIsMapped) {
LOG(" quit, mIsDestroyed = %d mIsMapped = %d", mIsDestroyed,
!!mIsMapped);
LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed,
mIsMapped);
return;
}
// Compositor will be resumed later by ResumeCompositorFlickering().
@ -6311,6 +6358,8 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
G_CALLBACK(settings_xft_dpi_changed_cb), this);
// Widget signals
g_signal_connect(mContainer, "map", G_CALLBACK(widget_map_cb), nullptr);
g_signal_connect(mContainer, "unmap", G_CALLBACK(widget_unmap_cb), nullptr);
g_signal_connect_after(mContainer, "size_allocate",
G_CALLBACK(size_allocate_cb), nullptr);
g_signal_connect(mContainer, "hierarchy-changed",
@ -6657,8 +6706,7 @@ void nsWindow::ResumeCompositorImpl() {
LOG("nsWindow::ResumeCompositorImpl()\n");
MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate);
mCompositorWidgetDelegate->SetRenderingSurface(GetX11Window(),
GetShapedState());
mCompositorWidgetDelegate->EnableRendering(GetX11Window(), GetShapedState());
// As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
// time to start it.
@ -8242,6 +8290,25 @@ static gboolean configure_event_cb(GtkWidget* widget,
return window->OnConfigureEvent(widget, event);
}
// Some Gtk widget code may call gtk_widget_unrealize() which destroys
// mGdkWindow. We need to listen on this signal and re-create
// mGdkWindow when we're already mapped.
static void widget_map_cb(GtkWidget* widget) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
return;
}
window->OnMap();
}
static void widget_unmap_cb(GtkWidget* widget) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
return;
}
window->OnUnmap();
}
static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
@ -9060,7 +9127,7 @@ void nsWindow::DidGetNonBlankPaint() {
void nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) {
LOG("nsWindow::SetCompositorWidgetDelegate %p mIsMapped %d "
"mCompositorWidgetDelegate %p\n",
delegate, !!mIsMapped, mCompositorWidgetDelegate);
delegate, mIsMapped, mCompositorWidgetDelegate);
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (delegate) {
@ -9977,28 +10044,41 @@ nsWindow* nsWindow::GetFocusedWindow() { return gFocusWindow; }
#ifdef MOZ_WAYLAND
bool nsWindow::SetEGLNativeWindowSize(
const LayoutDeviceIntSize& aEGLWindowSize) {
if (!GdkIsWaylandDisplay() || !mIsMapped) {
if (!GdkIsWaylandDisplay()) {
return true;
}
gint scale = GdkCeiledScaleFactor();
// SetEGLNativeWindowSize() is called from renderer/compositor thread,
// make sure nsWindow is not destroyed.
bool paint = false;
// See NS_NATIVE_EGL_WINDOW why we can't block here.
if (mDestroyMutex.TryLock()) {
if (!mIsDestroyed) {
gint scale = GdkCeiledScaleFactor();
# ifdef MOZ_LOGGING
if (LOG_ENABLED()) {
static uintptr_t lastSizeLog = 0;
uintptr_t sizeLog =
uintptr_t(this) + aEGLWindowSize.width + aEGLWindowSize.height + scale +
aEGLWindowSize.width / scale + aEGLWindowSize.height / scale;
if (lastSizeLog != sizeLog) {
lastSizeLog = sizeLog;
LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
"%d x %d)",
aEGLWindowSize.width, aEGLWindowSize.height, scale,
aEGLWindowSize.width / scale, aEGLWindowSize.height / scale);
}
}
if (LOG_ENABLED()) {
static uintptr_t lastSizeLog = 0;
uintptr_t sizeLog = uintptr_t(this) + aEGLWindowSize.width +
aEGLWindowSize.height + scale +
aEGLWindowSize.width / scale +
aEGLWindowSize.height / scale;
if (lastSizeLog != sizeLog) {
lastSizeLog = sizeLog;
LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
"%d x "
"%d)",
aEGLWindowSize.width, aEGLWindowSize.height, scale,
aEGLWindowSize.width / scale, aEGLWindowSize.height / scale);
}
}
# endif
return moz_container_wayland_egl_window_set_size(
mContainer, aEGLWindowSize.ToUnknownSize(), scale);
paint = moz_container_wayland_egl_window_set_size(
mContainer, aEGLWindowSize.ToUnknownSize(), scale);
}
mDestroyMutex.Unlock();
}
return paint;
}
#endif
@ -10015,34 +10095,8 @@ void nsWindow::ClearRenderingQueue() {
DestroyLayerManager();
}
// nsWindow::OnMap() / nsWindow::OnUnmap() is called from map/unmap mContainer
// handlers directly as we paint to mContainer.
void nsWindow::OnMap() {
LOG("nsWindow::OnMap");
// Gtk mapped widget to screen. Configure underlying GdkWindow properly
// as our rendering target.
// This call means we have X11 (or Wayland) window we can render to by GL
// so we need to notify compositor about it.
MutexAutoLock lock(mWindowVisibilityMutex);
mIsMapped = true;
ConfigureGdkWindow();
}
void nsWindow::OnUnmap() {
LOG("nsWindow::OnUnmap");
MutexAutoLock lock(mWindowVisibilityMutex);
mIsMapped = false;
if (mSourceDragContext) {
static auto sGtkDragCancel =
(void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
if (sGtkDragCancel) {
sGtkDragCancel(mSourceDragContext);
mSourceDragContext = nullptr;
}
}
void nsWindow::DisableRendering() {
LOG("nsWindow::DisableRendering()");
if (mGdkWindow) {
if (mIMContext) {
@ -10052,42 +10106,37 @@ void nsWindow::OnUnmap() {
mGdkWindow = nullptr;
}
// Clear resources (mainly XWindow) stored at GtkCompositorWidget.
// It makes sure we don't paint to it when nsWindow becomes hiden/deleted
// and XWindow is released.
if (mCompositorWidgetDelegate) {
mCompositorWidgetDelegate->CleanupResources();
}
// Clear nsWindow resources used for old (in-thread) rendering.
mSurfaceProvider.CleanupResources();
// Until Bug 1654938 is fixed we delete layer manager for hidden popups,
// otherwise it can easily hold 1GB+ memory for long time.
if (mWindowType == WindowType::Popup) {
DestroyLayerManager();
mSurfaceProvider.CleanupResources();
} else {
// Widget is backed by OpenGL EGLSurface created over wl_surface/XWindow.
//
// RenderCompositorEGL::Resume() deletes recent EGLSurface,
// calls nsWindow::GetNativeData(NS_NATIVE_EGL_WINDOW) from compositor
// thread to get new native rendering surface.
//
// For hidden/unmapped windows we return nullptr NS_NATIVE_EGL_WINDOW at
// nsWindow::GetNativeData() so RenderCompositorEGL::Resume() creates
// offscreen fallback EGLSurface to avoid compositor pause.
//
#ifdef MOZ_WAYLAND
// Widget is backed by OpenGL EGLSurface created over wl_surface
// owned by mContainer.
// RenderCompositorEGL::Resume() deletes recent EGLSurface based on
// wl_surface owned by mContainer and creates a new fallback EGLSurface.
// Then we can delete wl_surface in moz_container_wayland_unmap().
// We don't want to pause compositor as it may lead to whole
// browser freeze (Bug 1777664).
//
// If RenderCompositorSWGL compositor is used (SW fallback)
// RenderCompositorSWGL::Resume() only requests full render for next paint
// as wl_surface/XWindow is managed by WindowSurfaceProvider owned
// directly by GtkCompositorWidget and that's covered by
// mCompositorWidgetDelegate->CleanupResources() call above.
if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
remoteRenderer->SendResume();
///
// We don't need to do such operation for SW backend as
// WindowSurfaceWaylandMB::Commit() gets wl_surface from
// MozContainer every commit.
if (moz_container_wayland_has_egl_window(mContainer) &&
mCompositorWidgetDelegate) {
if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
// Call DisableRendering() to make GtkCompositorWidget hidden.
// Then SendResume() will create fallback EGLSurface, see
// GLContextEGL::CreateEGLSurfaceForCompositorWidget().
mCompositorWidgetDelegate->DisableRendering();
remoteRenderer->SendResume();
mCompositorWidgetDelegate->EnableRendering(GetX11Window(),
GetShapedState());
}
}
#endif
}
}

View File

@ -460,6 +460,8 @@ class nsWindow final : public nsBaseWidget {
// rendering queue blocking (see Bug 1782948).
void ClearRenderingQueue();
void DisableRendering();
bool ApplyEnterLeaveMutterWorkaround();
void NotifyOcclusionState(mozilla::widget::OcclusionState aState) override;
@ -630,12 +632,8 @@ class nsWindow final : public nsBaseWidget {
mozilla::Mutex mTitlebarRectMutex;
LayoutDeviceIntRect mTitlebarRect MOZ_GUARDED_BY(mTitlebarRectMutex);
// This mutex protect window visibility changes.
mozilla::Mutex mWindowVisibilityMutex;
mozilla::Mutex mDestroyMutex;
// This track real window visibility from OS perspective.
// It's set by OnMap/OnUnmap which is based on Gtk events.
mozilla::Atomic<bool, mozilla::Relaxed> mIsMapped;
// Has this widget been destroyed yet?
bool mIsDestroyed : 1;
// mIsShown tracks requested visible status from browser perspective, i.e.
@ -647,6 +645,9 @@ class nsWindow final : public nsBaseWidget {
// that the window is not actually visible but we report to browser that
// it is visible (mIsShown == true).
bool mNeedsShow : 1;
// This track real window visibility from OS perspective.
// It's set by OnMap/OnUnmap which is based on Gtk events.
bool mIsMapped : 1;
// is this widget enabled?
bool mEnabled : 1;
// has the native window for this been created yet?