diff options
author | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-04-10 16:49:52 +0200 |
---|---|---|
committer | Benjamin Franzke <benjaminfranzke@googlemail.com> | 2011-04-19 09:05:08 +0200 |
commit | 1178a3ce5c830a0b652843ba0046160b0c761128 (patch) | |
tree | b8d52d4146215ae5df60e7cd221d20b76a6bb995 | |
parent | d11eadb519fc390deb49e53f85b040dd1aa6659e (diff) |
compositor(-drm): Pageflip to fullscreen surfaces
-rw-r--r-- | compositor/compositor-drm.c | 74 | ||||
-rw-r--r-- | compositor/compositor-wayland.c | 8 | ||||
-rw-r--r-- | compositor/compositor-x11.c | 8 | ||||
-rw-r--r-- | compositor/compositor.c | 44 | ||||
-rw-r--r-- | compositor/compositor.h | 6 |
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 |