Added wayland patches

This commit is contained in:
Ondrej Zoder 2018-07-17 08:56:42 +02:00
parent 1d55a59366
commit e963c8683d
7 changed files with 975 additions and 0 deletions

View File

@ -181,6 +181,12 @@ Patch563: rb245262.patch
Patch564: mozilla-1464808.patch
Patch565: mozilla-1464823.patch
Patch566: mozilla-1466473.patch
Patch567: mozilla-1444437.patch
Patch568: mozilla-1441743.patch
Patch569: mozilla-1465371.patch
Patch570: mozilla-1467125.patch
Patch571: mozilla-1468670.patch
Patch572: mozilla-1467128.patch
# Debian patches
Patch500: mozilla-440908.patch
@ -389,6 +395,12 @@ This package contains results of tests executed during build.
%patch564 -p1 -b .mozilla-1464808
%patch565 -p1 -b .mozilla-1464823
%patch566 -p1 -b .mozilla-1466473
%patch567 -p1 -b .mozilla-1444437
%patch568 -p1 -b .mozilla-1441743
%patch569 -p1 -b .mozilla-1465371
%patch570 -p1 -b .mozilla-1467125
%patch571 -p1 -b .mozilla-1468670
%patch572 -p1 -b .mozilla-1467128
%endif
%{__rm} -f .mozconfig

336
mozilla-1441743.patch Normal file
View File

@ -0,0 +1,336 @@
diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -3,16 +3,17 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
#include <prthread.h>
+#include "mozilla/gfx/Types.h"
namespace mozilla {
namespace widget {
// Our general connection to Wayland display server,
// holds our display connection and runs event loop.
class nsWaylandDisplay : public nsISupports {
NS_DECL_THREADSAFE_ISUPPORTS
@@ -61,17 +62,17 @@ private:
};
// Holds actual graphics data for wl_surface
class WindowBackBuffer {
public:
WindowBackBuffer(nsWaylandDisplay* aDisplay, int aWidth, int aHeight);
~WindowBackBuffer();
- already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion);
+ already_AddRefed<gfx::DrawTarget> Lock();
void Attach(wl_surface* aSurface);
void Detach();
bool IsAttached() { return mAttached; }
bool Resize(int aWidth, int aHeight);
bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer);
@@ -107,27 +108,33 @@ public:
WindowSurfaceWayland(nsWindow *aWindow);
~WindowSurfaceWayland();
already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion) override;
void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
void FrameCallbackHandler();
private:
- WindowBackBuffer* GetBufferToDraw(int aWidth, int aHeight);
+ WindowBackBuffer* GetFrontBufferToDraw(int aWidth, int aHeight);
void UpdateScaleFactor();
+ already_AddRefed<gfx::DrawTarget> LockFrontBuffer(int aWidth, int aHeight);
+ already_AddRefed<gfx::DrawTarget> LockImageSurface(const gfx::IntSize& aLockSize);
+ bool CommitImageSurface(const LayoutDeviceIntRegion& aRegion);
+
// TODO: Do we need to hold a reference to nsWindow object?
nsWindow* mWindow;
nsWaylandDisplay* mWaylandDisplay;
WindowBackBuffer* mFrontBuffer;
WindowBackBuffer* mBackBuffer;
+ RefPtr<gfxImageSurface> mImageSurface;
wl_callback* mFrameCallback;
wl_surface* mFrameCallbackSurface;
MessageLoop* mDisplayThreadMessageLoop;
+ bool mDirectWlBufferDraw;
bool mDelayedCommit;
bool mFullScreenDamage;
bool mIsMainThread;
};
} // namespace widget
} // namespace mozilla
diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -299,16 +299,17 @@ nsWaylandDisplay::Matches(wl_display *aD
}
NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
: mThreadId(PR_GetCurrentThread())
// gfx::SurfaceFormat::B8G8R8A8 is a basic Wayland format
// and is always present.
+ // TODO: Provide also format without alpha (Bug 1470126).
, mFormat(gfx::SurfaceFormat::B8G8R8A8)
, mShm(nullptr)
, mDisplay(aDisplay)
{
if (NS_IsMainThread()) {
// Use default event queue in main thread operated by Gtk+.
mEventQueue = nullptr;
} else {
@@ -530,21 +531,19 @@ WindowBackBuffer::SetImageDataFromBackBu
}
mShmPool.SetImageDataFromPool(&aSourceBuffer->mShmPool,
aSourceBuffer->mWidth * aSourceBuffer->mHeight * BUFFER_BPP);
return true;
}
already_AddRefed<gfx::DrawTarget>
-WindowBackBuffer::Lock(const LayoutDeviceIntRegion& aRegion)
+WindowBackBuffer::Lock()
{
- gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
- gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
-
+ gfx::IntSize lockSize(mWidth, mHeight);
return gfxPlatform::CreateDrawTargetForData(static_cast<unsigned char*>(mShmPool.GetImageData()),
lockSize,
BUFFER_BPP * mWidth,
mWaylandDisplay->GetSurfaceFormat());
}
static void
frame_callback_handler(void *data, struct wl_callback *callback, uint32_t time)
@@ -560,16 +559,17 @@ static const struct wl_callback_listener
WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
: mWindow(aWindow)
, mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay()))
, mFrontBuffer(nullptr)
, mBackBuffer(nullptr)
, mFrameCallback(nullptr)
, mFrameCallbackSurface(nullptr)
, mDisplayThreadMessageLoop(MessageLoop::current())
+ , mDirectWlBufferDraw(true)
, mDelayedCommit(false)
, mFullScreenDamage(false)
, mIsMainThread(NS_IsMainThread())
{
}
WindowSurfaceWayland::~WindowSurfaceWayland()
{
@@ -598,17 +598,17 @@ WindowSurfaceWayland::UpdateScaleFactor(
{
wl_surface* waylandSurface = mWindow->GetWaylandSurface();
if (waylandSurface) {
wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
}
}
WindowBackBuffer*
-WindowSurfaceWayland::GetBufferToDraw(int aWidth, int aHeight)
+WindowSurfaceWayland::GetFrontBufferToDraw(int aWidth, int aHeight)
{
if (!mFrontBuffer) {
mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
return mFrontBuffer;
}
if (!mFrontBuffer->IsAttached()) {
@@ -647,46 +647,149 @@ WindowSurfaceWayland::GetBufferToDraw(in
// the new buffer and leave gecko to render new whole content.
mFrontBuffer->Resize(aWidth, aHeight);
}
return mFrontBuffer;
}
already_AddRefed<gfx::DrawTarget>
+WindowSurfaceWayland::LockFrontBuffer(int aWidth, int aHeight)
+{
+ WindowBackBuffer* buffer = GetFrontBufferToDraw(aWidth, aHeight);
+ if (buffer) {
+ return buffer->Lock();
+ }
+
+ NS_WARNING("WindowSurfaceWayland::LockFrontBuffer(): No buffer available");
+ return nullptr;
+}
+
+already_AddRefed<gfx::DrawTarget>
+WindowSurfaceWayland::LockImageSurface(const gfx::IntSize& aLockSize)
+{
+ if (!mImageSurface || mImageSurface->CairoStatus() ||
+ !(aLockSize <= mImageSurface->GetSize())) {
+ mImageSurface = new gfxImageSurface(aLockSize,
+ SurfaceFormatToImageFormat(mWaylandDisplay->GetSurfaceFormat()));
+ if (mImageSurface->CairoStatus()) {
+ return nullptr;
+ }
+ }
+
+ return gfxPlatform::CreateDrawTargetForData(mImageSurface->Data(),
+ mImageSurface->GetSize(),
+ mImageSurface->Stride(),
+ mWaylandDisplay->GetSurfaceFormat());
+}
+
+/*
+ There are some situations which can happen here:
+
+ 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.
+ - if we can't flip buffers - go B)
+
+ B) Lock() is requested for part(s) of screen. We need to provide temporary
+ surface to draw into and copy result (clipped) to target wl_surface.
+ */
+already_AddRefed<gfx::DrawTarget>
WindowSurfaceWayland::Lock(const LayoutDeviceIntRegion& aRegion)
{
MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
- // We allocate back buffer to widget size but return only
- // portion requested by aRegion.
- LayoutDeviceIntRect rect = mWindow->GetBounds();
- WindowBackBuffer* buffer = GetBufferToDraw(rect.width,
- rect.height);
- if (!buffer) {
- NS_WARNING("No drawing buffer available");
- return nullptr;
+ LayoutDeviceIntRect screenRect = mWindow->GetBounds();
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+ 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);
+ 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;
}
- return buffer->Lock(aRegion);
+ return LockImageSurface(lockSize);
+}
+
+bool
+WindowSurfaceWayland::CommitImageSurface(const LayoutDeviceIntRegion& aRegion)
+{
+ MOZ_ASSERT(!mDirectWlBufferDraw);
+
+ LayoutDeviceIntRect screenRect = mWindow->GetBounds();
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+
+ gfx::Rect rect(bounds);
+ if (rect.IsEmpty()) {
+ return false;
+ }
+
+ RefPtr<gfx::DrawTarget> dt = LockFrontBuffer(screenRect.width,
+ screenRect.height);
+ RefPtr<gfx::SourceSurface> surf =
+ gfx::Factory::CreateSourceSurfaceForCairoSurface(mImageSurface->CairoSurface(),
+ mImageSurface->GetSize(),
+ mImageSurface->Format());
+ if (!dt || !surf) {
+ return false;
+ }
+
+ uint32_t numRects = aRegion.GetNumRects();
+ if (numRects != 1) {
+ AutoTArray<IntRect, 32> rects;
+ rects.SetCapacity(numRects);
+ for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
+ rects.AppendElement(iter.Get().ToUnknownRect());
+ }
+ dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length());
+ }
+
+ dt->DrawSurface(surf, rect, rect);
+
+ if (numRects != 1) {
+ dt->PopClip();
+ }
+
+ return true;
}
void
WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
{
MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
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.");
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);
+ }
+
if (mFullScreenDamage) {
LayoutDeviceIntRect rect = mWindow->GetBounds();
wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height);
mFullScreenDamage = false;
} else {
for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
const mozilla::LayoutDeviceIntRect &r = iter.Get();
wl_surface_damage(waylandSurface, r.x, r.y, r.width, r.height);
@@ -730,17 +833,17 @@ WindowSurfaceWayland::FrameCallbackHandl
mFrameCallback = nullptr;
mFrameCallbackSurface = nullptr;
}
if (mDelayedCommit) {
wl_surface* waylandSurface = mWindow->GetWaylandSurface();
if (!waylandSurface) {
// Target window is already destroyed - don't bother to render there.
- NS_WARNING("No drawing buffer available");
+ NS_WARNING("WindowSurfaceWayland::FrameCallbackHandler(): parent wl_surface is already hidden/deleted.");
return;
}
wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
mWaylandDisplay->GetEventQueue());
// Send pending surface to compositor and register frame callback
// for possible subsequent drawing.
mFrameCallback = wl_surface_frame(waylandSurface);

81
mozilla-1444437.patch Normal file
View File

@ -0,0 +1,81 @@
diff -up firefox-61.0.1/widget/gtk/mozcontainer.cpp.mozilla-1444437 firefox-61.0.1/widget/gtk/mozcontainer.cpp
--- firefox-61.0.1/widget/gtk/mozcontainer.cpp.mozilla-1444437 2018-07-16 16:38:36.059138061 +0200
+++ firefox-61.0.1/widget/gtk/mozcontainer.cpp 2018-07-16 17:04:10.127003844 +0200
@@ -212,6 +212,7 @@ moz_container_init (MozContainer *contai
container->surface = nullptr;
container->subsurface = nullptr;
container->eglwindow = nullptr;
+ container->parent_surface_committed = false;
GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
@@ -231,6 +232,15 @@ moz_container_init (MozContainer *contai
}
#if defined(MOZ_WAYLAND)
+static void
+moz_container_commited_handler(GdkFrameClock *clock, MozContainer *container)
+{
+ container->parent_surface_committed = true;
+ g_signal_handler_disconnect(clock,
+ container->parent_surface_committed_handler);
+ container->parent_surface_committed_handler = 0;
+}
+
/* We want to draw to GdkWindow owned by mContainer from Compositor thread but
* Gtk+ can be used in main thread only. So we create wayland wl_surface
* and attach it as an overlay to GdkWindow.
@@ -256,6 +266,21 @@ moz_container_map_surface(MozContainer *
if (container->subsurface && container->surface)
return true;
+ if (!container->parent_surface_committed) {
+ if (!container->parent_surface_committed_handler) {
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
+ static auto sGdkWindowGetFrameClock =
+ (GdkFrameClock *(*)(GdkWindow *))
+ dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
+ GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
+ container->parent_surface_committed_handler =
+ g_signal_connect_after(clock, "after-paint",
+ G_CALLBACK(moz_container_commited_handler),
+ container);
+ }
+ return false;
+ }
+
if (!container->surface) {
struct wl_compositor *compositor;
compositor = sGdkWaylandDisplayGetWlCompositor(display);
@@ -298,6 +323,19 @@ moz_container_unmap_surface(MozContainer
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->parent_surface_committed_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->parent_surface_committed_handler);
+ container->parent_surface_committed_handler = 0;
+ }
+ container->parent_surface_committed = false;
}
#endif
diff -up firefox-61.0.1/widget/gtk/mozcontainer.h.mozilla-1444437 firefox-61.0.1/widget/gtk/mozcontainer.h
--- firefox-61.0.1/widget/gtk/mozcontainer.h.mozilla-1444437 2018-07-16 16:38:36.059138061 +0200
+++ firefox-61.0.1/widget/gtk/mozcontainer.h 2018-07-16 16:38:36.105138588 +0200
@@ -73,6 +73,8 @@ struct _MozContainer
struct wl_surface *surface;
struct wl_subsurface *subsurface;
struct wl_egl_window *eglwindow;
+ gboolean parent_surface_committed;
+ gulong parent_surface_committed_handler;
#endif
};

59
mozilla-1465371.patch Normal file
View File

@ -0,0 +1,59 @@
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1700,31 +1700,25 @@ ParseRemoteCommandLine(nsCString& progra
return REMOTE_FOUND;
}
static RemoteResult
StartRemoteClient(const char* aDesktopStartupID,
nsCString& program,
const char* profile,
- const char* username,
- bool aIsX11Display)
+ const char* username)
{
nsAutoPtr<nsRemoteClient> client;
- if (aIsX11Display) {
- client = new XRemoteClient();
- } else {
#if defined(MOZ_ENABLE_DBUS) && defined(MOZ_WAYLAND)
- client = new DBusRemoteClient();
+ client = new DBusRemoteClient();
#else
- MOZ_ASSERT(false, "Missing remote implementation!");
- return REMOTE_NOT_FOUND;
+ client = new XRemoteClient();
#endif
- }
nsresult rv = client->Init();
if (NS_FAILED(rv))
return REMOTE_NOT_FOUND;
nsCString response;
bool success = false;
rv = client->SendCommandLine(program.get(), username, profile,
@@ -4070,18 +4064,17 @@ XREMain::XRE_mainStartup(bool* aExitFlag
NS_WARNING("Cannot lock XRemote start mutex");
}
}
// Try to remote the entire command line. If this fails, start up normally.
const char* desktopStartupIDPtr =
mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
- rr = StartRemoteClient(desktopStartupIDPtr, program, profile, username,
- GDK_IS_X11_DISPLAY(mGdkDisplay));
+ rr = StartRemoteClient(desktopStartupIDPtr, program, profile, username);
if (rr == REMOTE_FOUND) {
*aExitFlag = true;
return 0;
}
if (rr == REMOTE_ARG_BAD) {
return 1;
}
}

26
mozilla-1467125.patch Normal file
View File

@ -0,0 +1,26 @@
diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -146,18 +146,19 @@ static StaticMutex gWaylandDisplaysMutex
//
// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
// compositor (not the main) thread.
static nsWaylandDisplay* WaylandDisplayGet(wl_display *aDisplay);
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*
WaylandDisplayGetLocked(wl_display *aDisplay, const StaticMutexAutoLock&)
{
nsWaylandDisplay* waylandDisplay = nullptr;
int len = gWaylandDisplays.Count();

359
mozilla-1467128.patch Normal file
View File

@ -0,0 +1,359 @@
diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -102,23 +102,42 @@ public:
#endif
#ifdef MOZ_X11
Display* GetCompositorDisplay() {
return mCompositorDisplay;
}
#endif // MOZ_X11
+#ifdef MOZ_WAYLAND
+ void SetWaylandLastVsync(uint32_t aVsyncTimestamp) {
+ mWaylandLastVsyncTimestamp = aVsyncTimestamp;
+ }
+ int64_t GetWaylandLastVsync() {
+ return mWaylandLastVsyncTimestamp;
+ }
+ void SetWaylandFrameDelay(int64_t aFrameDelay) {
+ mWaylandFrameDelay = aFrameDelay;
+ }
+ int64_t GetWaylandFrameDelay() {
+ return mWaylandFrameDelay;
+ }
+#endif
+
protected:
bool CheckVariationFontSupport() override;
int8_t mMaxGenericSubstitutions;
private:
virtual void GetPlatformCMSOutputProfile(void *&mem,
size_t &size) override;
#ifdef MOZ_X11
Display* mCompositorDisplay;
#endif
+#ifdef MOZ_WAYLAND
+ int64_t mWaylandLastVsyncTimestamp;
+ int64_t mWaylandFrameDelay;
+#endif
};
#endif /* GFX_PLATFORM_GTK_H */
diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -46,16 +46,20 @@
#include "GLContextGLX.h"
#include "GLXLibrary.h"
/* Undefine the Status from Xlib since it will conflict with system headers on OSX */
#if defined(__APPLE__) && defined(Status)
#undef Status
#endif
+#ifdef MOZ_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
+
#endif /* MOZ_X11 */
#include <fontconfig/fontconfig.h>
#include "nsMathUtils.h"
#define GDK_PIXMAP_SIZE_MAX 32767
@@ -89,16 +93,22 @@ gfxPlatformGtk::gfxPlatformGtk()
#ifdef MOZ_X11
if (gfxPlatform::IsHeadless() && GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
mCompositorDisplay = XOpenDisplay(nullptr);
MOZ_ASSERT(mCompositorDisplay, "Failed to create compositor display!");
} else {
mCompositorDisplay = nullptr;
}
#endif // MOZ_X11
+#ifdef MOZ_WAYLAND
+ // Wayland compositors use g_get_monotonic_time() to get timestamps.
+ mWaylandLastVsyncTimestamp = (g_get_monotonic_time() / 1000);
+ // Set default display fps to 60
+ mWaylandFrameDelay = 1000/60;
+#endif
}
gfxPlatformGtk::~gfxPlatformGtk()
{
#ifdef MOZ_X11
if (mCompositorDisplay) {
XCloseDisplay(mCompositorDisplay);
}
@@ -505,26 +515,26 @@ gfxPlatformGtk::CheckVariationFontSuppor
// until at least 2.7.1.
FT_Int major, minor, patch;
FT_Library_Version(GetFTLibrary(), &major, &minor, &patch);
return major * 1000000 + minor * 1000 + patch >= 2007001;
}
#ifdef MOZ_X11
-class GLXVsyncSource final : public VsyncSource
+class GtkVsyncSource final : public VsyncSource
{
public:
- GLXVsyncSource()
+ GtkVsyncSource()
{
MOZ_ASSERT(NS_IsMainThread());
mGlobalDisplay = new GLXDisplay();
}
- virtual ~GLXVsyncSource()
+ virtual ~GtkVsyncSource()
{
MOZ_ASSERT(NS_IsMainThread());
}
virtual Display& GetGlobalDisplay() override
{
return *mGlobalDisplay;
}
@@ -536,39 +546,52 @@ public:
public:
GLXDisplay() : mGLContext(nullptr)
, mXDisplay(nullptr)
, mSetupLock("GLXVsyncSetupLock")
, mVsyncThread("GLXVsyncThread")
, mVsyncTask(nullptr)
, mVsyncEnabledLock("GLXVsyncEnabledLock")
, mVsyncEnabled(false)
+#ifdef MOZ_WAYLAND
+ , mIsWaylandDisplay(false)
+#endif
{
}
// Sets up the display's GL context on a worker thread.
// Required as GLContexts may only be used by the creating thread.
// Returns true if setup was a success.
bool Setup()
{
MonitorAutoLock lock(mSetupLock);
MOZ_ASSERT(NS_IsMainThread());
if (!mVsyncThread.Start())
return false;
RefPtr<Runnable> vsyncSetup =
- NewRunnableMethod("GLXVsyncSource::GLXDisplay::SetupGLContext",
+ NewRunnableMethod("GtkVsyncSource::GLXDisplay::SetupGLContext",
this,
&GLXDisplay::SetupGLContext);
mVsyncThread.message_loop()->PostTask(vsyncSetup.forget());
// Wait until the setup has completed.
lock.Wait();
return mGLContext != nullptr;
}
+#ifdef MOZ_WAYLAND
+ bool SetupWayland()
+ {
+ MonitorAutoLock lock(mSetupLock);
+ MOZ_ASSERT(NS_IsMainThread());
+ mIsWaylandDisplay = true;
+ return mVsyncThread.Start();
+ }
+#endif
+
// Called on the Vsync thread to setup the GL context.
void SetupGLContext()
{
MonitorAutoLock lock(mSetupLock);
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!mGLContext, "GLContext already setup!");
// Create video sync timer on a separate Display to prevent locking the
@@ -613,29 +636,35 @@ public:
}
lock.NotifyAll();
}
virtual void EnableVsync() override
{
MOZ_ASSERT(NS_IsMainThread());
+#if !defined(MOZ_WAYLAND)
MOZ_ASSERT(mGLContext, "GLContext not setup!");
+#endif
MonitorAutoLock lock(mVsyncEnabledLock);
if (mVsyncEnabled) {
return;
}
mVsyncEnabled = true;
// If the task has not nulled itself out, it hasn't yet realized
// that vsync was disabled earlier, so continue its execution.
if (!mVsyncTask) {
mVsyncTask = NewRunnableMethod(
- "GLXVsyncSource::GLXDisplay::RunVsync", this, &GLXDisplay::RunVsync);
+ "GtkVsyncSource::GLXDisplay::RunVsync", this,
+#if defined(MOZ_WAYLAND)
+ mIsWaylandDisplay ? &GLXDisplay::RunVsyncWayland :
+#endif
+ &GLXDisplay::RunVsync);
RefPtr<Runnable> addrefedTask = mVsyncTask;
mVsyncThread.message_loop()->PostTask(addrefedTask.forget());
}
}
virtual void DisableVsync() override
{
MonitorAutoLock lock(mVsyncEnabledLock);
@@ -650,17 +679,17 @@ public:
virtual void Shutdown() override
{
MOZ_ASSERT(NS_IsMainThread());
DisableVsync();
// Cleanup thread-specific resources before shutting down.
RefPtr<Runnable> shutdownTask = NewRunnableMethod(
- "GLXVsyncSource::GLXDisplay::Cleanup", this, &GLXDisplay::Cleanup);
+ "GtkVsyncSource::GLXDisplay::Cleanup", this, &GLXDisplay::Cleanup);
mVsyncThread.message_loop()->PostTask(shutdownTask.forget());
// Stop, waiting for the cleanup task to finish execution.
mVsyncThread.Stop();
}
private:
virtual ~GLXDisplay()
@@ -709,50 +738,96 @@ public:
}
}
lastVsync = TimeStamp::Now();
NotifyVsync(lastVsync);
}
}
+#ifdef MOZ_WAYLAND
+ /* VSync on Wayland is tricky as we can get only "last VSync" event signal.
+ * That means we should draw next frame at "last Vsync + frame delay" time.
+ */
+ void RunVsyncWayland()
+ {
+ MOZ_ASSERT(!NS_IsMainThread());
+
+ for (;;) {
+ {
+ MonitorAutoLock lock(mVsyncEnabledLock);
+ if (!mVsyncEnabled) {
+ mVsyncTask = nullptr;
+ return;
+ }
+ }
+
+ gint64 lastVsync = gfxPlatformGtk::GetPlatform()->GetWaylandLastVsync();
+ gint64 currTime = (g_get_monotonic_time() / 1000);
+
+ gint64 remaining = gfxPlatformGtk::GetPlatform()->GetWaylandFrameDelay() -
+ (currTime - lastVsync);
+ if (remaining > 0) {
+ PlatformThread::Sleep(remaining);
+ } else {
+ // Time from last HW Vsync is longer than our frame delay,
+ // use our approximation then.
+ gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(currTime);
+ }
+
+ NotifyVsync(TimeStamp::Now());
+ }
+ }
+#endif
+
void Cleanup() {
MOZ_ASSERT(!NS_IsMainThread());
mGLContext = nullptr;
- XCloseDisplay(mXDisplay);
+ if (mXDisplay)
+ XCloseDisplay(mXDisplay);
}
// Owned by the vsync thread.
RefPtr<gl::GLContextGLX> mGLContext;
_XDisplay* mXDisplay;
Monitor mSetupLock;
base::Thread mVsyncThread;
RefPtr<Runnable> mVsyncTask;
Monitor mVsyncEnabledLock;
bool mVsyncEnabled;
+#ifdef MOZ_WAYLAND
+ bool mIsWaylandDisplay;
+#endif
};
private:
// We need a refcounted VsyncSource::Display to use chromium IPC runnables.
RefPtr<GLXDisplay> mGlobalDisplay;
};
already_AddRefed<gfx::VsyncSource>
gfxPlatformGtk::CreateHardwareVsyncSource()
{
+#ifdef MOZ_WAYLAND
+ if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
+ RefPtr<VsyncSource> vsyncSource = new GtkVsyncSource();
+ VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
+ static_cast<GtkVsyncSource::GLXDisplay&>(display).SetupWayland();
+ return vsyncSource.forget();
+ }
+#endif
+
// Only use GLX vsync when the OpenGL compositor is being used.
// The extra cost of initializing a GLX context while blocking the main
// thread is not worth it when using basic composition.
- // Also don't use it on non-X11 displays.
if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
- if (GDK_IS_X11_DISPLAY(gdk_display_get_default()) &&
- gl::sGLXLibrary.SupportsVideoSync()) {
- RefPtr<VsyncSource> vsyncSource = new GLXVsyncSource();
+ if (gl::sGLXLibrary.SupportsVideoSync()) {
+ RefPtr<VsyncSource> vsyncSource = new GtkVsyncSource();
VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
- if (!static_cast<GLXVsyncSource::GLXDisplay&>(display).Setup()) {
+ if (!static_cast<GtkVsyncSource::GLXDisplay&>(display).Setup()) {
NS_WARNING("Failed to setup GLContext, falling back to software vsync.");
return gfxPlatform::CreateHardwareVsyncSource();
}
return vsyncSource.forget();
}
NS_WARNING("SGI_video_sync unsupported. Falling back to software vsync.");
}
return gfxPlatform::CreateHardwareVsyncSource();
diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -546,16 +546,18 @@ WindowBackBuffer::Lock()
mWaylandDisplay->GetSurfaceFormat());
}
static void
frame_callback_handler(void *data, struct wl_callback *callback, uint32_t time)
{
auto surface = reinterpret_cast<WindowSurfaceWayland*>(data);
surface->FrameCallbackHandler();
+
+ gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(time);
}
static const struct wl_callback_listener frame_listener = {
frame_callback_handler
};
WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
: mWindow(aWindow)

102
mozilla-1468670.patch Normal file
View File

@ -0,0 +1,102 @@
diff --git a/widget/gtk/nsGtkKeyUtils.h b/widget/gtk/nsGtkKeyUtils.h
--- a/widget/gtk/nsGtkKeyUtils.h
+++ b/widget/gtk/nsGtkKeyUtils.h
@@ -169,17 +169,20 @@ protected:
bool mInitialized;
/**
* Initializing methods.
*/
void Init();
void InitXKBExtension();
- void InitBySystemSettings();
+ void InitBySystemSettingsX11();
+#ifdef MOZ_WAYLAND
+ void InitBySystemSettingsWayland();
+#endif
/**
* mModifierKeys stores each hardware key information.
*/
struct ModifierKey {
guint mHardwareKeycode;
guint mMask;
diff --git a/widget/gtk/nsGtkKeyUtils.cpp b/widget/gtk/nsGtkKeyUtils.cpp
--- a/widget/gtk/nsGtkKeyUtils.cpp
+++ b/widget/gtk/nsGtkKeyUtils.cpp
@@ -190,17 +190,21 @@ KeymapWrapper::Init()
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
("%p Init, mGdkKeymap=%p",
this, mGdkKeymap));
mModifierKeys.Clear();
memset(mModifierMasks, 0, sizeof(mModifierMasks));
if (GDK_IS_X11_DISPLAY(gdk_display_get_default()))
- InitBySystemSettings();
+ InitBySystemSettingsX11();
+#ifdef MOZ_WAYLAND
+ else
+ InitBySystemSettingsWayland();
+#endif
gdk_window_add_filter(nullptr, FilterEvents, this);
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
("%p Init, CapsLock=0x%X, NumLock=0x%X, "
"ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
"Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
this,
@@ -270,20 +274,20 @@ KeymapWrapper::InitXKBExtension()
return;
}
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
("%p InitXKBExtension, Succeeded", this));
}
void
-KeymapWrapper::InitBySystemSettings()
+KeymapWrapper::InitBySystemSettingsX11()
{
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
- ("%p InitBySystemSettings, mGdkKeymap=%p",
+ ("%p InitBySystemSettingsX11, mGdkKeymap=%p",
this, mGdkKeymap));
Display* display =
gdk_x11_display_get_xdisplay(gdk_display_get_default());
int min_keycode = 0;
int max_keycode = 0;
XDisplayKeycodes(display, &min_keycode, &max_keycode);
@@ -434,16 +438,26 @@ KeymapWrapper::InitBySystemSettings()
}
}
}
XFreeModifiermap(xmodmap);
XFree(xkeymap);
}
+#ifdef MOZ_WAYLAND
+void
+KeymapWrapper::InitBySystemSettingsWayland()
+{
+ // Not implemented yet, but at least Alt modifier should be handled to save
+ // popular usage.
+ mModifierMasks[INDEX_ALT] = 1 << 3;
+}
+#endif
+
KeymapWrapper::~KeymapWrapper()
{
gdk_window_remove_filter(nullptr, FilterEvents, this);
g_signal_handlers_disconnect_by_func(mGdkKeymap,
FuncToGpointer(OnKeysChanged), this);
g_signal_handlers_disconnect_by_func(mGdkKeymap,
FuncToGpointer(OnDirectionChanged), this);
g_object_unref(mGdkKeymap);