compositor-drm: Fix multi head rendering

dev
Benjamin Franzke 14 years ago committed by Kristian Høgsberg
parent 13d9db2095
commit eefc36c760
  1. 49
      compositor/compositor-drm.c
  2. 24
      compositor/compositor-wayland.c
  3. 23
      compositor/compositor-x11.c
  4. 46
      compositor/compositor.c
  5. 2
      compositor/compositor.h

@ -59,6 +59,22 @@ struct drm_output {
uint32_t current; 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 static void
drm_compositor_present(struct wlsc_compositor *ec) drm_compositor_present(struct wlsc_compositor *ec)
{ {
@ -66,14 +82,12 @@ drm_compositor_present(struct wlsc_compositor *ec)
struct drm_output *output; struct drm_output *output;
wl_list_for_each(output, &ec->output_list, base.link) { wl_list_for_each(output, &ec->output_list, base.link) {
output->current ^= 1; if (drm_output_prepare_render(&output->base))
continue;
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
output->rbo[output->current]);
glFlush(); glFlush();
output->current ^= 1;
drmModePageFlip(c->drm.fd, output->crtc_id, drmModePageFlip(c->drm.fd, output->crtc_id,
output->fb_id[output->current ^ 1], output->fb_id[output->current ^ 1],
DRM_MODE_PAGE_FLIP_EVENT, output); DRM_MODE_PAGE_FLIP_EVENT, output);
@ -88,8 +102,13 @@ page_flip_handler(int fd, unsigned int frame,
struct wlsc_compositor *compositor = output->compositor; struct wlsc_compositor *compositor = output->compositor;
uint32_t msecs; uint32_t msecs;
msecs = sec * 1000 + usec / 1000; /* run synchronized to first output, ignore other pflip events.
wlsc_compositor_finish_frame(compositor, msecs); * 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 static void
@ -175,7 +194,8 @@ static drmModeModeInfo builtin_1024x768 = {
static int static int
create_output_for_connector(struct drm_compositor *ec, create_output_for_connector(struct drm_compositor *ec,
drmModeRes *resources, drmModeRes *resources,
drmModeConnector *connector) drmModeConnector *connector,
int x, int y)
{ {
struct drm_output *output; struct drm_output *output;
drmModeEncoder *encoder; drmModeEncoder *encoder;
@ -215,7 +235,7 @@ create_output_for_connector(struct drm_compositor *ec,
} }
memset(output, 0, sizeof *output); 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); mode->hdisplay, mode->vdisplay, 0);
ec->crtc_allocator |= (1 << i); ec->crtc_allocator |= (1 << i);
@ -260,6 +280,8 @@ create_output_for_connector(struct drm_compositor *ec,
return -1; return -1;
} }
output->base.prepare_render = drm_output_prepare_render;
wl_list_insert(ec->base.output_list.prev, &output->base.link); wl_list_insert(ec->base.output_list.prev, &output->base.link);
return 0; return 0;
@ -271,6 +293,7 @@ create_outputs(struct drm_compositor *ec, int option_connector)
drmModeConnector *connector; drmModeConnector *connector;
drmModeRes *resources; drmModeRes *resources;
int i; int i;
int x = 0, y = 0;
resources = drmModeGetResources(ec->drm.fd); resources = drmModeGetResources(ec->drm.fd);
if (!resources) { if (!resources) {
@ -286,9 +309,13 @@ create_outputs(struct drm_compositor *ec, int option_connector)
if (connector->connection == DRM_MODE_CONNECTED && if (connector->connection == DRM_MODE_CONNECTED &&
(option_connector == 0 || (option_connector == 0 ||
connector->connector_id == option_connector)) 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; return -1;
x += container_of(ec->base.output_list.prev, struct wlsc_output,
link)->width;
drmModeFreeConnector(connector); drmModeFreeConnector(connector);
} }

@ -163,19 +163,31 @@ frame_callback(void *data, uint32_t time)
wlsc_compositor_finish_frame(&c->base, 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 static void
wayland_compositor_present(struct wlsc_compositor *base) wayland_compositor_present(struct wlsc_compositor *base)
{ {
struct wayland_compositor *c = (struct wayland_compositor *) base; struct wayland_compositor *c = (struct wayland_compositor *) base;
struct wayland_output *output; struct wayland_output *output;
wl_list_for_each(output, &base->output_list, base.link) { wl_list_for_each(output, &base->output_list, base.link) {
if (!eglMakeCurrent(c->base.display, output->egl_surface, if (wayland_output_prepare_render(&output->base))
output->egl_surface, c->base.context)) {
fprintf(stderr, "failed to make current\n");
continue; continue;
}
eglSwapBuffers(c->base.display, output->egl_surface); 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); 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); wl_list_insert(c->base.output_list.prev, &output->base.link);
return 0; return 0;

@ -156,6 +156,21 @@ x11_compositor_init_egl(struct x11_compositor *c)
return 0; 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 static void
x11_compositor_present(struct wlsc_compositor *base) x11_compositor_present(struct wlsc_compositor *base)
{ {
@ -165,11 +180,9 @@ x11_compositor_present(struct wlsc_compositor *base)
uint32_t msec; uint32_t msec;
wl_list_for_each(output, &c->base.output_list, base.link) { wl_list_for_each(output, &c->base.output_list, base.link) {
if (!eglMakeCurrent(c->base.display, output->egl_surface, if (x11_output_prepare_render(&output->base))
output->egl_surface, c->base.context)) {
fprintf(stderr, "failed to make current\n");
continue; continue;
}
eglSwapBuffers(c->base.display, output->egl_surface); 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; return -1;
} }
output->base.prepare_render = x11_output_prepare_render;
wl_list_insert(c->base.output_list.prev, &output->base.link); wl_list_insert(c->base.output_list.prev, &output->base.link);
return 0; return 0;

@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <fcntl.h> #include <fcntl.h>
@ -493,6 +494,8 @@ wlsc_output_repaint(struct wlsc_output *output)
struct wlsc_input_device *eid; struct wlsc_input_device *eid;
pixman_region32_t new_damage, total_damage; pixman_region32_t new_damage, total_damage;
output->prepare_render(output);
glViewport(0, 0, output->width, output->height); glViewport(0, 0, output->width, output->height);
glUniformMatrix4fv(ec->proj_uniform, 1, GL_FALSE, output->matrix.d); 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; const struct wl_grab_interface *interface;
struct wlsc_input_device *wd = (struct wlsc_input_device *) device; struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
int32_t sx, sy; int32_t sx, sy;
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;
}
/* FIXME: We need some multi head love here. */ if (!x_valid) {
output = container_of(ec->output_list.next, struct wlsc_output, link); if (x < min_x)
if (x < output->x) x = min_x;
x = 0; else if (x >= max_x)
if (y < output->y) x = max_x;
y = 0; }
if (x >= output->x + output->width) if (!y_valid) {
x = output->x + output->width - 1; if (y < min_y)
if (y >= output->y + output->height) y = min_y;
y = output->y + output->height - 1; else if (y >= max_y)
y = max_y;
}
device->x = x; device->x = x;
device->y = y; device->y = y;

@ -47,6 +47,8 @@ struct wlsc_output {
struct wlsc_matrix matrix; struct wlsc_matrix matrix;
int32_t x, y, width, height; int32_t x, y, width, height;
pixman_region32_t previous_damage_region; pixman_region32_t previous_damage_region;
int (*prepare_render)(struct wlsc_output *output);
}; };
enum wlsc_pointer_type { enum wlsc_pointer_type {

Loading…
Cancel
Save