From 3d5bae0700e4467000948133f89ce48cc295b4ff Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 6 Oct 2010 21:17:40 -0400 Subject: [PATCH] Add a shm buffer sharing mechanism --- TODO | 6 +- compositor/Makefile | 5 +- compositor/compositor.c | 43 +++++-------- compositor/compositor.h | 30 +++++++-- compositor/drm.c | 74 +++++++++++++++++++--- compositor/shm.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++ wayland/protocol.xml | 11 ++++ wayland/wayland-server.h | 7 +++ 8 files changed, 286 insertions(+), 46 deletions(-) create mode 100644 compositor/shm.c diff --git a/TODO b/TODO index 9be90be..871d551 100644 --- a/TODO +++ b/TODO @@ -17,13 +17,15 @@ Core wayland protocol buffer = drm.create_buffer(); /* buffer with stuff in it */ - cache.upload(buffer, x, y, width, height, int key) + cache.upload(buffer, x, y, width, height, int hash) drm.buffer: id, name, stride etc /* event to announce cache buffer */ - cache.image: key, buffer, x, y, stride /* event to announce + cache.image: hash, buffer, x, y, stride /* event to announce * location in cache */ + cache.reject: hash /* no upload for you! */ + cache.retire: buffer /* cache has stopped using buffer, please * reupload whatever you had in that buffer */ diff --git a/compositor/Makefile b/compositor/Makefile index f31c9ee..21d8353 100644 --- a/compositor/Makefile +++ b/compositor/Makefile @@ -1,6 +1,6 @@ include ../config.mk -CFLAGS += $(COMPOSITOR_CFLAGS) +CFLAGS += -I../wayland $(COMPOSITOR_CFLAGS) LDLIBS += -L../wayland -lwayland-server $(COMPOSITOR_LIBS) -rdynamic -lrt -lm all : compositor @@ -11,7 +11,8 @@ compositor : \ compositor-x11.o \ screenshooter.o \ screenshooter-protocol.o \ - drm.o + drm.o \ + shm.o screenshooter.c : screenshooter-server-protocol.h diff --git a/compositor/compositor.c b/compositor/compositor.c index df75b61..8dadd73 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -221,14 +221,6 @@ create_pointer_images(struct wlsc_compositor *ec) GLuint texture; const int width = 32, height = 32; - EGLint image_attribs[] = { - EGL_WIDTH, 0, - EGL_HEIGHT, 0, - EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, - EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA, - EGL_NONE - }; - glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -236,19 +228,15 @@ create_pointer_images(struct wlsc_compositor *ec) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - image_attribs[1] = width; - image_attribs[3] = height; count = ARRAY_LENGTH(pointer_images); ec->pointer_buffers = malloc(count * sizeof *ec->pointer_buffers); for (i = 0; i < count; i++) { - ec->pointer_buffers[i].image = - eglCreateDRMImageMESA(ec->display, image_attribs); + ec->pointer_buffers[i] = + wlsc_drm_buffer_create(ec, width, height, + &ec->argb_visual); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, - ec->pointer_buffers[i].image); + ec->pointer_buffers[i]->image); texture_from_png(pointer_images[i].filename, width, height); - ec->pointer_buffers[i].visual = &ec->argb_visual; - ec->pointer_buffers[i].width = width; - ec->pointer_buffers[i].height = height; } } @@ -413,15 +401,12 @@ surface_destroy(struct wl_client *client, static void surface_attach(struct wl_client *client, - struct wl_surface *surface, struct wl_buffer *buffer_base) + struct wl_surface *surface, struct wl_buffer *buffer) { struct wlsc_surface *es = (struct wlsc_surface *) surface; - struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base; - glBindTexture(GL_TEXTURE_2D, es->texture); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image); - es->visual = buffer->visual; - wlsc_compositor_schedule_repaint(es->compositor); + buffer->attach(buffer, surface); + es->buffer = buffer; } static void @@ -447,6 +432,7 @@ surface_damage(struct wl_client *client, { struct wlsc_surface *es = (struct wlsc_surface *) surface; + es->buffer->damage(es->buffer, surface, x, y, width, height); wlsc_compositor_schedule_repaint(es->compositor); } @@ -459,13 +445,11 @@ const static struct wl_surface_interface surface_interface = { static void wlsc_input_device_attach(struct wlsc_input_device *device, - struct wlsc_buffer *buffer, int x, int y) + struct wl_buffer *buffer, int x, int y) { struct wlsc_compositor *ec = device->ec; - glBindTexture(GL_TEXTURE_2D, device->sprite->texture); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image); - device->sprite->visual = buffer->visual; + buffer->attach(buffer, &device->sprite->base); device->hotspot_x = x; device->hotspot_y = y; @@ -486,7 +470,7 @@ wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, struct wlsc_compositor *compositor = device->ec; wlsc_input_device_attach(device, - &compositor->pointer_buffers[type], + &compositor->pointer_buffers[type]->base, pointer_images[type].hotspot_x, pointer_images[type].hotspot_y); } @@ -982,11 +966,10 @@ static void input_device_attach(struct wl_client *client, struct wl_input_device *device_base, uint32_t time, - struct wl_buffer *buffer_base, int32_t x, int32_t y) + struct wl_buffer *buffer, int32_t x, int32_t y) { struct wlsc_input_device *device = (struct wlsc_input_device *) device_base; - struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base; if (time < device->pointer_focus_time) return; @@ -1391,6 +1374,8 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) if (wl_display_add_global(display, &ec->base.base, NULL)) return -1; + wlsc_shm_init(ec); + ec->shell.base.interface = &wl_shell_interface; ec->shell.base.implementation = (void (**)(void)) &shell_interface; wl_display_add_object(display, &ec->shell.base); diff --git a/compositor/compositor.h b/compositor/compositor.h index d175965..558bd79 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -119,12 +119,19 @@ struct wlsc_drm { char *filename; }; -struct wlsc_buffer { +struct wlsc_drm_buffer { struct wl_buffer base; - struct wlsc_compositor *compositor; - int32_t width, height; EGLImageKHR image; - struct wl_visual *visual; +}; + +struct wlsc_shm { + struct wl_object base; +}; + +struct wlsc_shm_buffer { + struct wl_buffer base; + int32_t stride; + void *data; }; struct wlsc_compositor { @@ -132,11 +139,12 @@ struct wlsc_compositor { struct wl_visual argb_visual, premultiplied_argb_visual, rgb_visual; struct wlsc_drm drm; + struct wlsc_shm shm; EGLDisplay display; EGLContext context; GLuint fbo, vbo; GLuint proj_uniform, tex_uniform; - struct wlsc_buffer *pointer_buffers; + struct wlsc_drm_buffer **pointer_buffers; struct wl_display *wl_display; /* We implement the shell interface. */ @@ -180,6 +188,7 @@ struct wlsc_surface { struct wlsc_matrix matrix; struct wlsc_matrix matrix_inv; struct wl_visual *visual; + struct wl_buffer *buffer; }; void @@ -197,6 +206,10 @@ wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); +struct wlsc_drm_buffer * +wlsc_drm_buffer_create(struct wlsc_compositor *ec, + int width, int height, struct wl_visual *visual); + int wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display); void @@ -208,6 +221,13 @@ wlsc_input_device_init(struct wlsc_input_device *device, int wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename); +int +wlsc_shm_init(struct wlsc_compositor *ec); + +struct wl_buffer * +wl_buffer_create_drm(struct wlsc_compositor *compositor, + struct wl_visual *visual); + struct wlsc_compositor * x11_compositor_create(struct wl_display *display); diff --git a/compositor/drm.c b/compositor/drm.c index 87863e8..00134e7 100644 --- a/compositor/drm.c +++ b/compositor/drm.c @@ -41,9 +41,10 @@ drm_authenticate(struct wl_client *client, static void destroy_buffer(struct wl_resource *resource, struct wl_client *client) { - struct wlsc_buffer *buffer = - container_of(resource, struct wlsc_buffer, base.base); - struct wlsc_compositor *compositor = buffer->compositor; + struct wlsc_drm_buffer *buffer = + container_of(resource, struct wlsc_drm_buffer, base.base); + struct wlsc_compositor *compositor = + (struct wlsc_compositor *) buffer->base.compositor; eglDestroyImageKHR(compositor->display, buffer->image); free(buffer); @@ -60,6 +61,25 @@ const static struct wl_buffer_interface buffer_interface = { }; static void +drm_buffer_attach(struct wl_buffer *buffer_base, struct wl_surface *surface) +{ + struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct wlsc_drm_buffer *buffer = + (struct wlsc_drm_buffer *) buffer_base; + + glBindTexture(GL_TEXTURE_2D, es->texture); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, buffer->image); + es->visual = buffer->base.visual; +} + +static void +drm_buffer_damage(struct wl_buffer *buffer, + struct wl_surface *surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ +} + +static void drm_create_buffer(struct wl_client *client, struct wl_drm *drm_base, uint32_t id, uint32_t name, int32_t width, int32_t height, uint32_t stride, struct wl_visual *visual) @@ -67,7 +87,7 @@ drm_create_buffer(struct wl_client *client, struct wl_drm *drm_base, struct wlsc_drm *drm = (struct wlsc_drm *) drm_base; struct wlsc_compositor *compositor = container_of(drm, struct wlsc_compositor, drm); - struct wlsc_buffer *buffer; + struct wlsc_drm_buffer *buffer; EGLint attribs[] = { EGL_WIDTH, 0, EGL_HEIGHT, 0, @@ -98,10 +118,11 @@ drm_create_buffer(struct wl_client *client, struct wl_drm *drm_base, attribs[3] = height; attribs[5] = stride / 4; - buffer->compositor = compositor; - buffer->width = width; - buffer->height = height; - buffer->visual = visual; + buffer->base.compositor = &compositor->base; + buffer->base.width = width; + buffer->base.height = height; + buffer->base.visual = visual; + buffer->base.attach = drm_buffer_attach; buffer->image = eglCreateImageKHR(compositor->display, compositor->context, EGL_DRM_BUFFER_MESA, @@ -157,3 +178,40 @@ wlsc_drm_init(struct wlsc_compositor *ec, int fd, const char *filename) return 0; } + +struct wlsc_drm_buffer * +wlsc_drm_buffer_create(struct wlsc_compositor *ec, + int width, int height, struct wl_visual *visual) +{ + struct wlsc_drm_buffer *buffer; + + EGLint image_attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA, + EGL_DRM_BUFFER_USE_MESA, EGL_DRM_BUFFER_USE_SCANOUT_MESA, + EGL_NONE + }; + + image_attribs[1] = width; + image_attribs[3] = height; + + buffer = malloc(sizeof *buffer); + if (buffer == NULL) + return NULL; + + buffer->image = + eglCreateDRMImageMESA(ec->display, image_attribs); + if (buffer->image == NULL) { + free(buffer); + return NULL; + } + + buffer->base.visual = visual; + buffer->base.width = width; + buffer->base.height = height; + buffer->base.attach = drm_buffer_attach; + buffer->base.damage = drm_buffer_damage; + + return buffer; +} diff --git a/compositor/shm.c b/compositor/shm.c new file mode 100644 index 0000000..2f1245b --- /dev/null +++ b/compositor/shm.c @@ -0,0 +1,156 @@ +/* + * Copyright © 2010 Kristian Høgsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include "compositor.h" + + +static void +destroy_buffer(struct wl_resource *resource, struct wl_client *client) +{ + struct wlsc_shm_buffer *buffer = + container_of(resource, struct wlsc_shm_buffer, base.base); + + munmap(buffer->data, buffer->stride * buffer->base.height); + free(buffer); +} + +static void +buffer_destroy(struct wl_client *client, struct wl_buffer *buffer) +{ + // wl_resource_destroy(&buffer->base, client); +} + +const static struct wl_buffer_interface buffer_interface = { + buffer_destroy +}; + +static void +shm_buffer_attach(struct wl_buffer *buffer_base, struct wl_surface *surface) +{ + struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct wlsc_shm_buffer *buffer = + (struct wlsc_shm_buffer *) buffer_base; + + glBindTexture(GL_TEXTURE_2D, es->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, + buffer->base.width, buffer->base.height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, buffer->data); + es->visual = buffer->base.visual; +} + +static void +shm_buffer_damage(struct wl_buffer *buffer_base, + struct wl_surface *surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct wlsc_shm_buffer *buffer = + (struct wlsc_shm_buffer *) buffer_base; + + glBindTexture(GL_TEXTURE_2D, es->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, + buffer->base.width, buffer->base.height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, buffer->data); + + /* Hmm, should use glTexSubImage2D() here but GLES2 doesn't + * support any unpack attributes except GL_UNPACK_ALIGNMENT. */ +} + +static void +shm_create_buffer(struct wl_client *client, struct wl_shm *shm, + uint32_t id, int fd, int32_t width, int32_t height, + uint32_t stride, struct wl_visual *visual) +{ + struct wlsc_compositor *compositor = + container_of((struct wlsc_shm *) shm, + struct wlsc_compositor, shm); + struct wlsc_shm_buffer *buffer; + + if (visual != &compositor->argb_visual && + visual != &compositor->premultiplied_argb_visual && + visual != &compositor->rgb_visual) { + /* FIXME: Define a real exception event instead of + * abusing this one */ + wl_client_post_event(client, + (struct wl_object *) compositor->wl_display, + WL_DISPLAY_INVALID_OBJECT, 0); + fprintf(stderr, "invalid visual in create_buffer\n"); + close(fd); + return; + } + + buffer = malloc(sizeof *buffer); + if (buffer == NULL) { + close(fd); + wl_client_post_no_memory(client); + return; + } + + buffer->base.compositor = (struct wl_compositor *) compositor; + buffer->base.width = width; + buffer->base.height = height; + buffer->base.visual = visual; + buffer->base.attach = shm_buffer_attach; + buffer->base.damage = shm_buffer_damage; + buffer->stride = stride; + buffer->data = + mmap(NULL, stride * height, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + if (buffer->data == MAP_FAILED) { + /* FIXME: Define a real exception event instead of + * abusing this one */ + free(buffer); + wl_client_post_event(client, + (struct wl_object *) compositor->wl_display, + WL_DISPLAY_INVALID_OBJECT, 0); + fprintf(stderr, "failed to create image for fd %d\n", fd); + return; + } + + buffer->base.base.base.id = id; + buffer->base.base.base.interface = &wl_buffer_interface; + buffer->base.base.base.implementation = (void (**)(void)) + &buffer_interface; + + buffer->base.base.destroy = destroy_buffer; + + wl_client_add_resource(client, &buffer->base.base); +} + +const static struct wl_shm_interface shm_interface = { + shm_create_buffer +}; + +int +wlsc_shm_init(struct wlsc_compositor *ec) +{ + struct wlsc_shm *shm = &ec->shm; + + shm->base.interface = &wl_shm_interface; + shm->base.implementation = (void (**)(void)) &shm_interface; + wl_display_add_object(ec->wl_display, &shm->base); + wl_display_add_global(ec->wl_display, &shm->base, NULL); + + return 0; +} diff --git a/wayland/protocol.xml b/wayland/protocol.xml index 1f880cd..84398ac 100644 --- a/wayland/protocol.xml +++ b/wayland/protocol.xml @@ -68,6 +68,17 @@ + + + + + + + + + + + diff --git a/wayland/wayland-server.h b/wayland/wayland-server.h index 4405033..53c78ba 100644 --- a/wayland/wayland-server.h +++ b/wayland/wayland-server.h @@ -107,6 +107,13 @@ struct wl_resource { struct wl_buffer { struct wl_resource base; + struct wl_compositor *compositor; + struct wl_visual *visual; + int32_t width, height; + void (*attach)(struct wl_buffer *buffer, struct wl_surface *surface); + void (*damage)(struct wl_buffer *buffer, + struct wl_surface *surface, + int32_t x, int32_t y, int32_t width, int32_t height); }; struct wl_surface { -- 2.7.4