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)
{
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);
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)
{
}
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);
*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)
{
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;
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,
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 {
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);
}
}
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,
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;
}
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);
&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)
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
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,
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
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 = {