firefox/mozilla-wayland-trunk.patch

520 lines
20 KiB
Diff

Wayland patches from Firefox 63.
diff -up firefox-62.0.3/widget/gtk/mozcontainer.cpp.old firefox-62.0.3/widget/gtk/mozcontainer.cpp
--- firefox-62.0.3/widget/gtk/mozcontainer.cpp.old 2018-10-08 11:52:33.442449788 +0200
+++ firefox-62.0.3/widget/gtk/mozcontainer.cpp 2018-08-21 14:22:12.668885853 +0200
@@ -605,6 +605,15 @@ moz_container_get_wl_surface(MozContaine
return nullptr;
moz_container_map_surface(container);
+ // Set the scale factor for the buffer right after we create it.
+ if (container->surface) {
+ static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
+ dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
+ if (sGdkWindowGetScaleFactorPtr && window) {
+ gint scaleFactor = (*sGdkWindowGetScaleFactorPtr)(window);
+ wl_surface_set_buffer_scale(container->surface, scaleFactor);
+ }
+ }
}
return container->surface;
diff -up firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp.old firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp
--- firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp.old 2018-10-08 11:52:47.907392869 +0200
+++ firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp 2018-09-06 11:01:18.801964790 +0200
@@ -151,8 +151,9 @@ static nsWaylandDisplay* WaylandDisplayG
static void WaylandDisplayRelease(wl_display *aDisplay);
static void WaylandDisplayLoop(wl_display *aDisplay);
-// TODO: is the 60pfs loop correct?
-#define EVENT_LOOP_DELAY (1000/60)
+// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending() with
+// compositor event loop.
+#define EVENT_LOOP_DELAY (1000/240)
// Get WaylandDisplay for given wl_display and actual calling thread.
static nsWaylandDisplay*
@@ -523,7 +524,7 @@ WindowBackBuffer::Detach()
}
bool
-WindowBackBuffer::SetImageDataFromBackBuffer(
+WindowBackBuffer::SetImageDataFromBuffer(
class WindowBackBuffer* aSourceBuffer)
{
if (!IsMatchingSize(aSourceBuffer)) {
@@ -550,6 +551,8 @@ frame_callback_handler(void *data, struc
{
auto surface = reinterpret_cast<WindowSurfaceWayland*>(data);
surface->FrameCallbackHandler();
+
+ gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(time);
}
static const struct wl_callback_listener frame_listener = {
@@ -559,27 +562,40 @@ static const struct wl_callback_listener
WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
: mWindow(aWindow)
, mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay()))
- , mFrontBuffer(nullptr)
- , mBackBuffer(nullptr)
+ , mWaylandBuffer(nullptr)
+ , mBackupBuffer(nullptr)
, mFrameCallback(nullptr)
- , mFrameCallbackSurface(nullptr)
+ , mLastCommittedSurface(nullptr)
, mDisplayThreadMessageLoop(MessageLoop::current())
- , mDirectWlBufferDraw(true)
- , mDelayedCommit(false)
- , mFullScreenDamage(false)
+ , mDelayedCommitHandle(nullptr)
+ , mDrawToWaylandBufferDirectly(true)
+ , mPendingCommit(false)
+ , mWaylandBufferFullScreenDamage(false)
, mIsMainThread(NS_IsMainThread())
+ , mNeedScaleFactorUpdate(true)
{
}
WindowSurfaceWayland::~WindowSurfaceWayland()
{
- delete mFrontBuffer;
- delete mBackBuffer;
+ if (mPendingCommit) {
+ NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
+ }
+
+ if (mDelayedCommitHandle) {
+ // Delete reference to this to prevent WaylandBufferDelayCommitHandler()
+ // operate on released this. mDelayedCommitHandle itself will
+ // be released at WaylandBufferDelayCommitHandler().
+ *mDelayedCommitHandle = nullptr;
+ }
if (mFrameCallback) {
wl_callback_destroy(mFrameCallback);
}
+ delete mWaylandBuffer;
+ delete mBackupBuffer;
+
if (!mIsMainThread) {
// We can be destroyed from main thread even though we was created/used
// in compositor thread. We have to unref/delete WaylandDisplay in compositor
@@ -593,73 +609,64 @@ WindowSurfaceWayland::~WindowSurfaceWayl
}
}
-void
-WindowSurfaceWayland::UpdateScaleFactor()
-{
- wl_surface* waylandSurface = mWindow->GetWaylandSurface();
- if (waylandSurface) {
- wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
- }
-}
-
WindowBackBuffer*
-WindowSurfaceWayland::GetFrontBufferToDraw(int aWidth, int aHeight)
+WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth, int aHeight)
{
- if (!mFrontBuffer) {
- mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
- mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
- return mFrontBuffer;
+ if (!mWaylandBuffer) {
+ mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
+ mBackupBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
+ return mWaylandBuffer;
}
- if (!mFrontBuffer->IsAttached()) {
- if (!mFrontBuffer->IsMatchingSize(aWidth, aHeight)) {
- mFrontBuffer->Resize(aWidth, aHeight);
+ if (!mWaylandBuffer->IsAttached()) {
+ if (!mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
+ mWaylandBuffer->Resize(aWidth, aHeight);
// There's a chance that scale factor has been changed
// when buffer size changed
- UpdateScaleFactor();
+ mNeedScaleFactorUpdate = true;
}
- return mFrontBuffer;
+ return mWaylandBuffer;
}
// Front buffer is used by compositor, draw to back buffer
- if (mBackBuffer->IsAttached()) {
+ if (mBackupBuffer->IsAttached()) {
NS_WARNING("No drawing buffer available");
return nullptr;
}
- MOZ_ASSERT(!mDelayedCommit,
+ MOZ_ASSERT(!mPendingCommit,
"Uncommitted buffer switch, screen artifacts ahead.");
- WindowBackBuffer *tmp = mFrontBuffer;
- mFrontBuffer = mBackBuffer;
- mBackBuffer = tmp;
+ WindowBackBuffer *tmp = mWaylandBuffer;
+ mWaylandBuffer = mBackupBuffer;
+ mBackupBuffer = tmp;
- if (mBackBuffer->IsMatchingSize(aWidth, aHeight)) {
+ if (mBackupBuffer->IsMatchingSize(aWidth, aHeight)) {
// Former front buffer has the same size as a requested one.
// Gecko may expect a content already drawn on screen so copy
// existing data to the new buffer.
- mFrontBuffer->SetImageDataFromBackBuffer(mBackBuffer);
+ mWaylandBuffer->SetImageDataFromBuffer(mBackupBuffer);
// When buffer switches we need to damage whole screen
// (https://bugzilla.redhat.com/show_bug.cgi?id=1418260)
- mFullScreenDamage = true;
+ mWaylandBufferFullScreenDamage = true;
} else {
// Former buffer has different size from the new request. Only resize
// the new buffer and leave gecko to render new whole content.
- mFrontBuffer->Resize(aWidth, aHeight);
+ mWaylandBuffer->Resize(aWidth, aHeight);
}
- return mFrontBuffer;
+ return mWaylandBuffer;
}
already_AddRefed<gfx::DrawTarget>
-WindowSurfaceWayland::LockFrontBuffer(int aWidth, int aHeight)
+WindowSurfaceWayland::LockWaylandBuffer(int aWidth, int aHeight)
{
- WindowBackBuffer* buffer = GetFrontBufferToDraw(aWidth, aHeight);
+ WindowBackBuffer* buffer = GetWaylandBufferToDraw(aWidth, aHeight);
if (buffer) {
return buffer->Lock();
}
- NS_WARNING("WindowSurfaceWayland::LockFrontBuffer(): No buffer available");
+ NS_WARNING("WindowSurfaceWayland::LockWaylandBuffer(): No buffer available");
return nullptr;
}
@@ -687,8 +694,8 @@ WindowSurfaceWayland::LockImageSurface(c
A) Lock() is called to whole surface. In that case we don't need
to clip/buffer the drawing and we can return wl_buffer directly
for drawing.
- - mFrontBuffer is available - that's an ideal situation.
- - mFrontBuffer is locked by compositor - flip buffers and draw.
+ - mWaylandBuffer is available - that's an ideal situation.
+ - mWaylandBuffer is locked by compositor - flip buffers and draw.
- if we can't flip buffers - go B)
B) Lock() is requested for part(s) of screen. We need to provide temporary
@@ -704,30 +711,30 @@ WindowSurfaceWayland::Lock(const LayoutD
gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
// Are we asked for entire nsWindow to draw?
- mDirectWlBufferDraw = (aRegion.GetNumRects() == 1 &&
- bounds.x == 0 && bounds.y == 0 &&
- lockSize.width == screenRect.width &&
- lockSize.height == screenRect.height);
-
- if (mDirectWlBufferDraw) {
- RefPtr<gfx::DrawTarget> dt = LockFrontBuffer(screenRect.width,
- screenRect.height);
+ mDrawToWaylandBufferDirectly = (aRegion.GetNumRects() == 1 &&
+ bounds.x == 0 && bounds.y == 0 &&
+ lockSize.width == screenRect.width &&
+ lockSize.height == screenRect.height);
+
+ if (mDrawToWaylandBufferDirectly) {
+ RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(screenRect.width,
+ screenRect.height);
if (dt) {
return dt.forget();
}
// We don't have any front buffer available. Try indirect drawing
// to mImageSurface which is mirrored to front buffer at commit.
- mDirectWlBufferDraw = false;
+ mDrawToWaylandBufferDirectly = false;
}
return LockImageSurface(lockSize);
}
bool
-WindowSurfaceWayland::CommitImageSurface(const LayoutDeviceIntRegion& aRegion)
+WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion)
{
- MOZ_ASSERT(!mDirectWlBufferDraw);
+ MOZ_ASSERT(!mDrawToWaylandBufferDirectly);
LayoutDeviceIntRect screenRect = mWindow->GetBounds();
gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
@@ -737,8 +744,8 @@ WindowSurfaceWayland::CommitImageSurface
return false;
}
- RefPtr<gfx::DrawTarget> dt = LockFrontBuffer(screenRect.width,
- screenRect.height);
+ RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(screenRect.width,
+ screenRect.height);
RefPtr<gfx::SourceSurface> surf =
gfx::Factory::CreateSourceSurfaceForCairoSurface(mImageSurface->CairoSurface(),
mImageSurface->GetSize(),
@@ -766,92 +773,145 @@ WindowSurfaceWayland::CommitImageSurface
return true;
}
+static void
+WaylandBufferDelayCommitHandler(WindowSurfaceWayland **aSurface)
+{
+ if (*aSurface) {
+ (*aSurface)->DelayedCommitHandler();
+ } else {
+ // Referenced WindowSurfaceWayland is already deleted.
+ // Do nothing but just release the mDelayedCommitHandle allocated at
+ // WindowSurfaceWayland::CommitWaylandBuffer().
+ free(aSurface);
+ }
+}
+
void
-WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
+WindowSurfaceWayland::CommitWaylandBuffer()
{
- MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
+ MOZ_ASSERT(mPendingCommit, "Committing empty surface!");
wl_surface* waylandSurface = mWindow->GetWaylandSurface();
if (!waylandSurface) {
- // Target window is already destroyed - don't bother to render there.
- NS_WARNING("WindowSurfaceWayland::Commit(): parent wl_surface is already hidden/deleted.");
+ // Target window is not created yet - delay the commit. This can happen only
+ // when the window is newly created and there's no active
+ // frame callback pending.
+ MOZ_ASSERT(!mFrameCallback || waylandSurface != mLastCommittedSurface,
+ "Missing wayland surface at frame callback!");
+
+ // Do nothing if there's already mDelayedCommitHandle pending.
+ if (!mDelayedCommitHandle) {
+ mDelayedCommitHandle = static_cast<WindowSurfaceWayland**>(
+ moz_xmalloc(sizeof(*mDelayedCommitHandle)));
+ *mDelayedCommitHandle = this;
+
+ MessageLoop::current()->PostDelayedTask(
+ NewRunnableFunction("WaylandBackBufferCommit",
+ &WaylandBufferDelayCommitHandler,
+ mDelayedCommitHandle),
+ EVENT_LOOP_DELAY);
+ }
return;
}
wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
mWaylandDisplay->GetEventQueue());
- if (!mDirectWlBufferDraw) {
- // We have new content at mImageSurface - copy data to mFrontBuffer first.
- CommitImageSurface(aInvalidRegion);
+ // We have an active frame callback request so handle it.
+ if (mFrameCallback) {
+ if (waylandSurface == mLastCommittedSurface) {
+ // We have an active frame callback pending from our recent surface.
+ // It means we should defer the commit to FrameCallbackHandler().
+ return;
+ }
+ // If our stored wl_surface does not match the actual one it means the frame
+ // callback is no longer active and we should release it.
+ wl_callback_destroy(mFrameCallback);
+ mFrameCallback = nullptr;
+ mLastCommittedSurface = nullptr;
}
- if (mFullScreenDamage) {
+ if (mWaylandBufferFullScreenDamage) {
LayoutDeviceIntRect rect = mWindow->GetBounds();
wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height);
- mFullScreenDamage = false;
+ mWaylandBufferFullScreenDamage = false;
} else {
- for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
+ gint scaleFactor = mWindow->GdkScaleFactor();
+ for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done(); iter.Next()) {
const mozilla::LayoutDeviceIntRect &r = iter.Get();
- wl_surface_damage(waylandSurface, r.x, r.y, r.width, r.height);
+ // We need to remove the scale factor because the wl_surface_damage
+ // also multiplies by current scale factor.
+ wl_surface_damage(waylandSurface, r.x/scaleFactor, r.y/scaleFactor,
+ r.width/scaleFactor, r.height/scaleFactor);
}
}
- // Frame callback is always connected to actual wl_surface. When the surface
- // is unmapped/deleted the frame callback is never called. Unfortunatelly
- // we don't know if the frame callback is not going to be called.
- // But our mozcontainer code deletes wl_surface when the GdkWindow is hidden
- // creates a new one when is visible.
- if (mFrameCallback && mFrameCallbackSurface == waylandSurface) {
- // Do nothing here - we have a valid wl_surface and the buffer will be
- // commited to compositor in next frame callback event.
- mDelayedCommit = true;
- return;
- } else {
- if (mFrameCallback) {
- // Delete frame callback connected to obsoleted wl_surface.
- wl_callback_destroy(mFrameCallback);
- }
+ // Clear all back buffer damage as we're committing
+ // all requested regions.
+ mWaylandBufferDamage.SetEmpty();
+
+ mFrameCallback = wl_surface_frame(waylandSurface);
+ wl_callback_add_listener(mFrameCallback, &frame_listener, this);
- mFrameCallback = wl_surface_frame(waylandSurface);
- wl_callback_add_listener(mFrameCallback, &frame_listener, this);
- mFrameCallbackSurface = waylandSurface;
-
- // There's no pending frame callback so we can draw immediately
- // and create frame callback for possible subsequent drawing.
- mFrontBuffer->Attach(waylandSurface);
- mDelayedCommit = false;
+ if (mNeedScaleFactorUpdate || mLastCommittedSurface != waylandSurface) {
+ wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
+ mNeedScaleFactorUpdate = false;
}
+
+ mWaylandBuffer->Attach(waylandSurface);
+ mLastCommittedSurface = waylandSurface;
+
+ // There's no pending commit, all changes are sent to compositor.
+ mPendingCommit = false;
+}
+
+void
+WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
+{
+ MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
+
+ // We have new content at mImageSurface - copy data to mWaylandBuffer first.
+ if (!mDrawToWaylandBufferDirectly) {
+ CommitImageSurfaceToWaylandBuffer(aInvalidRegion);
+ }
+
+ // If we're not at fullscreen damage add drawing area from aInvalidRegion
+ if (!mWaylandBufferFullScreenDamage) {
+ mWaylandBufferDamage.OrWith(aInvalidRegion);
+ }
+
+ // We're ready to commit.
+ mPendingCommit = true;
+ CommitWaylandBuffer();
}
void
WindowSurfaceWayland::FrameCallbackHandler()
{
MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
+ MOZ_ASSERT(mFrameCallback != nullptr,
+ "FrameCallbackHandler() called without valid frame callback!");
+ MOZ_ASSERT(mLastCommittedSurface != nullptr,
+ "FrameCallbackHandler() called without valid wl_surface!");
- if (mFrameCallback) {
- wl_callback_destroy(mFrameCallback);
- mFrameCallback = nullptr;
- mFrameCallbackSurface = nullptr;
+ wl_callback_destroy(mFrameCallback);
+ mFrameCallback = nullptr;
+
+ if (mPendingCommit) {
+ CommitWaylandBuffer();
}
+}
- if (mDelayedCommit) {
- wl_surface* waylandSurface = mWindow->GetWaylandSurface();
- if (!waylandSurface) {
- // Target window is already destroyed - don't bother to render there.
- NS_WARNING("WindowSurfaceWayland::FrameCallbackHandler(): parent wl_surface is already hidden/deleted.");
- return;
- }
- wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
- mWaylandDisplay->GetEventQueue());
+void
+WindowSurfaceWayland::DelayedCommitHandler()
+{
+ MOZ_ASSERT(mDelayedCommitHandle != nullptr, "Missing mDelayedCommitHandle!");
- // Send pending surface to compositor and register frame callback
- // for possible subsequent drawing.
- mFrameCallback = wl_surface_frame(waylandSurface);
- wl_callback_add_listener(mFrameCallback, &frame_listener, this);
- mFrameCallbackSurface = waylandSurface;
+ *mDelayedCommitHandle = nullptr;
+ free(mDelayedCommitHandle);
+ mDelayedCommitHandle = nullptr;
- mFrontBuffer->Attach(waylandSurface);
- mDelayedCommit = false;
+ if (mPendingCommit) {
+ CommitWaylandBuffer();
}
}
diff -up firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h.old firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h
--- firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h.old 2018-10-08 11:52:52.154376159 +0200
+++ firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h 2018-09-06 11:01:18.802964787 +0200
@@ -74,7 +74,7 @@ public:
bool IsAttached() { return mAttached; }
bool Resize(int aWidth, int aHeight);
- bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer);
+ bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer);
bool IsMatchingSize(int aWidth, int aHeight)
{
@@ -111,28 +111,32 @@ public:
already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
void FrameCallbackHandler();
+ void DelayedCommitHandler();
private:
- WindowBackBuffer* GetFrontBufferToDraw(int aWidth, int aHeight);
- void UpdateScaleFactor();
+ WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight);
- already_AddRefed<gfx::DrawTarget> LockFrontBuffer(int aWidth, int aHeight);
+ already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(int aWidth, int aHeight);
already_AddRefed<gfx::DrawTarget> LockImageSurface(const gfx::IntSize& aLockSize);
- bool CommitImageSurface(const LayoutDeviceIntRegion& aRegion);
+ bool CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion);
+ void CommitWaylandBuffer();
// TODO: Do we need to hold a reference to nsWindow object?
nsWindow* mWindow;
nsWaylandDisplay* mWaylandDisplay;
- WindowBackBuffer* mFrontBuffer;
- WindowBackBuffer* mBackBuffer;
+ WindowBackBuffer* mWaylandBuffer;
+ LayoutDeviceIntRegion mWaylandBufferDamage;
+ WindowBackBuffer* mBackupBuffer;
RefPtr<gfxImageSurface> mImageSurface;
wl_callback* mFrameCallback;
- wl_surface* mFrameCallbackSurface;
+ wl_surface* mLastCommittedSurface;
MessageLoop* mDisplayThreadMessageLoop;
- bool mDirectWlBufferDraw;
- bool mDelayedCommit;
- bool mFullScreenDamage;
+ WindowSurfaceWayland** mDelayedCommitHandle;
+ bool mDrawToWaylandBufferDirectly;
+ bool mPendingCommit;
+ bool mWaylandBufferFullScreenDamage;
bool mIsMainThread;
+ bool mNeedScaleFactorUpdate;
};
} // namespace widget