From 1178a3ce5c830a0b652843ba0046160b0c761128 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sun, 10 Apr 2011 16:49:52 +0200 Subject: [PATCH 1/2] compositor(-drm): Pageflip to fullscreen surfaces --- compositor/compositor-drm.c | 74 +++++++++++++++++++++++++++++++-- compositor/compositor-wayland.c | 8 ++++ compositor/compositor-x11.c | 8 ++++ compositor/compositor.c | 44 ++++++++++++++++---- 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 @@ -196,6 +196,13 @@ wayland_output_present(struct wlsc_output *output_base) return 0; } +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 From 431da9a4cc9096fbe922031a501c24b1b4578dc0 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Wed, 20 Apr 2011 11:02:58 +0200 Subject: [PATCH 2/2] Make use of a hardware cursor in compositor-drm --- compositor/compositor-drm.c | 110 +++++++++++++++++++++++- compositor/compositor-wayland.c | 9 +- compositor/compositor-x11.c | 10 ++- compositor/compositor.c | 148 +++++++++++++++++++++++++------- compositor/compositor.h | 23 +++-- compositor/shm.c | 21 ----- 6 files changed, 259 insertions(+), 62 deletions(-) diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index 7527023b..4133c197 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -179,6 +179,68 @@ drm_output_image_is_scanoutable(struct wlsc_output *output_base, return fb_id != 0; } +static int +drm_output_set_cursor(struct wlsc_output *output_base, + struct wl_input_device *input) +{ + struct drm_output *output = (struct drm_output *) output_base; + struct drm_compositor *c = + (struct drm_compositor *) output->base.compositor; + struct wlsc_input_device *eid = (struct wlsc_input_device *) input; + EGLint handle, stride; + int ret = -1; + pixman_region32_t cursor_region; + + pixman_region32_init_rect(&cursor_region, + eid->sprite->x, eid->sprite->y, + eid->sprite->width, eid->sprite->height); + + pixman_region32_intersect_rect(&cursor_region, &cursor_region, + output->base.x, output->base.y, + output->base.width, output->base.height); + + if (!pixman_region32_not_empty(&cursor_region)) { + ret = 0; + goto out; + } + + if (eid->sprite->image == EGL_NO_IMAGE_KHR) + goto out; + + if (eid->sprite->width > 64 || eid->sprite->height > 64) + goto out; + + eglExportDRMImageMESA(c->base.display, eid->sprite->image, + NULL, &handle, &stride); + + if (stride != 64 * 4) { + fprintf(stderr, "info: cursor stride is != 64\n"); + goto out; + } + + ret = drmModeSetCursor(c->drm.fd, output->crtc_id, handle, 64, 64); + if (ret) { + fprintf(stderr, "failed to set cursor: %s\n", strerror(-ret)); + goto out; + } + + ret = drmModeMoveCursor(c->drm.fd, output->crtc_id, + eid->sprite->x - output->base.x, + eid->sprite->y - output->base.y); + if (ret) { + fprintf(stderr, "failed to move cursor: %s\n", strerror(-ret)); + goto out; + } + + printf("info: set hardware cursor\n"); + +out: + pixman_region32_fini(&cursor_region); + if (ret) + drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0); + return ret; +} + static void on_drm_input(int fd, uint32_t mask, void *data) { @@ -353,6 +415,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; + output->base.set_hardware_cursor = drm_output_set_cursor; wl_list_insert(ec->base.output_list.prev, &output->base.link); @@ -534,6 +597,50 @@ udev_drm_event(int fd, uint32_t mask, void *data) udev_device_unref(event); } +static EGLImageKHR +drm_compositor_create_cursor_image(struct wlsc_compositor *ec, + int32_t width, int32_t height) +{ + EGLint image_attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + 0, 0, + EGL_NONE + }; + EGLint stride, name; + EGLImageKHR tmp_image, image; + + if (width > 64 || height > 64) + return EGL_NO_IMAGE_KHR; + + image_attribs[1] = 64; + image_attribs[3] = 64; + image_attribs[6] = EGL_DRM_BUFFER_USE_MESA; + image_attribs[7] = EGL_DRM_BUFFER_USE_SCANOUT_MESA; + + tmp_image = eglCreateDRMImageMESA(ec->display, image_attribs); + + eglExportDRMImageMESA(ec->display, tmp_image, &name, NULL, &stride); + + if (stride == 64) + return tmp_image; + + /* recreate image width stide 64 forced */ + image_attribs[1] = width; + image_attribs[3] = height; + image_attribs[6] = EGL_DRM_BUFFER_STRIDE_MESA; + image_attribs[7] = 64; + + image = eglCreateImageKHR(ec->display, EGL_NO_CONTEXT, EGL_DRM_BUFFER_MESA, + (EGLClientBuffer)(intptr_t) name, image_attribs); + eglExportDRMImageMESA(ec->display, image, &name, NULL, &stride); + + eglDestroyImageKHR(ec->display, tmp_image); + + return image; +} + static void drm_destroy(struct wlsc_compositor *ec) { @@ -589,7 +696,8 @@ drm_compositor_create(struct wl_display *display, int connector) } ec->base.destroy = drm_destroy; - ec->base.create_buffer = wlsc_shm_buffer_create; + ec->base.create_cursor_image = drm_compositor_create_cursor_image; + ec->base.focus = 1; glGenFramebuffers(1, &ec->base.fbo); diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index 93fb5777..f457570a 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -203,6 +203,13 @@ wayland_output_image_is_scanoutable(struct wlsc_output *output_base, return 0; } +static int +wayland_output_set_cursor(struct wlsc_output *output_base, + struct wl_input_device *input) +{ + return -1; +} + static int wayland_compositor_create_output(struct wayland_compositor *c, int width, int height) @@ -254,6 +261,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; + output->base.set_hardware_cursor = wayland_output_set_cursor; wl_list_insert(c->base.output_list.prev, &output->base.link); @@ -488,7 +496,6 @@ wayland_compositor_create(struct wl_display *display, int width, int height) return NULL; c->base.destroy = wayland_destroy; - c->base.create_buffer = wlsc_shm_buffer_create; /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&c->base, display) < 0) diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c index e63d6be2..32225c37 100644 --- a/compositor/compositor-x11.c +++ b/compositor/compositor-x11.c @@ -198,6 +198,14 @@ x11_output_image_is_scanoutable(struct wlsc_output *output_base, return 0; } +static int +x11_output_set_cursor(struct wlsc_output *output_base, + struct wl_input_device *input) +{ + return -1; +} + + static void x11_output_set_wm_protocols(struct x11_output *output) { @@ -347,6 +355,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; + output->base.set_hardware_cursor = x11_output_set_cursor; wl_list_insert(c->base.output_list.prev, &output->base.link); @@ -582,7 +591,6 @@ x11_compositor_create(struct wl_display *display, int width, int height) return NULL; c->base.destroy = x11_destroy; - c->base.create_buffer = wlsc_shm_buffer_create; /* Can't init base class until we have a current egl context */ if (wlsc_compositor_init(&c->base, display) < 0) diff --git a/compositor/compositor.c b/compositor/compositor.c index e88293a6..5ff7a45c 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -120,7 +120,7 @@ wlsc_matrix_transform(struct wlsc_matrix *matrix, struct wlsc_vector *v) *v = t; } -static struct wlsc_surface * +struct wlsc_surface * wlsc_surface_create(struct wlsc_compositor *compositor, int32_t x, int32_t y, int32_t width, int32_t height) { @@ -144,6 +144,7 @@ wlsc_surface_create(struct wlsc_compositor *compositor, surface->compositor = compositor; surface->visual = NULL; surface->image = EGL_NO_IMAGE_KHR; + surface->saved_texture = 0; surface->x = x; surface->y = y; surface->width = width; @@ -201,7 +202,11 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client) wlsc_surface_damage(surface); wl_list_remove(&surface->link); - glDeleteTextures(1, &surface->texture); + if (surface->saved_texture == 0) + glDeleteTextures(1, &surface->texture); + else + glDeleteTextures(1, &surface->saved_texture); + if (surface->image != EGL_NO_IMAGE_KHR) eglDestroyImageKHR(surface->compositor->display, @@ -295,30 +300,81 @@ wlsc_buffer_attach(struct wl_buffer *buffer, struct wl_surface *surface) EGL_WAYLAND_BUFFER_WL, buffer, NULL); + if (es->saved_texture != 0) + es->texture = es->saved_texture; glBindTexture(GL_TEXTURE_2D, es->texture); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, es->image); es->visual = buffer->visual; } } -static struct wl_buffer * -create_buffer_from_png(struct wlsc_compositor *ec, - const char *filename, int width, int height) +static void +wlsc_sprite_attach(struct wlsc_sprite *sprite, struct wl_surface *surface) +{ + struct wlsc_surface *es = (struct wlsc_surface *) surface; + + es->image = sprite->image; + if (sprite->image != EGL_NO_IMAGE_KHR) { + glBindTexture(GL_TEXTURE_2D, es->texture); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, es->image); + } else { + if (es->saved_texture == 0) + es->saved_texture = es->texture; + es->texture = sprite->texture; + } + + es->visual = sprite->visual; +} + +enum sprite_usage { + SPRITE_USE_CURSOR = (1 << 0), +}; + +static struct wlsc_sprite * +create_sprite_from_png(struct wlsc_compositor *ec, + const char *filename, int width, int height, + uint32_t usage) { uint32_t *pixels; - struct wl_buffer *buffer; + struct wlsc_sprite *sprite; pixels = wlsc_load_image(filename, width, height); if(pixels == NULL) - return NULL; + return NULL; + + sprite = malloc(sizeof *sprite); + if (sprite == NULL) { + free(pixels); + return NULL; + } + + sprite->visual = &ec->compositor.premultiplied_argb_visual; + sprite->width = width; + sprite->height = height; + sprite->image = EGL_NO_IMAGE_KHR; - buffer = ec->create_buffer(ec, width, height, width * 4, - &ec->compositor.premultiplied_argb_visual, - pixels); + if (usage & SPRITE_USE_CURSOR && ec->create_cursor_image != NULL) + sprite->image = ec->create_cursor_image(ec, width, height); + + glGenTextures(1, &sprite->texture); + glBindTexture(GL_TEXTURE_2D, sprite->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if (sprite->image != EGL_NO_IMAGE_KHR) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, sprite->image); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, + GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0, + GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); + } free(pixels); - return buffer; + return sprite; } static const struct { @@ -345,12 +401,13 @@ create_pointer_images(struct wlsc_compositor *ec) const int width = 32, height = 32; count = ARRAY_LENGTH(pointer_images); - ec->pointer_buffers = malloc(count * sizeof *ec->pointer_buffers); + ec->pointer_sprites = malloc(count * sizeof *ec->pointer_sprites); for (i = 0; i < count; i++) { - ec->pointer_buffers[i] = - create_buffer_from_png(ec, + ec->pointer_sprites[i] = + create_sprite_from_png(ec, pointer_images[i].filename, - width, height); + width, height, + SPRITE_USE_CURSOR); } } @@ -358,7 +415,7 @@ static struct wlsc_surface * background_create(struct wlsc_output *output, const char *filename) { struct wlsc_surface *background; - struct wl_buffer *buffer; + struct wlsc_sprite *sprite; background = wlsc_surface_create(output->compositor, output->x, output->y, @@ -366,15 +423,14 @@ background_create(struct wlsc_output *output, const char *filename) if (background == NULL) return NULL; - buffer = create_buffer_from_png(output->compositor, - filename, - output->width, output->height); - if (buffer == NULL) { + sprite = create_sprite_from_png(output->compositor, filename, + output->width, output->height, 0); + if (sprite == NULL) { free(background); return NULL; } - wlsc_buffer_attach(buffer, &background->surface); + wlsc_sprite_attach(sprite, &background->surface); return background; } @@ -516,6 +572,7 @@ wlsc_output_repaint(struct wlsc_output *output) struct wlsc_surface *es; struct wlsc_input_device *eid; pixman_region32_t new_damage, total_damage, repaint; + int using_hardware_cursor = 1; output->prepare_render(output); @@ -536,14 +593,23 @@ wlsc_output_repaint(struct wlsc_output *output) &output->previous_damage_region); pixman_region32_copy(&output->previous_damage_region, &new_damage); + if (ec->focus) + if (output->set_hardware_cursor(output, ec->input_device) < 0) + using_hardware_cursor = 0; + 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->visual == &ec->compositor.rgb_visual && + using_hardware_cursor && wlsc_surface_is_scanoutable(es, output)) { output->scanout_surface = es; + /* we're drawing nothing now, draw the damages later */ + pixman_region32_union(&ec->damage_region, + &ec->damage_region, + &total_damage); } else { if (es->width < output->width || es->height < output->height) @@ -589,8 +655,12 @@ wlsc_output_repaint(struct wlsc_output *output) wlsc_surface_draw(ec->overlay, output, &total_damage); if (ec->focus) - wl_list_for_each(eid, &ec->input_device_list, link) - wlsc_surface_draw(eid->sprite, output, &total_damage); + wl_list_for_each(eid, &ec->input_device_list, link) { + if (&eid->input_device != ec->input_device || + !using_hardware_cursor) + wlsc_surface_draw(eid->sprite, output, + &total_damage); + } } static void @@ -814,23 +884,37 @@ const static struct wl_surface_interface surface_interface = { static void wlsc_input_device_attach(struct wlsc_input_device *device, - struct wl_buffer *buffer, int x, int y) + int x, int y, int width, int height) { wlsc_surface_damage(device->sprite); - wlsc_buffer_attach(buffer, &device->sprite->surface); device->hotspot_x = x; device->hotspot_y = y; device->sprite->x = device->input_device.x - device->hotspot_x; device->sprite->y = device->input_device.y - device->hotspot_y; - device->sprite->width = buffer->width; - device->sprite->height = buffer->height; + device->sprite->width = width; + device->sprite->height = height; wlsc_surface_update_matrix(device->sprite); wlsc_surface_damage(device->sprite); } +static void +wlsc_input_device_attach_buffer(struct wlsc_input_device *device, + struct wl_buffer *buffer, int x, int y) +{ + wlsc_buffer_attach(buffer, &device->sprite->surface); + wlsc_input_device_attach(device, x, y, buffer->width, buffer->height); +} + +static void +wlsc_input_device_attach_sprite(struct wlsc_input_device *device, + struct wlsc_sprite *sprite, int x, int y) +{ + wlsc_sprite_attach(sprite, &device->sprite->surface); + wlsc_input_device_attach(device, x, y, sprite->width, sprite->height); +} void wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, @@ -839,10 +923,10 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, struct wlsc_compositor *compositor = (struct wlsc_compositor *) device->input_device.compositor; - wlsc_input_device_attach(device, - compositor->pointer_buffers[type], - pointer_images[type].hotspot_x, - pointer_images[type].hotspot_y); + wlsc_input_device_attach_sprite(device, + compositor->pointer_sprites[type], + pointer_images[type].hotspot_x, + pointer_images[type].hotspot_y); } static void @@ -1268,7 +1352,7 @@ input_device_attach(struct wl_client *client, return; } - wlsc_input_device_attach(device, buffer, x, y); + wlsc_input_device_attach_buffer(device, buffer, x, y); } const static struct wl_input_device_interface input_device_interface = { diff --git a/compositor/compositor.h b/compositor/compositor.h index 12905f0b..84c01397 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -57,6 +57,8 @@ struct wlsc_output { int (*present)(struct wlsc_output *output); int (*image_is_scanoutable)(struct wlsc_output *output, EGLImageKHR image); + int (*set_hardware_cursor)(struct wlsc_output *output, + struct wl_input_device *input); }; enum wlsc_pointer_type { @@ -86,6 +88,14 @@ struct wlsc_shm { struct wl_object object; }; +struct wlsc_sprite { + GLuint texture; + EGLImageKHR image; + struct wl_visual *visual; + int width; + int height; +}; + struct wlsc_compositor { struct wl_compositor compositor; @@ -95,7 +105,7 @@ struct wlsc_compositor { EGLConfig config; GLuint fbo; GLuint proj_uniform, tex_uniform; - struct wl_buffer **pointer_buffers; + struct wlsc_sprite **pointer_sprites; struct wl_display *wl_display; /* We implement the shell interface. */ @@ -122,10 +132,8 @@ struct wlsc_compositor { void (*destroy)(struct wlsc_compositor *ec); int (*authenticate)(struct wlsc_compositor *c, uint32_t id); - struct wl_buffer *(*create_buffer)(struct wlsc_compositor *c, - int32_t width, int32_t height, - int32_t stride, struct wl_visual *visual, - void *data); + EGLImageKHR (*create_cursor_image)(struct wlsc_compositor *c, + int32_t width, int32_t height); }; #define MODIFIER_CTRL (1 << 8) @@ -150,7 +158,7 @@ enum wlsc_surface_map_type { struct wlsc_surface { struct wl_surface surface; struct wlsc_compositor *compositor; - GLuint texture; + GLuint texture, saved_texture; int32_t x, y, width, height; int32_t saved_x, saved_y; struct wl_list link; @@ -210,6 +218,9 @@ wlsc_compositor_add_binding(struct wlsc_compositor *compositor, void wlsc_binding_destroy(struct wlsc_binding *binding); +struct wlsc_surface * +wlsc_surface_create(struct wlsc_compositor *compositor, + int32_t x, int32_t y, int32_t width, int32_t height); void wlsc_surface_assign_output(struct wlsc_surface *surface); diff --git a/compositor/shm.c b/compositor/shm.c index 967ff727..4c17a08d 100644 --- a/compositor/shm.c +++ b/compositor/shm.c @@ -195,24 +195,3 @@ wlsc_shm_init(struct wlsc_compositor *ec) return 0; } - -struct wl_buffer * -wlsc_shm_buffer_create(struct wlsc_compositor *ec, int width, int height, - int stride, struct wl_visual *visual, - void *data) -{ - struct wlsc_shm_buffer *buffer; - void *pixels; - - pixels = malloc(stride * height); - if (!pixels) - return NULL; - - memcpy(pixels, data, stride * height); - - buffer = wlsc_shm_buffer_init(ec, width, height, - stride, visual, pixels); - buffer->mapped = 0; - - return &buffer->buffer; -}