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 */
include ../config.mk
-CFLAGS += $(COMPOSITOR_CFLAGS)
+CFLAGS += -I../wayland $(COMPOSITOR_CFLAGS)
LDLIBS += -L../wayland -lwayland-server $(COMPOSITOR_LIBS) -rdynamic -lrt -lm
all : compositor
compositor-x11.o \
screenshooter.o \
screenshooter-protocol.o \
- drm.o
+ drm.o \
+ shm.o
screenshooter.c : screenshooter-server-protocol.h
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);
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;
}
}
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
{
struct wlsc_surface *es = (struct wlsc_surface *) surface;
+ es->buffer->damage(es->buffer, surface, x, y, width, height);
wlsc_compositor_schedule_repaint(es->compositor);
}
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;
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);
}
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;
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);
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 {
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. */
struct wlsc_matrix matrix;
struct wlsc_matrix matrix_inv;
struct wl_visual *visual;
+ struct wl_buffer *buffer;
};
void
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
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);
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);
};
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)
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,
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,
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;
+}
--- /dev/null
+/*
+ * 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;
+}
<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>
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 {