From eefc36c760ef6b126c2e60bb34eca82542c57011 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 11 Mar 2011 16:39:20 +0100 Subject: [PATCH] compositor-drm: Fix multi head rendering --- compositor/compositor-drm.c | 49 ++++++++++++++++++++++++++++++++--------- compositor/compositor-wayland.c | 24 +++++++++++++++----- compositor/compositor-x11.c | 23 +++++++++++++++---- compositor/compositor.c | 48 +++++++++++++++++++++++++++++++--------- compositor/compositor.h | 2 ++ 5 files changed, 115 insertions(+), 31 deletions(-) diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index 135e1cb..b2eead6 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -59,6 +59,22 @@ struct drm_output { uint32_t current; }; +static int +drm_output_prepare_render(struct wlsc_output *output_base) +{ + struct drm_output *output = (struct drm_output *) output_base; + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + output->rbo[output->current]); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + return -1; + + return 0; +} + static void drm_compositor_present(struct wlsc_compositor *ec) { @@ -66,14 +82,12 @@ drm_compositor_present(struct wlsc_compositor *ec) struct drm_output *output; wl_list_for_each(output, &ec->output_list, base.link) { - output->current ^= 1; - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, - output->rbo[output->current]); + if (drm_output_prepare_render(&output->base)) + continue; glFlush(); + output->current ^= 1; + drmModePageFlip(c->drm.fd, output->crtc_id, output->fb_id[output->current ^ 1], DRM_MODE_PAGE_FLIP_EVENT, output); @@ -88,8 +102,13 @@ page_flip_handler(int fd, unsigned int frame, struct wlsc_compositor *compositor = output->compositor; uint32_t msecs; - msecs = sec * 1000 + usec / 1000; - wlsc_compositor_finish_frame(compositor, msecs); + /* run synchronized to first output, ignore other pflip events. + * FIXME: support per output/surface frame callbacks */ + if (output == container_of(compositor->output_list.prev, + struct wlsc_output, link)) { + msecs = sec * 1000 + usec / 1000; + wlsc_compositor_finish_frame(compositor, msecs); + } } static void @@ -175,7 +194,8 @@ static drmModeModeInfo builtin_1024x768 = { static int create_output_for_connector(struct drm_compositor *ec, drmModeRes *resources, - drmModeConnector *connector) + drmModeConnector *connector, + int x, int y) { struct drm_output *output; drmModeEncoder *encoder; @@ -215,7 +235,7 @@ create_output_for_connector(struct drm_compositor *ec, } memset(output, 0, sizeof *output); - wlsc_output_init(&output->base, &ec->base, 0, 0, + wlsc_output_init(&output->base, &ec->base, x, y, mode->hdisplay, mode->vdisplay, 0); ec->crtc_allocator |= (1 << i); @@ -260,6 +280,8 @@ create_output_for_connector(struct drm_compositor *ec, return -1; } + output->base.prepare_render = drm_output_prepare_render; + wl_list_insert(ec->base.output_list.prev, &output->base.link); return 0; @@ -271,6 +293,7 @@ create_outputs(struct drm_compositor *ec, int option_connector) drmModeConnector *connector; drmModeRes *resources; int i; + int x = 0, y = 0; resources = drmModeGetResources(ec->drm.fd); if (!resources) { @@ -286,9 +309,13 @@ create_outputs(struct drm_compositor *ec, int option_connector) if (connector->connection == DRM_MODE_CONNECTED && (option_connector == 0 || connector->connector_id == option_connector)) - if (create_output_for_connector(ec, resources, connector) < 0) + if (create_output_for_connector(ec, resources, + connector, x, y) < 0) return -1; + x += container_of(ec->base.output_list.prev, struct wlsc_output, + link)->width; + drmModeFreeConnector(connector); } diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index 7580472..524a25c 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -163,19 +163,31 @@ frame_callback(void *data, uint32_t time) wlsc_compositor_finish_frame(&c->base, time); } +static int +wayland_output_prepare_render(struct wlsc_output *output_base) +{ + struct wayland_output *output = (struct wayland_output *) output_base; + struct wlsc_compositor *ec = output->base.compositor; + + if (!eglMakeCurrent(ec->display, output->egl_surface, + output->egl_surface, ec->context)) { + fprintf(stderr, "failed to make current\n"); + return -1; + } + + return 0; +} + static void wayland_compositor_present(struct wlsc_compositor *base) { struct wayland_compositor *c = (struct wayland_compositor *) base; struct wayland_output *output; - wl_list_for_each(output, &base->output_list, base.link) { - if (!eglMakeCurrent(c->base.display, output->egl_surface, - output->egl_surface, c->base.context)) { - fprintf(stderr, "failed to make current\n"); + if (wayland_output_prepare_render(&output->base)) continue; - } + eglSwapBuffers(c->base.display, output->egl_surface); } @@ -230,6 +242,8 @@ wayland_compositor_create_output(struct wayland_compositor *c, glClearColor(0, 0, 0, 0.5); + output->base.prepare_render = wayland_output_prepare_render; + wl_list_insert(c->base.output_list.prev, &output->base.link); return 0; diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c index 91f4a2c..ba593c1 100644 --- a/compositor/compositor-x11.c +++ b/compositor/compositor-x11.c @@ -156,6 +156,21 @@ x11_compositor_init_egl(struct x11_compositor *c) return 0; } +static int +x11_output_prepare_render(struct wlsc_output *output_base) +{ + struct x11_output *output = (struct x11_output *) output_base; + struct wlsc_compositor *ec = output->base.compositor; + + if (!eglMakeCurrent(ec->display, output->egl_surface, + output->egl_surface, ec->context)) { + fprintf(stderr, "failed to make current\n"); + return -1; + } + + return 0; +} + static void x11_compositor_present(struct wlsc_compositor *base) { @@ -165,11 +180,9 @@ x11_compositor_present(struct wlsc_compositor *base) uint32_t msec; wl_list_for_each(output, &c->base.output_list, base.link) { - if (!eglMakeCurrent(c->base.display, output->egl_surface, - output->egl_surface, c->base.context)) { - fprintf(stderr, "failed to make current\n"); + if (x11_output_prepare_render(&output->base)) continue; - } + eglSwapBuffers(c->base.display, output->egl_surface); } @@ -324,6 +337,8 @@ x11_compositor_create_output(struct x11_compositor *c, int width, int height) return -1; } + output->base.prepare_render = x11_output_prepare_render; + wl_list_insert(c->base.output_list.prev, &output->base.link); return 0; diff --git a/compositor/compositor.c b/compositor/compositor.c index c1db8f2..afa0e59 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -493,6 +494,8 @@ wlsc_output_repaint(struct wlsc_output *output) struct wlsc_input_device *eid; pixman_region32_t new_damage, total_damage; + output->prepare_render(output); + glViewport(0, 0, output->width, output->height); glUniformMatrix4fv(ec->proj_uniform, 1, GL_FALSE, output->matrix.d); @@ -849,17 +852,40 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y) const struct wl_grab_interface *interface; struct wlsc_input_device *wd = (struct wlsc_input_device *) device; int32_t sx, sy; - - /* FIXME: We need some multi head love here. */ - output = container_of(ec->output_list.next, struct wlsc_output, link); - if (x < output->x) - x = 0; - if (y < output->y) - y = 0; - if (x >= output->x + output->width) - x = output->x + output->width - 1; - if (y >= output->y + output->height) - y = output->y + output->height - 1; + int x_valid = 0, y_valid = 0; + int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN; + + wl_list_for_each(output, &ec->output_list, link) { + if (output->x <= x && x <= output->x + output->width) + x_valid = 1; + + if (output->y <= y && y <= output->y + output->height) + y_valid = 1; + + /* FIXME: calculate this only on output addition/deletion */ + if (output->x < min_x) + min_x = output->x; + if (output->y < min_y) + min_y = output->y; + + if (output->x + output->width > max_x) + max_x = output->x + output->width; + if (output->y + output->height > max_y) + max_y = output->y + output->height; + } + + if (!x_valid) { + if (x < min_x) + x = min_x; + else if (x >= max_x) + x = max_x; + } + if (!y_valid) { + if (y < min_y) + y = min_y; + else if (y >= max_y) + y = max_y; + } device->x = x; device->y = y; diff --git a/compositor/compositor.h b/compositor/compositor.h index 7f79da7..77df80a 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -47,6 +47,8 @@ struct wlsc_output { struct wlsc_matrix matrix; int32_t x, y, width, height; pixman_region32_t previous_damage_region; + + int (*prepare_render)(struct wlsc_output *output); }; enum wlsc_pointer_type { -- 2.7.4