From: Kristian Høgsberg Date: Thu, 9 Oct 2008 02:51:32 +0000 (-0400) Subject: Add an EGL compositor. Still pretty lame. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=16eb6753991d33cc2a90e6f8d1b970cf4603ef0e;p=profile%2Fivi%2Fwayland.git Add an EGL compositor. Still pretty lame. --- diff --git a/Makefile b/Makefile index 21f28e8..0c16050 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,12 @@ LDLIBS += $(shell pkg-config --libs libffi libdrm) all : wayland client -wayland_objs = wayland.o event-loop.o connection.o hash.o compositor.o +wayland_objs = wayland.o event-loop.o connection.o hash.o egl-compositor.o +wayland : CFLAGS += -I../eagle +wayland : LDLIBS += -L../eagle -leagle -ldl wayland : $(wayland_objs) - gcc -o $@ $(wayland_objs) $(LDLIBS) + gcc -o $@ $(LDLIBS) $(wayland_objs) libwayland_objs = wayland-client.o connection.o diff --git a/client.c b/client.c index 8eb83b3..5c8e8ed 100644 --- a/client.c +++ b/client.c @@ -112,7 +112,7 @@ int main(int argc, char *argv[]) { struct wl_display *display; struct wl_surface *surface; - const int x = 400, y = 200, width = 300, height = 300; + const int x = 200, y = 100, width = 300, height = 300; int fd, i, ret; uint32_t name, mask; cairo_surface_t *s; @@ -141,9 +141,12 @@ int main(int argc, char *argv[]) cairo_image_surface_get_stride(s)); i = 0; - while (ret = poll(p, 1, 40), ret >= 0) { + while (ret = poll(p, 1, 20), ret >= 0) { if (ret == 0) { - wl_surface_map(surface, x + i, y + i, width, height); + wl_surface_map(surface, + x + cos(i / 10.0) * 50, + y + sin(i / 10.0) * 50, + width, height); i++; continue; } diff --git a/egl-compositor.c b/egl-compositor.c new file mode 100644 index 0000000..a12d482 --- /dev/null +++ b/egl-compositor.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wayland.h" + +#include +#include + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +struct egl_compositor { + struct wl_compositor base; + EGLDisplay display; + EGLSurface surface; + EGLContext context; + int gem_fd; +}; + +struct surface_data { + uint32_t handle; + int32_t width, height, stride; + GLuint texture; +}; + +void notify_surface_create(struct wl_compositor *compositor, + struct wl_surface *surface) +{ + struct surface_data *sd; + + sd = malloc(sizeof *sd); + if (sd == NULL) + return; + + sd->handle = 0; + wl_surface_set_data(surface, sd); + + glGenTextures(1, &sd->texture); +} + +void notify_surface_destroy(struct wl_compositor *compositor, + struct wl_surface *surface) +{ + struct egl_compositor *ec = (struct egl_compositor *) compositor; + struct surface_data *sd; + struct drm_gem_close close_arg; + int ret; + + sd = wl_surface_get_data(surface); + if (sd == NULL || sd->handle == 0) + return; + + close_arg.handle = sd->handle; + ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + if (ret != 0) { + fprintf(stderr, "failed to gem_close handle %d: %m\n", sd->handle); + } + + glDeleteTextures(1, &sd->texture); + + free(sd); +} + +void notify_surface_attach(struct wl_compositor *compositor, + struct wl_surface *surface, uint32_t name, + uint32_t width, uint32_t height, uint32_t stride) +{ + struct egl_compositor *ec = (struct egl_compositor *) compositor; + struct surface_data *sd; + struct drm_gem_open open_arg; + struct drm_gem_close close_arg; + struct drm_i915_gem_pread pread; + void *data; + uint32_t size; + int ret; + + sd = wl_surface_get_data(surface); + if (sd == NULL) + return; + + if (sd->handle != 0) { + close_arg.handle = sd->handle; + ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + if (ret != 0) { + fprintf(stderr, "failed to gem_close name %d: %m\n", name); + } + } + + open_arg.name = name; + ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (ret != 0) { + fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, ec->gem_fd); + return; + } + + sd->handle = open_arg.handle; + sd->width = width; + sd->height = height; + sd->stride = stride; + + size = sd->height * sd->stride; + data = malloc(size); + if (data == NULL) { + fprintf(stderr, "swap buffers malloc failed\n"); + return; + } + + pread.handle = sd->handle; + pread.pad = 0; + pread.offset = 0; + pread.size = size; + pread.data_ptr = (long) data; + + if (ioctl(ec->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) { + fprintf(stderr, "gem pread failed"); + return; + } + + glBindTexture(GL_TEXTURE_2D, sd->texture); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_BGRA, GL_UNSIGNED_BYTE, data); + + free(data); +} + +void notify_surface_map(struct wl_compositor *compositor, + struct wl_surface *surface, struct wl_map *map) +{ + struct egl_compositor *ec = (struct egl_compositor *) compositor; + struct surface_data *sd; + GLint vertices[12] = { + map->x, map->y, 0.0, + map->x, map->y + map->height, 0.0, + map->x + map->width, map->y + map->height, 0.0, + map->x + map->width, map->y, 0.0 + }; + GLint tex_coords[8] = { + 1, 0, + 1, 1, + 0, 1, + 0, 0 + }; + GLuint indices[4] = { 0, 1, 2, 3 }; + + /* This part is where we actually copy the buffer to screen. + * Needs to be part of the repaint loop, not in the notify_map + * handler. */ + + sd = wl_surface_get_data(surface); + if (sd == NULL) + return; + + glClear(GL_COLOR_BUFFER_BIT); + glBindTexture(GL_TEXTURE_2D, sd->texture); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_INT, 0, vertices); + glTexCoordPointer(2, GL_INT, 0, tex_coords); + glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, indices); + + glFlush(); + + eglSwapBuffers(ec->display, ec->surface); +} + +struct wl_compositor_interface interface = { + notify_surface_create, + notify_surface_destroy, + notify_surface_attach, + notify_surface_map +}; + +static const char gem_device[] = "/dev/dri/card0"; + +struct wl_compositor * +wl_compositor_create(void) +{ + EGLConfig configs[64]; + EGLint major, minor, count; + struct egl_compositor *ec; + const int width = 800, height = 600; + + ec = malloc(sizeof *ec); + if (ec == NULL) + return NULL; + + ec->base.interface = &interface; + + ec->display = eglCreateDisplay(gem_device, "i965"); + if (ec->display == NULL) { + fprintf(stderr, "failed to create display\n"); + return NULL; + } + + if (!eglInitialize(ec->display, &major, &minor)) { + fprintf(stderr, "failed to initialize display\n"); + return NULL; + } + + if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) { + fprintf(stderr, "failed to get configs\n"); + return NULL; + } + + ec->surface = eglCreateSurface(ec->display, configs[24], 0, 0, width, height); + if (ec->surface == NULL) { + fprintf(stderr, "failed to create surface\n"); + return NULL; + } + + ec->context = eglCreateContext(ec->display, configs[24], NULL, NULL); + if (ec->context == NULL) { + fprintf(stderr, "failed to create context\n"); + return NULL; + } + + if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) { + fprintf(stderr, "failed to make context current\n"); + return NULL; + } + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, 0, 1000.0); + glMatrixMode(GL_MODELVIEW); + glClearColor(0.0, 0.1, 0.3, 0.0); + + ec->gem_fd = open(gem_device, O_RDWR); + if (ec->gem_fd < 0) { + fprintf(stderr, "failed to open drm device\n"); + return NULL; + } + + return &ec->base; +}