Commit eefc36c7 authored by Benjamin Franzke's avatar Benjamin Franzke 😀 Committed by Kristian H. Kristensen

compositor-drm: Fix multi head rendering

parent 13d9db20
......@@ -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);
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -24,6 +24,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <fcntl.h>
......@@ -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;
......
......@@ -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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment