diff --git a/Makefile b/Makefile index a533f612..383188d1 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,22 @@ -CFLAGS += -Wall -g $(shell pkg-config --cflags libffi libdrm) -LDLIBS += $(shell pkg-config --libs libffi libdrm) +CFLAGS = -Wall -g EAGLE_CFLAGS = -I../eagle EAGLE_LDLIBS = -L../eagle -leagle clients = flower pointer background window +compositors = egl-compositor.so glx-compositor.so -all : wayland $(clients) +all : wayland libwayland.so $(compositors) $(clients) -wayland_objs = wayland.o event-loop.o connection.o hash.o input.o egl-compositor.o -wayland : CFLAGS += $(EAGLE_CFLAGS) -wayland : LDLIBS += $(EAGLE_LDLIBS) +wayland_objs = \ + wayland.o \ + event-loop.o \ + connection.o \ + hash.o \ + input.o + +wayland : CFLAGS += $(shell pkg-config --cflags libffi) +wayland : LDLIBS += $(shell pkg-config --libs libffi) -ldl -rdynamic wayland : $(wayland_objs) gcc -o $@ $(LDLIBS) $(wayland_objs) @@ -18,7 +24,23 @@ wayland : $(wayland_objs) libwayland_objs = wayland-client.o connection.o libwayland.so : $(libwayland_objs) - gcc -o $@ $(libwayland_objs) -shared + +$(compositors) $(clients) : CFLAGS += $(shell pkg-config --cflags libdrm) + +egl_compositor_objs = egl-compositor.o +egl-compositor.so : CFLAGS += $(EAGLE_CFLAGS) +egl-compositor.so : LDLIBS += $(EAGLE_LDLIBS) -rdynamic + +egl-compositor.so : $(egl_compositor_objs) + +glx_compositor_objs = glx-compositor.o +glx-compositor.so : LDLIBS += -lGL + +glx-compositor.so : $(glx_compositor_objs) + + +libwayland.so $(compositors) : + gcc -o $@ $^ $(LDLIBS) -shared flower_objs = flower.o pointer_objs = pointer.o @@ -26,7 +48,7 @@ background_objs = background.o window_objs = window.o gears.o $(clients) : CFLAGS += $(shell pkg-config --cflags cairo) -$(clients) : LDLIBS += $(shell pkg-config --libs cairo gdk-pixbuf-2.0) -lrt +$(clients) : LDLIBS += $(shell pkg-config --libs cairo) -lrt background : CFLAGS += $(shell pkg-config --cflags gdk-pixbuf-2.0) background : LDLIBS += $(shell pkg-config --libs gdk-pixbuf-2.0) @@ -44,4 +66,4 @@ $(clients) : gcc -o $@ -L. -lwayland $(LDLIBS) $^ clean : - rm -f $(clients) wayland *.o libwayland.so \ No newline at end of file + rm -f $(clients) wayland *.o *.so diff --git a/egl-compositor.c b/egl-compositor.c index 40ffc4cf..c37ea120 100644 --- a/egl-compositor.c +++ b/egl-compositor.c @@ -85,7 +85,8 @@ repaint(void *data) eglSwapBuffers(ec->display, ec->surface); } -static void schedule_repaint(struct egl_compositor *ec) +static void +schedule_repaint(struct egl_compositor *ec) { struct wl_event_loop *loop; @@ -93,8 +94,9 @@ static void schedule_repaint(struct egl_compositor *ec) wl_event_loop_add_idle(loop, repaint, ec); } -void notify_surface_create(struct wl_compositor *compositor, - struct wl_surface *surface) +static void +notify_surface_create(struct wl_compositor *compositor, + struct wl_surface *surface) { struct surface_data *sd; @@ -108,8 +110,9 @@ void notify_surface_create(struct wl_compositor *compositor, glGenTextures(1, &sd->texture); } -void notify_surface_destroy(struct wl_compositor *compositor, - struct wl_surface *surface) +static void +notify_surface_destroy(struct wl_compositor *compositor, + struct wl_surface *surface) { struct egl_compositor *ec = (struct egl_compositor *) compositor; struct surface_data *sd; @@ -128,9 +131,10 @@ void notify_surface_destroy(struct wl_compositor *compositor, schedule_repaint(ec); } -void notify_surface_attach(struct wl_compositor *compositor, - struct wl_surface *surface, uint32_t name, - uint32_t width, uint32_t height, uint32_t stride) +static 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; @@ -158,8 +162,9 @@ void notify_surface_attach(struct wl_compositor *compositor, schedule_repaint(ec); } -void notify_surface_map(struct wl_compositor *compositor, - struct wl_surface *surface, struct wl_map *map) +static 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; @@ -173,7 +178,7 @@ void notify_surface_map(struct wl_compositor *compositor, schedule_repaint(ec); } -struct wl_compositor_interface interface = { +static const struct wl_compositor_interface interface = { notify_surface_create, notify_surface_destroy, notify_surface_attach, diff --git a/glx-compositor.c b/glx-compositor.c new file mode 100644 index 00000000..574caaf6 --- /dev/null +++ b/glx-compositor.c @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wayland.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +struct glx_compositor { + struct wl_compositor base; + Display *display; + GLXContext context; + Window window; + struct wl_display *wl_display; + int gem_fd; + struct wl_event_source *x_source; +}; + +struct surface_data { + GLuint texture; + struct wl_map map; +}; + +static void +repaint(void *data) +{ + struct glx_compositor *gc = data; + struct wl_surface_iterator *iterator; + struct wl_surface *surface; + struct surface_data *sd; + GLint vertices[12]; + GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 }; + GLuint indices[4] = { 0, 1, 2, 3 }; + + iterator = wl_surface_iterator_create(gc->wl_display, 0); + while (wl_surface_iterator_next(iterator, &surface)) { + sd = wl_surface_get_data(surface); + if (sd == NULL) + continue; + + vertices[0] = sd->map.x; + vertices[1] = sd->map.y; + vertices[2] = 0; + + vertices[3] = sd->map.x; + vertices[4] = sd->map.y + sd->map.height; + vertices[5] = 0; + + vertices[6] = sd->map.x + sd->map.width; + vertices[7] = sd->map.y; + vertices[8] = 0; + + vertices[9] = sd->map.x + sd->map.width; + vertices[10] = sd->map.y + sd->map.height; + vertices[11] = 0; + + glBindTexture(GL_TEXTURE_2D, sd->texture); + glEnable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + /* Assume pre-multiplied alpha for now, this probably + * needs to be a wayland visual type of thing. */ + glBlendFunc(GL_ONE, 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_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices); + } + wl_surface_iterator_destroy(iterator); + + glXSwapBuffers(gc->display, gc->window); +} + +static void +schedule_repaint(struct glx_compositor *gc) +{ + struct wl_event_loop *loop; + + loop = wl_display_get_event_loop(gc->wl_display); + wl_event_loop_add_idle(loop, repaint, gc); +} + +static void +notify_surface_create(struct wl_compositor *compositor, + struct wl_surface *surface) +{ + struct surface_data *sd; + + sd = malloc(sizeof *sd); + if (sd == NULL) + return; + + wl_surface_set_data(surface, sd); + + glGenTextures(1, &sd->texture); +} + +static void +notify_surface_destroy(struct wl_compositor *compositor, + struct wl_surface *surface) +{ + struct glx_compositor *gc = (struct glx_compositor *) compositor; + struct surface_data *sd; + + sd = wl_surface_get_data(surface); + if (sd == NULL) + return; + + glDeleteTextures(1, &sd->texture); + + free(sd); + + schedule_repaint(gc); +} + +static 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 glx_compositor *gc = (struct glx_compositor *) compositor; + struct surface_data *sd; + struct drm_gem_open open_arg; + struct drm_gem_close close_arg; + struct drm_i915_gem_pread pread; + uint32_t size; + void *data; + int ret; + + sd = wl_surface_get_data(surface); + if (sd == NULL) + return; + + open_arg.name = name; + ret = ioctl(gc->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (ret != 0) { + fprintf(stderr, + "failed to gem_open name %d, fd=%d: %m\n", + name, gc->gem_fd); + return; + } + + size = height * stride; + data = malloc(size); + if (data == NULL) { + fprintf(stderr, "malloc for gem_pread failed\n"); + return; + } + + pread.handle = open_arg.handle; + pread.pad = 0; + pread.offset = 0; + pread.size = size; + pread.data_ptr = (long) data; + + if (ioctl(gc->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) { + fprintf(stderr, "gem_pread failed"); + return; + } + + close_arg.handle = open_arg.handle; + ret = ioctl(gc->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + if (ret != 0) { + fprintf(stderr, "failed to gem_close name %d: %m\n", name); + 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); + + schedule_repaint(gc); +} + +static void +notify_surface_map(struct wl_compositor *compositor, + struct wl_surface *surface, struct wl_map *map) +{ + struct glx_compositor *gc = (struct glx_compositor *) compositor; + struct surface_data *sd; + + sd = wl_surface_get_data(surface); + if (sd == NULL) + return; + + sd->map = *map; + + schedule_repaint(gc); +} + +static const 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"; + +static void +display_data(int fd, uint32_t mask, void *data) +{ + struct glx_compositor *gc = data; + XEvent ev; + + while (XPending(gc->display) > 0) { + XNextEvent(gc->display, &ev); + /* Some day we'll do something useful with these events. */ + } +} + +struct wl_compositor * +wl_compositor_create(struct wl_display *display) +{ + static int attribs[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None + }; + struct glx_compositor *gc; + const int x = 100, y = 100, width = 1024, height = 768; + XSetWindowAttributes attr; + unsigned long mask; + Window root; + XVisualInfo *visinfo; + int screen; + struct wl_event_loop *loop; + + gc = malloc(sizeof *gc); + if (gc == NULL) + return NULL; + + gc->base.interface = &interface; + gc->wl_display = display; + gc->display = XOpenDisplay(NULL); + if (gc->display == NULL) { + free(gc); + return NULL; + } + + loop = wl_display_get_event_loop(gc->wl_display); + gc->x_source = wl_event_loop_add_fd(loop, + ConnectionNumber(gc->display), + WL_EVENT_READABLE, + display_data, gc); + + screen = DefaultScreen(gc->display); + root = RootWindow(gc->display, screen); + + visinfo = glXChooseVisual(gc->display, screen, attribs); + + /* window attributes */ + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(gc->display, + root, visinfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + gc->window = XCreateWindow(gc->display, root, x, y, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr); + + gc->context = glXCreateContext(gc->display, visinfo, NULL, True); + + XMapWindow(gc->display, gc->window); + glXMakeCurrent(gc->display, gc->window, gc->context); + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, 0, 1000.0); + glMatrixMode(GL_MODELVIEW); + glClearColor(0.0, 0.05, 0.2, 0.0); + + gc->gem_fd = open(gem_device, O_RDWR); + if (gc->gem_fd < 0) { + fprintf(stderr, "failed to open drm device\n"); + return NULL; + } + + schedule_repaint(gc); + + return &gc->base; +} diff --git a/wayland.c b/wayland.c index 765a443c..b51d3877 100644 --- a/wayland.c +++ b/wayland.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "wayland.h" @@ -98,7 +99,7 @@ static void wl_surface_destroy(struct wl_client *client, struct wl_surface *surface) { - struct wl_compositor_interface *interface; + const struct wl_compositor_interface *interface; interface = client->display->compositor->interface; interface->notify_surface_destroy(client->display->compositor, @@ -111,7 +112,7 @@ wl_surface_attach(struct wl_client *client, struct wl_surface *surface, uint32_t name, uint32_t width, uint32_t height, uint32_t stride) { - struct wl_compositor_interface *interface; + const struct wl_compositor_interface *interface; interface = client->display->compositor->interface; interface->notify_surface_attach(client->display->compositor, @@ -129,7 +130,7 @@ void wl_surface_map(struct wl_client *client, struct wl_surface *surface, int32_t x, int32_t y, int32_t width, int32_t height) { - struct wl_compositor_interface *interface; + const struct wl_compositor_interface *interface; /* FIXME: This needs to take a tri-mesh argument... - count * and a list of tris. 0 tris means unmap. */ @@ -170,7 +171,7 @@ struct wl_surface * wl_surface_create(struct wl_display *display, uint32_t id) { struct wl_surface *surface; - struct wl_compositor_interface *interface; + const struct wl_compositor_interface *interface; surface = malloc(sizeof *surface); if (surface == NULL) @@ -706,10 +707,41 @@ wl_surface_iterator_destroy(struct wl_surface_iterator *iterator) free(iterator); } +static int +load_compositor(struct wl_display *display, const char *path) +{ + struct wl_compositor *(*create)(struct wl_display *display); + struct wl_compositor *compositor; + void *p; + + p = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); + if (p == NULL) { + fprintf(stderr, "failed to open compositor %s: %s\n", + path, dlerror()); + return -1; + } + + create = dlsym(p, "wl_compositor_create"); + if (create == NULL) { + fprintf(stderr, "failed to look up compositor constructor\n"); + return -1; + } + + compositor = create(display); + if (compositor == NULL) { + fprintf(stderr, "couldn't create compositor\n"); + return -1; + } + + wl_display_set_compositor(display, compositor); + + return 0; +} + int main(int argc, char *argv[]) { struct wl_display *display; - struct wl_compositor *compositor; + const char *compositor = "egl-compositor.so"; display = wl_display_create(); @@ -718,10 +750,9 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - compositor = wl_compositor_create(display); - wl_display_set_compositor(display, compositor); - - printf("wayland online, display is %p\n", display); + if (argc == 2) + compositor = argv[1]; + load_compositor(display, compositor); wl_display_run(display); diff --git a/wayland.h b/wayland.h index a7e80a41..ec28a44e 100644 --- a/wayland.h +++ b/wayland.h @@ -113,7 +113,7 @@ wl_display_post_button_event(struct wl_display *display, struct wl_object *source, int button, int state); struct wl_compositor { - struct wl_compositor_interface *interface; + const struct wl_compositor_interface *interface; }; struct wl_compositor_interface { @@ -128,8 +128,6 @@ struct wl_compositor_interface { struct wl_surface *surface, struct wl_map *map); }; -struct wl_compositor *wl_compositor_create(struct wl_display *display); - void wl_display_set_compositor(struct wl_display *display, struct wl_compositor *compositor);