uint32_t prev_state;
- clockid_t clock;
struct udev_input input;
uint32_t cursor_width;
struct drm_compositor *compositor = (struct drm_compositor *)
output_base->compositor;
uint32_t fb_id;
- uint32_t msec;
struct timespec ts;
if (output->destroy_pending)
finish_frame:
/* if we cannot page-flip, immediately finish frame */
- clock_gettime(compositor->clock, &ts);
- msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
- weston_output_finish_frame(output_base, msec);
+ clock_gettime(compositor->base.presentation_clock, &ts);
+ weston_output_finish_frame(output_base, &ts);
}
static void
{
struct drm_sprite *s = (struct drm_sprite *)data;
struct drm_output *output = s->output;
- uint32_t msecs;
+ struct timespec ts;
output->vblank_pending = 0;
s->next = NULL;
if (!output->page_flip_pending) {
- msecs = sec * 1000 + usec / 1000;
- weston_output_finish_frame(&output->base, msecs);
+ ts.tv_sec = sec;
+ ts.tv_nsec = usec * 1000;
+ weston_output_finish_frame(&output->base, &ts);
}
}
unsigned int sec, unsigned int usec, void *data)
{
struct drm_output *output = (struct drm_output *) data;
- uint32_t msecs;
+ struct timespec ts;
/* We don't set page_flip_pending on start_repaint_loop, in that case
* we just want to page flip to the current buffer to get an accurate
if (output->destroy_pending)
drm_output_destroy(&output->base);
else if (!output->vblank_pending) {
- msecs = sec * 1000 + usec / 1000;
- weston_output_finish_frame(&output->base, msecs);
+ ts.tv_sec = sec;
+ ts.tv_nsec = usec * 1000;
+ weston_output_finish_frame(&output->base, &ts);
/* We can't call this from frame_notify, because the output's
* repaint needed flag is cleared just after that */
const char *filename, *sysnum;
uint64_t cap;
int fd, ret;
+ clockid_t clk_id;
sysnum = udev_device_get_sysnum(device);
if (sysnum)
ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
if (ret == 0 && cap == 1)
- ec->clock = CLOCK_MONOTONIC;
+ clk_id = CLOCK_MONOTONIC;
else
- ec->clock = CLOCK_REALTIME;
+ clk_id = CLOCK_REALTIME;
+
+ if (weston_compositor_set_presentation_clock(&ec->base, clk_id) < 0) {
+ weston_log("Error: failed to set presentation clock %d.\n",
+ clk_id);
+ return -1;
+ }
ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
if (ret == 0)
static void
fbdev_output_start_repaint_loop(struct weston_output *output)
{
- uint32_t msec;
- struct timeval tv;
+ struct timespec ts;
- gettimeofday(&tv, NULL);
- msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
- weston_output_finish_frame(output, msec);
+ clock_gettime(output->compositor->presentation_clock, &ts);
+ weston_output_finish_frame(output, &ts);
}
static void
config) < 0)
goto out_free;
+ if (weston_compositor_set_presentation_clock_software(
+ &compositor->base) < 0)
+ goto out_compositor;
+
compositor->udev = udev_new();
if (compositor->udev == NULL) {
weston_log("Failed to initialize udev context.\n");
static void
headless_output_start_repaint_loop(struct weston_output *output)
{
- uint32_t msec;
- struct timeval tv;
+ struct timespec ts;
- gettimeofday(&tv, NULL);
- msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
- weston_output_finish_frame(output, msec);
+ clock_gettime(output->compositor->presentation_clock, &ts);
+ weston_output_finish_frame(output, &ts);
}
static int
if (weston_compositor_init(&c->base, display, argc, argv, config) < 0)
goto err_free;
+ if (weston_compositor_set_presentation_clock_software(&c->base) < 0)
+ goto err_compositor;
+
if (headless_input_create(c) < 0)
goto err_compositor;
static void
rdp_output_start_repaint_loop(struct weston_output *output)
{
- uint32_t msec;
- struct timeval tv;
+ struct timespec ts;
- gettimeofday(&tv, NULL);
- msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
- weston_output_finish_frame(output, msec);
+ clock_gettime(output->compositor->presentation_clock, &ts);
+ weston_output_finish_frame(output, &ts);
}
static int
c->tls_enabled = 1;
}
+ if (weston_compositor_set_presentation_clock_software(&c->base) < 0)
+ goto err_compositor;
+
if (pixman_renderer_init(&c->base) < 0)
goto err_compositor;
struct rpi_flippipe {
int readfd;
int writefd;
+ clockid_t clk_id;
struct wl_event_source *source;
};
return container_of(base, struct rpi_compositor, base);
}
-static uint64_t
-rpi_get_current_time(void)
-{
- struct timeval tv;
-
- /* XXX: use CLOCK_MONOTONIC instead? */
- gettimeofday(&tv, NULL);
- return (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
static void
rpi_flippipe_update_complete(DISPMANX_UPDATE_HANDLE_T update, void *data)
{
/* This function runs in a different thread. */
struct rpi_flippipe *flippipe = data;
- uint64_t time;
+ struct timespec ts;
ssize_t ret;
/* manufacture flip completion timestamp */
- time = rpi_get_current_time();
+ clock_gettime(flippipe->clk_id, &ts);
- ret = write(flippipe->writefd, &time, sizeof time);
- if (ret != sizeof time)
+ ret = write(flippipe->writefd, &ts, sizeof ts);
+ if (ret != sizeof ts)
weston_log("ERROR: %s failed to write, ret %zd, errno %d\n",
__func__, ret, errno);
}
}
static void
-rpi_output_update_complete(struct rpi_output *output, uint64_t time);
+rpi_output_update_complete(struct rpi_output *output,
+ const struct timespec *stamp);
static int
rpi_flippipe_handler(int fd, uint32_t mask, void *data)
{
struct rpi_output *output = data;
ssize_t ret;
- uint64_t time;
+ struct timespec ts;
if (mask != WL_EVENT_READABLE)
weston_log("ERROR: unexpected mask 0x%x in %s\n",
mask, __func__);
- ret = read(fd, &time, sizeof time);
- if (ret != sizeof time) {
+ ret = read(fd, &ts, sizeof ts);
+ if (ret != sizeof ts) {
weston_log("ERROR: %s failed to read, ret %zd, errno %d\n",
__func__, ret, errno);
}
- rpi_output_update_complete(output, time);
+ rpi_output_update_complete(output, &ts);
return 1;
}
flippipe->readfd = fd[0];
flippipe->writefd = fd[1];
+ flippipe->clk_id = output->compositor->base.presentation_clock;
loop = wl_display_get_event_loop(output->compositor->base.wl_display);
flippipe->source = wl_event_loop_add_fd(loop, flippipe->readfd,
static void
rpi_output_start_repaint_loop(struct weston_output *output)
{
- uint64_t time;
+ struct timespec ts;
- time = rpi_get_current_time();
- weston_output_finish_frame(output, time);
+ clock_gettime(output->compositor->presentation_clock, &ts);
+ weston_output_finish_frame(output, &ts);
}
static int
}
static void
-rpi_output_update_complete(struct rpi_output *output, uint64_t time)
+rpi_output_update_complete(struct rpi_output *output,
+ const struct timespec *stamp)
{
- DBG("frame update complete(%" PRIu64 ")\n", time);
+ DBG("frame update complete(%ld.%09ld)\n",
+ (long)stamp->tv_sec, (long)stamp->tv_nsec);
rpi_renderer_finish_frame(&output->base);
- weston_output_finish_frame(&output->base, time);
+ weston_output_finish_frame(&output->base, stamp);
}
static void
config) < 0)
goto out_free;
+ if (weston_compositor_set_presentation_clock_software(
+ &compositor->base) < 0)
+ goto out_compositor;
+
compositor->udev = udev_new();
if (compositor->udev == NULL) {
weston_log("Failed to initialize udev context.\n");
frame_done(void *data, struct wl_callback *callback, uint32_t time)
{
struct weston_output *output = data;
+ struct timespec ts;
wl_callback_destroy(callback);
- weston_output_finish_frame(output, time);
+
+ /* XXX: use the presentation extension for proper timings */
+ ts.tv_sec = time / 1000;
+ ts.tv_nsec = (time % 1000) * 1000000;
+ weston_output_finish_frame(output, &ts);
}
static const struct wl_callback_listener frame_listener = {
config) < 0)
goto err_free;
- c->parent.wl_display = wl_display_connect(display_name);
+ if (weston_compositor_set_presentation_clock_software(&c->base) < 0)
+ goto err_compositor;
+ c->parent.wl_display = wl_display_connect(display_name);
if (c->parent.wl_display == NULL) {
weston_log("failed to create display: %m\n");
goto err_compositor;
static void
x11_output_start_repaint_loop(struct weston_output *output)
{
- uint32_t msec;
- struct timeval tv;
+ struct timespec ts;
- gettimeofday(&tv, NULL);
- msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
- weston_output_finish_frame(output, msec);
+ clock_gettime(output->compositor->presentation_clock, &ts);
+ weston_output_finish_frame(output, &ts);
}
static int
if (weston_compositor_init(&c->base, display, argc, argv, config) < 0)
goto err_free;
+ if (weston_compositor_set_presentation_clock_software(&c->base) < 0)
+ goto err_free;
+
c->dpy = XOpenDisplay(NULL);
if (c->dpy == NULL)
goto err_free;
}
static int
-weston_output_repaint(struct weston_output *output, uint32_t msecs)
+weston_output_repaint(struct weston_output *output)
{
struct weston_compositor *ec = output->compositor;
struct weston_view *ev;
wl_event_loop_dispatch(ec->input_loop, 0);
wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
- wl_callback_send_done(cb->resource, msecs);
+ wl_callback_send_done(cb->resource, output->frame_time);
wl_resource_destroy(cb->resource);
}
wl_list_for_each_safe(animation, next, &output->animation_list, link) {
animation->frame_counter++;
- animation->frame(animation, output, msecs);
+ animation->frame(animation, output, output->frame_time);
}
return r;
}
WL_EXPORT void
-weston_output_finish_frame(struct weston_output *output, uint32_t msecs)
+weston_output_finish_frame(struct weston_output *output,
+ const struct timespec *stamp)
{
struct weston_compositor *compositor = output->compositor;
struct wl_event_loop *loop =
wl_display_get_event_loop(compositor->wl_display);
int fd, r;
- output->frame_time = msecs;
+ output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
if (output->repaint_needed &&
compositor->state != WESTON_COMPOSITOR_SLEEPING &&
compositor->state != WESTON_COMPOSITOR_OFFSCREEN) {
- r = weston_output_repaint(output, msecs);
+ r = weston_output_repaint(output);
if (!r)
return;
}
wl_resource_set_implementation(resource, &presentation_implementation,
compositor, NULL);
- presentation_send_clock_id(resource, CLOCK_MONOTONIC);
+ presentation_send_clock_id(resource, compositor->presentation_clock);
}
static void
}
}
+WL_EXPORT int
+weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
+ clockid_t clk_id)
+{
+ struct timespec ts;
+
+ if (clock_gettime(clk_id, &ts) < 0)
+ return -1;
+
+ compositor->presentation_clock = clk_id;
+
+ return 0;
+}
+
+/*
+ * For choosing the software clock, when the display hardware or API
+ * does not expose a compatible presentation timestamp.
+ */
+WL_EXPORT int
+weston_compositor_set_presentation_clock_software(
+ struct weston_compositor *compositor)
+{
+ /* In order of preference */
+ static const clockid_t clocks[] = {
+ CLOCK_MONOTONIC_RAW, /* no jumps, no crawling */
+ CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
+ CLOCK_MONOTONIC, /* no jumps, may crawl */
+ CLOCK_REALTIME_COARSE, /* may jump and crawl, fast & coarse */
+ CLOCK_REALTIME /* may jump and crawl */
+ };
+ unsigned i;
+
+ for (i = 0; i < ARRAY_LENGTH(clocks); i++)
+ if (weston_compositor_set_presentation_clock(compositor,
+ clocks[i]) == 0)
+ return 0;
+
+ weston_log("Error: no suitable presentation clock available.\n");
+
+ return -1;
+}
+
WL_EXPORT void
weston_version(int *major, int *minor, int *micro)
{
*micro = WESTON_VERSION_MICRO;
}
+static const char *
+clock_name(clockid_t clk_id)
+{
+ static const char *names[] = {
+ [CLOCK_REALTIME] = "CLOCK_REALTIME",
+ [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC",
+ [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW",
+ [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE",
+ [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE",
+ [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME",
+ };
+
+ if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names))
+ return "unknown";
+
+ return names[clk_id];
+}
+
static const struct {
uint32_t bit; /* enum weston_capability */
const char *desc;
capability_strings[i].desc,
yes ? "yes" : "no");
}
+
+ weston_log_continue(STAMP_SPACE "presentation clock: %s, id %d\n",
+ clock_name(compositor->presentation_clock),
+ compositor->presentation_clock);
}
static int on_term_signal(int signal_number, void *data)
extern "C" {
#endif
+#include <time.h>
#include <pixman.h>
#include <xkbcommon/xkbcommon.h>
struct wl_signal frame_signal;
struct wl_signal destroy_signal;
int move_x, move_y;
- uint32_t frame_time;
+ uint32_t frame_time; /* presentation timestamp in milliseconds */
int disable_planes;
int destroying;
int32_t kb_repeat_rate;
int32_t kb_repeat_delay;
+
+ clockid_t presentation_clock;
};
struct weston_buffer {
struct weston_plane *above);
void
-weston_output_finish_frame(struct weston_output *output, uint32_t msecs);
+weston_output_finish_frame(struct weston_output *output,
+ const struct timespec *stamp);
void
weston_output_schedule_repaint(struct weston_output *output);
void
int
weston_compositor_init(struct weston_compositor *ec, struct wl_display *display,
int *argc, char *argv[], struct weston_config *config);
+int
+weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
+ clockid_t clk_id);
+int
+weston_compositor_set_presentation_clock_software(
+ struct weston_compositor *compositor);
void
weston_compositor_shutdown(struct weston_compositor *ec);
void