firefox/mozilla-1467128.patch

353 lines
10 KiB
Diff

# HG changeset patch
# User Martin Stransky <stransky@redhat.com>
# Date 1530270941 -7200
# Node ID 338c0093263be6440a33b79a92801bd2b4658f79
# Parent 84a6d5a0b551f5da116aab702dd38bb725bc8a08
Bug 1467128 - [Wayland] Get VSync from Gtk/Wayland, r?lsalzman
VSync on Wayland is a bit tricky as we can get only "last VSync" event signal with
CLOCK_MONOTONIC timestamp or none (if application is hidden/minimized).
That means we should draw a next frame at "last Vsync + frame delay" time and also
approximate next VSync event when we don't get any.
MozReview-Commit-ID: FI3Z4nkmDNK
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/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 */