compositor(-drm): Pageflip to fullscreen surfaces
authorBenjamin Franzke <benjaminfranzke@googlemail.com>
Sun, 10 Apr 2011 14:49:52 +0000 (16:49 +0200)
committerBenjamin Franzke <benjaminfranzke@googlemail.com>
Tue, 19 Apr 2011 07:05:08 +0000 (09:05 +0200)
compositor/compositor-drm.c
compositor/compositor-wayland.c
compositor/compositor-x11.c
compositor/compositor.c
compositor/compositor.h

index 10ba65a..7527023 100644 (file)
@@ -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);
 
index 097b23e..93fb577 100644 (file)
@@ -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);
 
index 48dd347..e63d6be 100644 (file)
@@ -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);
 
index ed3069d..e88293a 100644 (file)
@@ -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)
index e48c2b2..12905f0 100644 (file)
@@ -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