2019-11-27 03:21:33 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
|
|
|
|
|
|
# include "WaylandVsyncSource.h"
|
|
|
|
# include "nsThreadUtils.h"
|
|
|
|
# include "nsISupportsImpl.h"
|
|
|
|
# include "MainThreadUtils.h"
|
|
|
|
|
|
|
|
# include <gdk/gdkwayland.h>
|
|
|
|
|
2020-09-04 13:54:49 +03:00
|
|
|
using namespace mozilla::widget;
|
|
|
|
|
2019-11-27 03:21:33 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
static void WaylandVsyncSourceCallbackHandler(void* data,
|
|
|
|
struct wl_callback* callback,
|
|
|
|
uint32_t time) {
|
2020-06-05 21:35:22 +03:00
|
|
|
WaylandVsyncSource::WaylandDisplay* context =
|
|
|
|
(WaylandVsyncSource::WaylandDisplay*)data;
|
2019-11-27 03:21:33 +03:00
|
|
|
wl_callback_destroy(callback);
|
2020-06-05 21:35:22 +03:00
|
|
|
context->FrameCallback();
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_callback_listener WaylandVsyncSourceCallbackListener = {
|
|
|
|
WaylandVsyncSourceCallbackHandler};
|
|
|
|
|
|
|
|
WaylandVsyncSource::WaylandDisplay::WaylandDisplay(MozContainer* container)
|
2020-06-05 21:35:22 +03:00
|
|
|
: mEnabledLock("WaylandVsyncEnabledLock"),
|
2019-11-27 03:21:33 +03:00
|
|
|
mVsyncEnabled(false),
|
|
|
|
mMonitorEnabled(false),
|
2020-06-05 21:35:22 +03:00
|
|
|
mCallback(nullptr),
|
2019-11-27 03:21:33 +03:00
|
|
|
mContainer(container) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
// We store the display here so all the frame callbacks won't have to look it
|
|
|
|
// up all the time.
|
2020-09-04 13:54:49 +03:00
|
|
|
mDisplay = WaylandDisplayGetWLDisplay();
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
2020-06-05 04:31:45 +03:00
|
|
|
void WaylandVsyncSource::WaylandDisplay::ClearFrameCallback() {
|
2020-06-05 21:35:22 +03:00
|
|
|
if (mCallback) {
|
|
|
|
wl_callback_destroy(mCallback);
|
|
|
|
mCallback = nullptr;
|
2020-06-05 02:39:30 +03:00
|
|
|
}
|
2020-06-05 04:31:45 +03:00
|
|
|
}
|
2019-11-27 03:21:33 +03:00
|
|
|
|
2020-06-05 21:35:22 +03:00
|
|
|
void WaylandVsyncSource::WaylandDisplay::Refresh() {
|
|
|
|
if (!mMonitorEnabled || !mVsyncEnabled || mCallback) {
|
|
|
|
// We don't need to do anything because:
|
|
|
|
// * We are unwanted by our widget or monitor, or
|
|
|
|
// * The last frame callback hasn't yet run to see that it had been shut
|
|
|
|
// down, so we can reuse it after having set mVsyncEnabled to true.
|
|
|
|
return;
|
|
|
|
}
|
2020-06-05 04:31:45 +03:00
|
|
|
|
2020-06-05 21:35:22 +03:00
|
|
|
struct wl_surface* surface = moz_container_wayland_surface_lock(mContainer);
|
|
|
|
if (!surface) {
|
|
|
|
// The surface hasn't been created yet. Try again when the surface is ready.
|
|
|
|
RefPtr<WaylandVsyncSource::WaylandDisplay> self(this);
|
|
|
|
moz_container_wayland_add_initial_draw_callback(
|
|
|
|
mContainer, [self]() -> void {
|
|
|
|
MutexAutoLock lock(self->mEnabledLock);
|
|
|
|
self->Refresh();
|
|
|
|
});
|
|
|
|
return;
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
2020-06-05 21:35:22 +03:00
|
|
|
moz_container_wayland_surface_unlock(mContainer, &surface);
|
2019-11-27 03:21:33 +03:00
|
|
|
|
2020-06-05 21:35:22 +03:00
|
|
|
// Vsync is enabled, but we don't have a callback configured. Set one up so
|
|
|
|
// we can get to work.
|
|
|
|
SetupFrameCallback();
|
2020-07-18 08:34:35 +03:00
|
|
|
TimeStamp vsyncTimestamp = TimeStamp::Now();
|
|
|
|
TimeStamp outputTimestamp = vsyncTimestamp + GetVsyncRate();
|
|
|
|
NotifyVsync(vsyncTimestamp, outputTimestamp);
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::EnableMonitor() {
|
|
|
|
MutexAutoLock lock(mEnabledLock);
|
|
|
|
if (mMonitorEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mMonitorEnabled = true;
|
2020-06-05 21:35:22 +03:00
|
|
|
Refresh();
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::DisableMonitor() {
|
|
|
|
MutexAutoLock lock(mEnabledLock);
|
|
|
|
if (!mMonitorEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mMonitorEnabled = false;
|
|
|
|
ClearFrameCallback();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::SetupFrameCallback() {
|
2020-06-05 21:35:22 +03:00
|
|
|
MOZ_ASSERT(mCallback == nullptr);
|
2020-06-02 19:22:16 +03:00
|
|
|
struct wl_surface* surface = moz_container_wayland_surface_lock(mContainer);
|
2019-11-27 03:21:33 +03:00
|
|
|
if (!surface) {
|
|
|
|
// We don't have a surface, either due to being called before it was made
|
|
|
|
// available in the mozcontainer, or after it was destroyed. We're all done
|
|
|
|
// regardless.
|
|
|
|
ClearFrameCallback();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-05 21:35:22 +03:00
|
|
|
mCallback = wl_surface_frame(surface);
|
|
|
|
wl_callback_add_listener(mCallback, &WaylandVsyncSourceCallbackListener,
|
|
|
|
this);
|
2019-11-27 03:21:33 +03:00
|
|
|
wl_surface_commit(surface);
|
|
|
|
wl_display_flush(mDisplay);
|
2020-06-04 16:50:46 +03:00
|
|
|
moz_container_wayland_surface_unlock(mContainer, &surface);
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::FrameCallback() {
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mEnabledLock);
|
2020-06-05 21:35:22 +03:00
|
|
|
mCallback = nullptr;
|
2019-11-27 03:21:33 +03:00
|
|
|
|
|
|
|
if (!mVsyncEnabled || !mMonitorEnabled) {
|
|
|
|
// We are unwanted by either our creator or our consumer, so we just stop
|
|
|
|
// here without setting up a new frame callback.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure our next frame callback.
|
|
|
|
SetupFrameCallback();
|
|
|
|
}
|
|
|
|
|
2020-07-18 08:34:35 +03:00
|
|
|
TimeStamp vsyncTimestamp = TimeStamp::Now();
|
|
|
|
TimeStamp outputTimestamp = vsyncTimestamp + GetVsyncRate();
|
|
|
|
NotifyVsync(vsyncTimestamp, outputTimestamp);
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::EnableVsync() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MutexAutoLock lock(mEnabledLock);
|
|
|
|
if (mVsyncEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mVsyncEnabled = true;
|
2020-06-05 21:35:22 +03:00
|
|
|
Refresh();
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::DisableVsync() {
|
|
|
|
MutexAutoLock lock(mEnabledLock);
|
|
|
|
mVsyncEnabled = false;
|
|
|
|
ClearFrameCallback();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WaylandVsyncSource::WaylandDisplay::IsVsyncEnabled() {
|
|
|
|
MutexAutoLock lock(mEnabledLock);
|
|
|
|
return mVsyncEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WaylandVsyncSource::WaylandDisplay::Shutdown() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
DisableVsync();
|
2020-06-05 21:35:22 +03:00
|
|
|
wl_display_roundtrip(mDisplay);
|
2019-11-27 03:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // MOZ_WAYLAND
|