Make backends always specify output repaint time
Most backends relies on gettimeofday(2) for output repaint timestamps but this is not a requirement. Before this patch repaints coming from idle_repaint() always used gettimeofday(2) for timestamps. For backends not using that time source this could cause large jumps between timestamps. To fix this, timestamps needs to always come from the backend. This means that the backend needs to always be responsible of starting the repaint loop in case that the repaint cannot start immediately. The drm backend implementation is from the patch by Ander Conselvan de Oliveira found here: http://lists.freedesktop.org/archives/wayland-devel/2013-February/007393.html Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
parent
b76237e508
commit
e5a1225bc4
@ -622,6 +622,26 @@ drm_output_repaint(struct weston_output *output_base,
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
drm_output_start_repaint_loop(struct weston_output *output_base)
|
||||
{
|
||||
struct drm_output *output = (struct drm_output *) output_base;
|
||||
struct drm_compositor *compositor = (struct drm_compositor *)
|
||||
output_base->compositor;
|
||||
uint32_t fb_id;
|
||||
|
||||
if (output->current)
|
||||
fb_id = output->current->fb_id;
|
||||
else
|
||||
fb_id = output->original_crtc->buffer_id;
|
||||
|
||||
if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
||||
weston_log("queueing pageflip failed: %m\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
|
||||
void *data)
|
||||
@ -649,11 +669,16 @@ page_flip_handler(int fd, unsigned int frame,
|
||||
struct drm_output *output = (struct drm_output *) data;
|
||||
uint32_t msecs;
|
||||
|
||||
output->page_flip_pending = 0;
|
||||
/* 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
|
||||
* timestamp */
|
||||
if (output->page_flip_pending) {
|
||||
drm_output_release_fb(output, output->current);
|
||||
output->current = output->next;
|
||||
output->next = NULL;
|
||||
}
|
||||
|
||||
drm_output_release_fb(output, output->current);
|
||||
output->current = output->next;
|
||||
output->next = NULL;
|
||||
output->page_flip_pending = 0;
|
||||
|
||||
if (!output->vblank_pending) {
|
||||
msecs = sec * 1000 + usec / 1000;
|
||||
@ -1618,6 +1643,7 @@ create_output_for_connector(struct drm_compositor *ec,
|
||||
wl_list_insert(ec->base.output_list.prev, &output->base.link);
|
||||
|
||||
output->base.origin = output->base.current;
|
||||
output->base.start_repaint_loop = drm_output_start_repaint_loop;
|
||||
output->base.repaint = drm_output_repaint;
|
||||
output->base.destroy = drm_output_destroy;
|
||||
output->base.assign_planes = drm_assign_planes;
|
||||
|
@ -122,6 +122,17 @@ to_fbdev_compositor(struct weston_compositor *base)
|
||||
return container_of(base, struct fbdev_compositor, base);
|
||||
}
|
||||
|
||||
static void
|
||||
fbdev_output_start_repaint_loop(struct weston_output *output)
|
||||
{
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(output, msec);
|
||||
}
|
||||
|
||||
static void
|
||||
fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
|
||||
{
|
||||
@ -200,12 +211,8 @@ static int
|
||||
finish_frame_handler(void *data)
|
||||
{
|
||||
struct fbdev_output *output = data;
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(&output->base, msec);
|
||||
fbdev_output_start_repaint_loop(&output->base);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -504,6 +511,7 @@ fbdev_output_create(struct fbdev_compositor *compositor,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
|
||||
output->base.repaint = fbdev_output_repaint;
|
||||
output->base.destroy = fbdev_output_destroy;
|
||||
output->base.assign_planes = NULL;
|
||||
|
@ -43,16 +43,21 @@ struct headless_output {
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
finish_frame_handler(void *data)
|
||||
static void
|
||||
headless_output_start_repaint_loop(struct weston_output *output)
|
||||
{
|
||||
struct weston_output *output = data;
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(output, msec);
|
||||
}
|
||||
|
||||
static int
|
||||
finish_frame_handler(void *data)
|
||||
{
|
||||
headless_output_start_repaint_loop(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -119,6 +124,7 @@ headless_compositor_create_output(struct headless_compositor *c,
|
||||
wl_event_loop_add_timer(loop, finish_frame_handler, output);
|
||||
|
||||
output->base.origin = output->base.current;
|
||||
output->base.start_repaint_loop = headless_output_start_repaint_loop;
|
||||
output->base.repaint = headless_output_repaint;
|
||||
output->base.destroy = headless_output_destroy;
|
||||
output->base.assign_planes = NULL;
|
||||
|
@ -265,6 +265,16 @@ rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rdp_output_start_repaint_loop(struct weston_output *output)
|
||||
{
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(output, msec);
|
||||
}
|
||||
|
||||
static void
|
||||
rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
|
||||
@ -302,13 +312,7 @@ rdp_output_destroy(struct weston_output *output_base)
|
||||
static int
|
||||
finish_frame_handler(void *data)
|
||||
{
|
||||
struct weston_output *output = data;
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(output, msec);
|
||||
rdp_output_start_repaint_loop(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -461,6 +465,7 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
|
||||
output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
|
||||
|
||||
output->base.origin = output->base.current;
|
||||
output->base.start_repaint_loop = rdp_output_start_repaint_loop;
|
||||
output->base.repaint = rdp_output_repaint;
|
||||
output->base.destroy = rdp_output_destroy;
|
||||
output->base.assign_planes = NULL;
|
||||
|
@ -612,19 +612,26 @@ rpi_element_update(struct rpi_element *element,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
struct timeval tv;
|
||||
uint64_t time;
|
||||
ssize_t ret;
|
||||
|
||||
/* manufacture flip completion timestamp */
|
||||
/* XXX: use CLOCK_MONOTONIC instead? */
|
||||
gettimeofday(&tv, NULL);
|
||||
time = (uint64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
time = rpi_get_current_time();
|
||||
|
||||
ret = write(flippipe->writefd, &time, sizeof time);
|
||||
if (ret != sizeof time)
|
||||
@ -884,6 +891,15 @@ rpi_output_destroy_old_elements(struct rpi_output *output)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rpi_output_start_repaint_loop(struct weston_output *output)
|
||||
{
|
||||
uint64_t time;
|
||||
|
||||
time = rpi_get_current_time();
|
||||
weston_output_finish_frame(output, time);
|
||||
}
|
||||
|
||||
static void
|
||||
rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
|
||||
{
|
||||
@ -1029,6 +1045,7 @@ rpi_output_create(struct rpi_compositor *compositor)
|
||||
output->egl_window.width = modeinfo.width;
|
||||
output->egl_window.height = modeinfo.height;
|
||||
|
||||
output->base.start_repaint_loop = rpi_output_start_repaint_loop;
|
||||
output->base.repaint = rpi_output_repaint;
|
||||
output->base.destroy = rpi_output_destroy;
|
||||
if (compositor->max_planes > 0)
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "compositor.h"
|
||||
#include "gl-renderer.h"
|
||||
#include "../shared/image-loader.h"
|
||||
#include "../shared/os-compatibility.h"
|
||||
|
||||
struct wayland_compositor {
|
||||
struct weston_compositor base;
|
||||
@ -49,6 +50,7 @@ struct wayland_compositor {
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_shell *shell;
|
||||
struct wl_output *output;
|
||||
struct wl_shm *shm;
|
||||
|
||||
struct {
|
||||
int32_t x, y, width, height;
|
||||
@ -68,6 +70,7 @@ struct wayland_compositor {
|
||||
struct wayland_output {
|
||||
struct weston_output base;
|
||||
struct {
|
||||
int draw_initial_frame;
|
||||
struct wl_surface *surface;
|
||||
struct wl_shell_surface *shell_surface;
|
||||
struct wl_egl_window *egl_window;
|
||||
@ -126,6 +129,90 @@ static const struct wl_callback_listener frame_listener = {
|
||||
frame_done
|
||||
};
|
||||
|
||||
static void
|
||||
buffer_release(void *data, struct wl_buffer *buffer)
|
||||
{
|
||||
wl_buffer_destroy(buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
buffer_release
|
||||
};
|
||||
|
||||
static void
|
||||
draw_initial_frame(struct wayland_output *output)
|
||||
{
|
||||
struct wayland_compositor *c =
|
||||
(struct wayland_compositor *) output->base.compositor;
|
||||
struct wl_shm *shm = c->parent.shm;
|
||||
struct wl_surface *surface = output->parent.surface;
|
||||
struct wl_shm_pool *pool;
|
||||
struct wl_buffer *buffer;
|
||||
|
||||
int width, height, stride;
|
||||
int size;
|
||||
int fd;
|
||||
void *data;
|
||||
|
||||
width = output->mode.width + c->border.left + c->border.right;
|
||||
height = output->mode.height + c->border.top + c->border.bottom;
|
||||
stride = width * 4;
|
||||
size = height * stride;
|
||||
|
||||
fd = os_create_anonymous_file(size);
|
||||
if (fd < 0) {
|
||||
perror("os_create_anonymous_file");
|
||||
return;
|
||||
}
|
||||
|
||||
data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
pool = wl_shm_create_pool(shm, fd, size);
|
||||
|
||||
buffer = wl_shm_pool_create_buffer(pool, 0,
|
||||
width, height,
|
||||
stride,
|
||||
WL_SHM_FORMAT_ARGB8888);
|
||||
wl_buffer_add_listener(buffer, &buffer_listener, buffer);
|
||||
wl_shm_pool_destroy(pool);
|
||||
close(fd);
|
||||
|
||||
memset(data, 0, size);
|
||||
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
|
||||
/* We only need to damage some part, as its only transparant
|
||||
* pixels anyway. */
|
||||
wl_surface_damage(surface, 0, 0, 1, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
wayland_output_start_repaint_loop(struct weston_output *output_base)
|
||||
{
|
||||
struct wayland_output *output = (struct wayland_output *) output_base;
|
||||
struct wl_callback *callback;
|
||||
|
||||
/* If this is the initial frame, we need to attach a buffer so that
|
||||
* the compositor can map the surface and include it in its render
|
||||
* loop. If the surface doesn't end up in the render loop, the frame
|
||||
* callback won't be invoked. The buffer is transparent and of the
|
||||
* same size as the future real output buffer. */
|
||||
if (output->parent.draw_initial_frame) {
|
||||
output->parent.draw_initial_frame = 0;
|
||||
|
||||
draw_initial_frame(output);
|
||||
}
|
||||
|
||||
callback = wl_surface_frame(output->parent.surface);
|
||||
wl_callback_add_listener(callback, &frame_listener, output);
|
||||
wl_surface_commit(output->parent.surface);
|
||||
}
|
||||
|
||||
static void
|
||||
wayland_output_repaint(struct weston_output *output_base,
|
||||
pixman_region32_t *damage)
|
||||
@ -204,6 +291,7 @@ wayland_compositor_create_output(struct wayland_compositor *c,
|
||||
output->parent.egl_window) < 0)
|
||||
goto cleanup_window;
|
||||
|
||||
output->parent.draw_initial_frame = 1;
|
||||
output->parent.shell_surface =
|
||||
wl_shell_get_shell_surface(c->parent.shell,
|
||||
output->parent.surface);
|
||||
@ -212,6 +300,7 @@ wayland_compositor_create_output(struct wayland_compositor *c,
|
||||
wl_shell_surface_set_toplevel(output->parent.shell_surface);
|
||||
|
||||
output->base.origin = output->base.current;
|
||||
output->base.start_repaint_loop = wayland_output_start_repaint_loop;
|
||||
output->base.repaint = wayland_output_repaint;
|
||||
output->base.destroy = wayland_output_destroy;
|
||||
output->base.assign_planes = NULL;
|
||||
@ -580,6 +669,9 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
|
||||
&wl_shell_interface, 1);
|
||||
} else if (strcmp(interface, "wl_seat") == 0) {
|
||||
display_add_seat(c, name);
|
||||
} else if (strcmp(interface, "wl_shm") == 0) {
|
||||
c->parent.shm =
|
||||
wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,10 +706,15 @@ wayland_restore(struct weston_compositor *ec)
|
||||
static void
|
||||
wayland_destroy(struct weston_compositor *ec)
|
||||
{
|
||||
struct wayland_compositor *c = (struct wayland_compositor *) ec;
|
||||
|
||||
ec->renderer->destroy(ec);
|
||||
|
||||
weston_compositor_shutdown(ec);
|
||||
|
||||
if (c->parent.shm)
|
||||
wl_shm_destroy(c->parent.shm);
|
||||
|
||||
free(ec);
|
||||
}
|
||||
|
||||
|
@ -325,6 +325,17 @@ x11_input_destroy(struct x11_compositor *compositor)
|
||||
weston_seat_release(&compositor->core_seat);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_output_start_repaint_loop(struct weston_output *output)
|
||||
{
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(output, msec);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_output_repaint_gl(struct weston_output *output_base,
|
||||
pixman_region32_t *damage)
|
||||
@ -376,12 +387,8 @@ static int
|
||||
finish_frame_handler(void *data)
|
||||
{
|
||||
struct x11_output *output = data;
|
||||
uint32_t msec;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
weston_output_finish_frame(&output->base, msec);
|
||||
|
||||
x11_output_start_repaint_loop(&output->base);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -773,6 +780,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
|
||||
x11_output_wait_for_map(c, output);
|
||||
|
||||
output->base.origin = output->base.current;
|
||||
output->base.start_repaint_loop = x11_output_start_repaint_loop;
|
||||
if (c->use_pixman)
|
||||
output->base.repaint = x11_output_repaint_shm;
|
||||
else
|
||||
|
@ -1308,7 +1308,7 @@ idle_repaint(void *data)
|
||||
{
|
||||
struct weston_output *output = data;
|
||||
|
||||
weston_output_finish_frame(output, weston_compositor_get_time());
|
||||
output->start_repaint_loop(output);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
|
@ -186,6 +186,7 @@ struct weston_output {
|
||||
struct weston_mode *origin;
|
||||
struct wl_list mode_list;
|
||||
|
||||
void (*start_repaint_loop)(struct weston_output *output);
|
||||
void (*repaint)(struct weston_output *output,
|
||||
pixman_region32_t *damage);
|
||||
void (*destroy)(struct weston_output *output);
|
||||
|
Loading…
Reference in New Issue
Block a user