summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compositor-drm.c34
-rw-r--r--src/compositor-fbdev.c18
-rw-r--r--src/compositor-headless.c12
-rw-r--r--src/compositor-rdp.c19
-rw-r--r--src/compositor-rpi.c25
-rw-r--r--src/compositor-wayland.c97
-rw-r--r--src/compositor-x11.c20
-rw-r--r--src/compositor.c2
-rw-r--r--src/compositor.h1
9 files changed, 198 insertions, 30 deletions
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 5fccace..da1ba79 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -623,6 +623,26 @@ drm_output_repaint(struct weston_output *output_base,
}
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;
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 61cacc7..9d9eff5 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -123,6 +123,17 @@ to_fbdev_compositor(struct weston_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)
{
struct fbdev_output *output = to_fbdev_output(base);
@@ -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;
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
index 1e286fa..4720329 100644
--- a/src/compositor-headless.c
+++ b/src/compositor-headless.c
@@ -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;
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index 2caaa57..80f8b15 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -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;
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index cae6f7b..0b3bab3 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -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)
@@ -885,6 +892,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)
{
struct rpi_output *output = to_rpi_output(base);
@@ -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)
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index ceb912a..d9d7530 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -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;
@@ -127,6 +130,90 @@ static const struct wl_callback_listener frame_listener = {
};
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);
}
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index a95c1fb..eb6e58b 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -326,6 +326,17 @@ x11_input_destroy(struct x11_compositor *compositor)
}
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
diff --git a/src/compositor.c b/src/compositor.c
index e7c22db..693df2c 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -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
diff --git a/src/compositor.h b/src/compositor.h
index 7d1d68e..1e999a6 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -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);