Make use of a hardware cursor in compositor-drm
diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c
index 7527023..4133c19 100644
--- a/compositor/compositor-drm.c
+++ b/compositor/compositor-drm.c
@@ -179,6 +179,68 @@
 	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 @@
 	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_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 @@
 	}
 
 	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 93fb577..f457570 100644
--- a/compositor/compositor-wayland.c
+++ b/compositor/compositor-wayland.c
@@ -204,6 +204,13 @@
 }
 
 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 @@
 	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 @@
 		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 e63d6be..32225c3 100644
--- a/compositor/compositor-x11.c
+++ b/compositor/compositor-x11.c
@@ -198,6 +198,14 @@
 	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 @@
 	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 @@
 		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 e88293a..5ff7a45 100644
--- a/compositor/compositor.c
+++ b/compositor/compositor.c
@@ -120,7 +120,7 @@
 	*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 @@
 	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 @@
 	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 @@
 					      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;
 
-	buffer = ec->create_buffer(ec, width, height, width * 4,
-				   &ec->compositor.premultiplied_argb_visual,
-				   pixels);
+	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;
+
+	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 @@
 	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 @@
 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 @@
 	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 @@
 	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 @@
 			      &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_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 @@
 
 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 @@
 	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 @@
 		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 12905f0..84c0139 100644
--- a/compositor/compositor.h
+++ b/compositor/compositor.h
@@ -57,6 +57,8 @@
 	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 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 @@
 	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 @@
 
 	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 @@
 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 @@
 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 967ff72..4c17a08 100644
--- a/compositor/shm.c
+++ b/compositor/shm.c
@@ -195,24 +195,3 @@
 
 	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;
-}