summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2011-04-10 16:49:52 +0200
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2011-04-19 09:05:08 +0200
commit1178a3ce5c830a0b652843ba0046160b0c761128 (patch)
treeb8d52d4146215ae5df60e7cd221d20b76a6bb995
parentd11eadb519fc390deb49e53f85b040dd1aa6659e (diff)
compositor(-drm): Pageflip to fullscreen surfaces
-rw-r--r--compositor/compositor-drm.c74
-rw-r--r--compositor/compositor-wayland.c8
-rw-r--r--compositor/compositor-x11.c8
-rw-r--r--compositor/compositor.c44
-rw-r--r--compositor/compositor.h6
5 files changed, 128 insertions, 12 deletions
diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c
index 10ba65a0..7527023b 100644
--- a/compositor/compositor-drm.c
+++ b/compositor/compositor-drm.c
@@ -63,6 +63,9 @@ struct drm_output {
uint32_t fb_id[2];
EGLImageKHR image[2];
uint32_t current;
+
+ uint32_t fs_surf_fb_id;
+ uint32_t pending_fs_surf_fb_id;
};
static int
@@ -87,6 +90,8 @@ drm_output_present(struct wlsc_output *output_base)
struct drm_output *output = (struct drm_output *) output_base;
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
+ int ret;
+ uint32_t fb_id = 0;
if (drm_output_prepare_render(&output->base))
return -1;
@@ -94,8 +99,29 @@ drm_output_present(struct wlsc_output *output_base)
output->current ^= 1;
+ if (output->base.scanout_surface) {
+ EGLint handle, stride;
+
+ eglExportDRMImageMESA(c->base.display,
+ output->base.scanout_surface->image,
+ NULL, &handle, &stride);
+
+ ret = drmModeAddFB(c->drm.fd,
+ output->base.width, output->base.height,
+ 32, 32, stride, handle,
+ &output->fs_surf_fb_id);
+ if (ret)
+ return -1;
+
+ printf("pageflip to fullscreen buffer: %d\n", handle);
+
+ fb_id = output->fs_surf_fb_id;
+ } else {
+ fb_id = output->fb_id[output->current ^ 1];
+ }
+
drmModePageFlip(c->drm.fd, output->crtc_id,
- output->fb_id[output->current ^ 1],
+ fb_id,
DRM_MODE_PAGE_FLIP_EVENT, output);
return 0;
@@ -105,11 +131,52 @@ static void
page_flip_handler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void *data)
{
- struct wlsc_output *output = data;
+ struct drm_output *output = (struct drm_output *) data;
+ struct drm_compositor *c =
+ (struct drm_compositor *) output->base.compositor;
uint32_t msecs;
+ if (output->pending_fs_surf_fb_id) {
+ drmModeRmFB(c->drm.fd, output->pending_fs_surf_fb_id);
+ output->pending_fs_surf_fb_id = 0;
+ }
+
+ if (output->fs_surf_fb_id) {
+ output->pending_fs_surf_fb_id = output->fs_surf_fb_id;
+ output->fs_surf_fb_id = 0;
+ }
+
msecs = sec * 1000 + usec / 1000;
- wlsc_output_finish_frame(output, msecs);
+ wlsc_output_finish_frame(&output->base, msecs);
+}
+
+static int
+drm_output_image_is_scanoutable(struct wlsc_output *output_base,
+ EGLImageKHR image)
+{
+ struct drm_output *output = (struct drm_output *) output_base;
+ struct drm_compositor *c =
+ (struct drm_compositor *) output->base.compositor;
+ EGLint handle, stride;
+ int ret;
+ uint32_t fb_id = 0;
+
+ eglExportDRMImageMESA(c->base.display, image,
+ NULL, &handle, &stride);
+
+ ret = drmModeAddFB(c->drm.fd,
+ output->base.width, output->base.height,
+ 32, 32, stride, handle,
+ &fb_id);
+ if (ret)
+ return 0;
+
+ /* FIXME: change interface to keep this fb_id,
+ * to be used directly in next pageflip? */
+ if (fb_id)
+ drmModeRmFB(c->drm.fd, fb_id);
+
+ return fb_id != 0;
}
static void
@@ -285,6 +352,7 @@ create_output_for_connector(struct drm_compositor *ec,
output->base.prepare_render = drm_output_prepare_render;
output->base.present = drm_output_present;
+ output->base.image_is_scanoutable = drm_output_image_is_scanoutable;
wl_list_insert(ec->base.output_list.prev, &output->base.link);
diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c
index 097b23e4..93fb5777 100644
--- a/compositor/compositor-wayland.c
+++ b/compositor/compositor-wayland.c
@@ -197,6 +197,13 @@ wayland_output_present(struct wlsc_output *output_base)
}
static int
+wayland_output_image_is_scanoutable(struct wlsc_output *output_base,
+ EGLImageKHR image)
+{
+ return 0;
+}
+
+static int
wayland_compositor_create_output(struct wayland_compositor *c,
int width, int height)
{
@@ -246,6 +253,7 @@ wayland_compositor_create_output(struct wayland_compositor *c,
output->base.prepare_render = wayland_output_prepare_render;
output->base.present = wayland_output_present;
+ output->base.image_is_scanoutable = wayland_output_image_is_scanoutable;
wl_list_insert(c->base.output_list.prev, &output->base.link);
diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c
index 48dd3475..e63d6be2 100644
--- a/compositor/compositor-x11.c
+++ b/compositor/compositor-x11.c
@@ -191,6 +191,13 @@ x11_output_present(struct wlsc_output *output_base)
return 0;
}
+static int
+x11_output_image_is_scanoutable(struct wlsc_output *output_base,
+ EGLImageKHR image)
+{
+ return 0;
+}
+
static void
x11_output_set_wm_protocols(struct x11_output *output)
{
@@ -339,6 +346,7 @@ x11_compositor_create_output(struct x11_compositor *c, int width, int height)
output->base.prepare_render = x11_output_prepare_render;
output->base.present = x11_output_present;
+ output->base.image_is_scanoutable = x11_output_image_is_scanoutable;
wl_list_insert(c->base.output_list.prev, &output->base.link);
diff --git a/compositor/compositor.c b/compositor/compositor.c
index ed3069d3..e88293a6 100644
--- a/compositor/compositor.c
+++ b/compositor/compositor.c
@@ -143,6 +143,7 @@ wlsc_surface_create(struct wlsc_compositor *compositor,
surface->compositor = compositor;
surface->visual = NULL;
+ surface->image = EGL_NO_IMAGE_KHR;
surface->x = x;
surface->y = y;
surface->width = width;
@@ -202,6 +203,10 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client)
wl_list_remove(&surface->link);
glDeleteTextures(1, &surface->texture);
+ if (surface->image != EGL_NO_IMAGE_KHR)
+ eglDestroyImageKHR(surface->compositor->display,
+ surface->image);
+
time = get_time();
wl_list_for_each_safe(l, next,
&surface->surface.destroy_listener_list, link)
@@ -282,19 +287,17 @@ wlsc_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface)
{
struct wlsc_surface *es = (struct wlsc_surface *) surface;
struct wlsc_compositor *ec = es->compositor;
- EGLImageKHR *image;
if (buffer->attach) {
buffer->attach(buffer, surface);
} else {
- image = eglCreateImageKHR(ec->display, ec->context,
- EGL_WAYLAND_BUFFER_WL,
- buffer, NULL);
+ es->image = eglCreateImageKHR(ec->display, ec->context,
+ EGL_WAYLAND_BUFFER_WL,
+ buffer, NULL);
glBindTexture(GL_TEXTURE_2D, es->texture);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, es->image);
es->visual = buffer->visual;
- eglDestroyImageKHR(ec->display, image);
}
}
@@ -491,6 +494,21 @@ wlsc_output_finish_frame(struct wlsc_output *output, int msecs)
compositor->repaint_on_timeout = 1;
}
+static int
+wlsc_surface_is_scanoutable(struct wlsc_surface *es,
+ struct wlsc_output *output)
+{
+ if (es->width != output->width ||
+ es->height != output->height ||
+ es->image == NULL)
+ return 0;
+
+ if (!output->image_is_scanoutable(output, es->image))
+ return 0;
+
+ return 1;
+}
+
static void
wlsc_output_repaint(struct wlsc_output *output)
{
@@ -518,12 +536,20 @@ wlsc_output_repaint(struct wlsc_output *output)
&output->previous_damage_region);
pixman_region32_copy(&output->previous_damage_region, &new_damage);
+ output->scanout_surface = NULL;
+
es = container_of(ec->surface_list.next, struct wlsc_surface, link);
if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN &&
es->fullscreen_output == output) {
- if (es->width < output->width || es->height < output->height)
- glClear(GL_COLOR_BUFFER_BIT);
- wlsc_surface_draw(es, output, &total_damage);
+ if (es->visual == &ec->compositor.rgb_visual &&
+ wlsc_surface_is_scanoutable(es, output)) {
+ output->scanout_surface = es;
+ } else {
+ if (es->width < output->width ||
+ es->height < output->height)
+ glClear(GL_COLOR_BUFFER_BIT);
+ wlsc_surface_draw(es, output, &total_damage);
+ }
} else {
wl_list_for_each(es, &ec->surface_list, link) {
if (es->visual != &ec->compositor.rgb_visual)
diff --git a/compositor/compositor.h b/compositor/compositor.h
index e48c2b28..12905f0b 100644
--- a/compositor/compositor.h
+++ b/compositor/compositor.h
@@ -51,8 +51,12 @@ struct wlsc_output {
int repaint_needed;
int finished;
+ struct wlsc_surface *scanout_surface;
+
int (*prepare_render)(struct wlsc_output *output);
int (*present)(struct wlsc_output *output);
+ int (*image_is_scanoutable)(struct wlsc_output *output,
+ EGLImageKHR image);
};
enum wlsc_pointer_type {
@@ -157,6 +161,8 @@ struct wlsc_surface {
struct wlsc_output *output;
enum wlsc_surface_map_type map_type;
struct wlsc_output *fullscreen_output;
+
+ EGLImageKHR image;
};
void