Add a shm buffer sharing mechanism

dev
Kristian Høgsberg 14 years ago
parent 98ffc93b95
commit 3d5bae0700
  1. 6
      TODO
  2. 5
      compositor/Makefile
  3. 43
      compositor/compositor.c
  4. 30
      compositor/compositor.h
  5. 74
      compositor/drm.c
  6. 156
      compositor/shm.c
  7. 11
      wayland/protocol.xml
  8. 7
      wayland/wayland-server.h

@ -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 */

@ -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

@ -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);

@ -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);

@ -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);
@ -59,6 +60,25 @@ const static struct wl_buffer_interface buffer_interface = {
buffer_destroy
};
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,
@ -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;
}

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#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;
}

@ -68,6 +68,17 @@
<event name="authenticated"/>
</interface>
<interface name="shm" version="1">
<request name="create_buffer">
<arg name="id" type="new_id" interface="buffer"/>
<arg name="fd" type="fd"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="stride" type="uint"/>
<arg name="visual" type="object" interface="visual"/>
</request>
</interface>
<interface name="buffer" version="1">
<request name="destroy" type="destructor"/>
</interface>

@ -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 {

Loading…
Cancel
Save