diff --git a/clients/Makefile b/clients/Makefile index 7dfafe81..35419eb3 100644 --- a/clients/Makefile +++ b/clients/Makefile @@ -8,7 +8,7 @@ all : $(egl_clients) $(cairo_clients) clean : rm -f $(egl_clients) $(cairo_clients) *.o -flower : flower.o wayland-glib.o +flower : flower.o window.o wayland-glib.o gears : gears.o window.o wayland-glib.o screenshot : screenshot.o wayland-glib.o terminal : terminal.o window.o wayland-glib.o @@ -23,5 +23,5 @@ view : LDLIBS += $(POPPLER_LIBS) $(egl_clients) : CFLAGS += $(EGL_CLIENT_CFLAGS) $(egl_clients) : LDLIBS += -L.. -lwayland $(EGL_CLIENT_LIBS) -lrt -lm -$(cairo_clients) : CFLAGS += $(CAIRO_CLIENT_CFLAGS) -$(cairo_clients) : LDLIBS += -L.. -lwayland $(CAIRO_CLIENT_LIBS) -lrt -lm +$(cairo_clients) : CFLAGS += $(CAIRO_CLIENT_CFLAGS) $(EGL_CLIENT_CFLAGS) +$(cairo_clients) : LDLIBS += -L.. -lwayland $(CAIRO_CLIENT_LIBS) $(EGL_CLIENT_LIBS) -lrt -lm diff --git a/clients/flower.c b/clients/flower.c index adbb0cb7..5f3a85e8 100644 --- a/clients/flower.c +++ b/clients/flower.c @@ -31,10 +31,10 @@ #include #include #include -#include #include "wayland-client.h" #include "wayland-glib.h" +#include "window.h" static const char gem_device[] = "/dev/dri/card0"; static const char socket_name[] = "\0wayland"; @@ -96,49 +96,34 @@ draw_stuff(cairo_surface_t *surface, int width, int height) } struct flower { - struct wl_compositor *compositor; - struct wl_surface *surface; + struct window *window; int x, y, width, height; int offset; }; static void -handle_acknowledge(void *data, - struct wl_compositor *compositor, - uint32_t key, uint32_t frame) -{ -} - -static void -handle_frame(void *data, - struct wl_compositor *compositor, - uint32_t frame, uint32_t timestamp) +handle_frame(struct window *window, + uint32_t frame, uint32_t timestamp, void *data) { struct flower *flower = data; - wl_surface_map(flower->surface, - flower->x + cos((flower->offset + timestamp) / 400.0) * 400 - flower->width / 2, - flower->y + sin((flower->offset + timestamp) / 320.0) * 300 - flower->height / 2, - flower->width, flower->height); - wl_compositor_commit(flower->compositor, 0); + window_move(flower->window, + flower->x + cos((flower->offset + timestamp) / 400.0) * 400 - flower->width / 2, + flower->y + sin((flower->offset + timestamp) / 320.0) * 300 - flower->height / 2); + window_commit(flower->window, 0); } -static const struct wl_compositor_listener compositor_listener = { - handle_acknowledge, - handle_frame, -}; - int main(int argc, char *argv[]) { struct wl_display *display; struct wl_visual *visual; int fd; - cairo_device_t *device; cairo_surface_t *s; struct timespec ts; GMainLoop *loop; GSource *source; struct flower flower; + struct display *d; fd = open(gem_device, O_RDWR); if (fd < 0) { @@ -154,40 +139,34 @@ int main(int argc, char *argv[]) return -1; } + d = display_create(display, fd); + source = wl_glib_source_new(display); g_source_attach(source, NULL); - /* Process connection events. */ - wl_display_iterate(display, WL_DISPLAY_READABLE); - - flower.compositor = wl_display_get_compositor(display); flower.x = 512; flower.y = 384; flower.width = 200; flower.height = 200; - flower.surface = wl_compositor_create_surface(flower.compositor); + flower.window = window_create(d, "flower", flower.x, flower.y, + flower.width, flower.height); clock_gettime(CLOCK_MONOTONIC, &ts); srandom(ts.tv_nsec); flower.offset = random(); - device = cairo_drm_device_get_for_fd(fd); - s = cairo_drm_surface_create(device, - CAIRO_CONTENT_COLOR_ALPHA, - flower.width, flower.height); + window_draw(flower.window); + s = window_get_surface(flower.window); + if (s == NULL || cairo_surface_status (s) != CAIRO_STATUS_SUCCESS) { + fprintf(stderr, "failed to create cairo drm surface\n"); + return -1; + } + draw_stuff(s, flower.width, flower.height); + cairo_surface_flush(s); - visual = wl_display_get_premultiplied_argb_visual(display); - wl_surface_attach(flower.surface, - cairo_drm_surface_get_name(s), - flower.width, flower.height, - cairo_drm_surface_get_stride(s), - visual); - - wl_compositor_add_listener(flower.compositor, - &compositor_listener, &flower); - - wl_compositor_commit(flower.compositor, 0); + window_set_frame_handler(flower.window, handle_frame, &flower); + window_commit(flower.window, 0); g_main_loop_run(loop); diff --git a/clients/gears.c b/clients/gears.c index 4b029437..ed714479 100644 --- a/clients/gears.c +++ b/clients/gears.c @@ -339,12 +339,8 @@ handle_frame(void *data, uint32_t frame, uint32_t timestamp) { struct gears *gears = data; - EGLint name, stride; - eglExportDRMImageMESA(gears->display, - gears->image, &name, NULL, &stride); - - window_copy(gears->window, &gears->rectangle, name, stride); + window_copy_image(gears->window, &gears->rectangle, gears->image); window_commit(gears->window, 10); diff --git a/clients/window.c b/clients/window.c index 8008017d..a566c9fb 100644 --- a/clients/window.c +++ b/clients/window.c @@ -30,7 +30,13 @@ #include #include #include -#include + +#define EGL_EGLEXT_PROTOTYPES 1 +#define GL_GLEXT_PROTOTYPES 1 +#include +#include +#include +#include #include #include "wayland-util.h" @@ -46,6 +52,8 @@ struct display { struct wl_output *output; struct wl_input_device *input_device; struct rectangle screen_allocation; + EGLDisplay dpy; + EGLContext ctx; cairo_device_t *device; int fd; }; @@ -60,17 +68,21 @@ struct window { int drag_x, drag_y; int state; int fullscreen; + int decoration; struct wl_input_device *grab_device; struct wl_input_device *keyboard_device; uint32_t name; uint32_t modifiers; + EGLImageKHR *image; cairo_surface_t *cairo_surface, *pending_surface; int new_surface; window_resize_handler_t resize_handler; window_key_handler_t key_handler; window_keyboard_focus_handler_t keyboard_focus_handler; + window_frame_handler_t frame_handler; + void *user_data; }; @@ -88,10 +100,65 @@ rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius) cairo_close_path(cr); } +static const cairo_user_data_key_t surface_data_key; +struct surface_data { + EGLImageKHR image; + GLuint texture; + EGLDisplay dpy; +}; + +static void +surface_data_destroy(void *p) +{ + struct surface_data *data = p; + + glDeleteTextures(1, &data->texture); + eglDestroyImageKHR(data->dpy, data->image); +} + +cairo_surface_t * +window_create_surface(struct window *window, + struct rectangle *rectangle) +{ + struct surface_data *data; + EGLDisplay dpy = window->display->dpy; + cairo_surface_t *surface; + + EGLint image_attribs[] = { + EGL_WIDTH, 0, + EGL_HEIGHT, 0, + EGL_IMAGE_FORMAT_MESA, EGL_IMAGE_FORMAT_ARGB8888_MESA, + EGL_IMAGE_USE_MESA, EGL_IMAGE_USE_SCANOUT_MESA, + EGL_NONE + }; + + data = malloc(sizeof *data); + image_attribs[1] = rectangle->width; + image_attribs[3] = rectangle->height; + data->image = eglCreateDRMImageMESA(dpy, image_attribs); + glGenTextures(1, &data->texture); + data->dpy = dpy; + glBindTexture(GL_TEXTURE_2D, data->texture); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data->image); + + surface = cairo_gl_surface_create_for_texture(window->display->device, + CAIRO_CONTENT_COLOR_ALPHA, + data->texture, + rectangle->width, + rectangle->height); + + cairo_surface_set_user_data (surface, &surface_data_key, + data, surface_data_destroy); + + return surface; +} + static void window_attach_surface(struct window *window) { struct wl_visual *visual; + struct surface_data *data; + EGLint name, stride; if (window->pending_surface != NULL) return; @@ -99,12 +166,15 @@ window_attach_surface(struct window *window) window->pending_surface = cairo_surface_reference(window->cairo_surface); + data = cairo_surface_get_user_data (window->cairo_surface, &surface_data_key); + eglExportDRMImageMESA(window->display->dpy, data->image, &name, NULL, &stride); + visual = wl_display_get_premultiplied_argb_visual(window->display->display); wl_surface_attach(window->surface, - cairo_drm_surface_get_name(window->cairo_surface), + name, window->allocation.width, window->allocation.height, - cairo_drm_surface_get_stride(window->cairo_surface), + stride, visual); wl_surface_map(window->surface, @@ -136,10 +206,7 @@ window_draw_decorations(struct window *window) int shadow_dx = 4, shadow_dy = 4; window->cairo_surface = - cairo_drm_surface_create(window->display->device, - CAIRO_CONTENT_COLOR_ALPHA, - window->allocation.width, - window->allocation.height); + window_create_surface(window, &window->allocation); outline = cairo_pattern_create_rgb(0.1, 0.1, 0.1); bright = cairo_pattern_create_rgb(0.8, 0.8, 0.8); @@ -228,10 +295,7 @@ static void window_draw_fullscreen(struct window *window) { window->cairo_surface = - cairo_drm_surface_create(window->display->device, - CAIRO_CONTENT_COLOR_ALPHA, - window->allocation.width, - window->allocation.height); + window_create_surface(window, &window->allocation); } void @@ -240,7 +304,7 @@ window_draw(struct window *window) if (window->cairo_surface != NULL) cairo_surface_destroy(window->cairo_surface); - if (window->fullscreen) + if (window->fullscreen || !window->decoration) window_draw_fullscreen(window); else window_draw_decorations(window); @@ -248,6 +312,12 @@ window_draw(struct window *window) window->new_surface = 1; } +cairo_surface_t * +window_get_surface(struct window *window) +{ + return window->cairo_surface; +} + static void window_handle_acknowledge(void *data, struct wl_compositor *compositor, @@ -273,6 +343,10 @@ window_handle_frame(void *data, struct wl_compositor *compositor, uint32_t frame, uint32_t timestamp) { + struct window *window = data; + + if (window->frame_handler) + (*window->frame_handler)(window, frame, timestamp, window->user_data); } static const struct wl_compositor_listener compositor_listener = { @@ -554,7 +628,7 @@ void window_get_child_rectangle(struct window *window, struct rectangle *rectangle) { - if (window->fullscreen) { + if (window->fullscreen && !window->decoration) { *rectangle = window->allocation; } else { rectangle->x = window->margin + 10; @@ -574,38 +648,11 @@ window_set_child_size(struct window *window, } } -cairo_surface_t * -window_create_surface(struct window *window, - struct rectangle *rectangle) -{ - return cairo_drm_surface_create(window->display->device, - CAIRO_CONTENT_COLOR_ALPHA, - rectangle->width, - rectangle->height); -} - void -window_copy(struct window *window, - struct rectangle *rectangle, - uint32_t name, uint32_t stride) +window_copy_image(struct window *window, + struct rectangle *rectangle, EGLImageKHR image) { - cairo_surface_t *surface; - cairo_t *cr; - - surface = cairo_drm_surface_create_for_name (window->display->device, - name, CAIRO_FORMAT_ARGB32, - rectangle->width, rectangle->height, - stride); - - cr = cairo_create (window->cairo_surface); - - cairo_set_source_surface (cr, - surface, - rectangle->x, rectangle->y); - - cairo_paint (cr); - cairo_destroy (cr); - cairo_surface_destroy (surface); + /* set image as read buffer, copy pixels or something... */ } void @@ -637,6 +684,12 @@ window_set_fullscreen(struct window *window, int fullscreen) } } +void +window_set_decoration(struct window *window, int decoration) +{ + window->decoration = decoration; +} + void window_set_resize_handler(struct window *window, window_resize_handler_t handler, void *data) @@ -653,6 +706,14 @@ window_set_key_handler(struct window *window, window->user_data = data; } +void +window_set_frame_handler(struct window *window, + window_frame_handler_t handler, void *data) +{ + window->frame_handler = handler; + window->user_data = data; +} + void window_set_keyboard_focus_handler(struct window *window, window_keyboard_focus_handler_t handler, void *data) @@ -661,6 +722,19 @@ window_set_keyboard_focus_handler(struct window *window, window->user_data = data; } +void +window_move(struct window *window, int32_t x, int32_t y) +{ + window->allocation.x = x; + window->allocation.y = y; + + wl_surface_map(window->surface, + window->allocation.x - window->margin, + window->allocation.y - window->margin, + window->allocation.width, + window->allocation.height); +} + struct window * window_create(struct display *display, const char *title, int32_t x, int32_t y, int32_t width, int32_t height) @@ -728,14 +802,57 @@ display_handle_global(struct wl_display *display, struct display * display_create(struct wl_display *display, int fd) { + PFNEGLGETTYPEDDISPLAYMESA get_typed_display_mesa; struct display *d; + EGLint major, minor, count; + EGLConfig config; + + static const EGLint config_attribs[] = { + EGL_SURFACE_TYPE, 0, + EGL_NO_SURFACE_CAPABLE_MESA, EGL_OPENGL_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + }; d = malloc(sizeof *d); if (d == NULL) return NULL; + get_typed_display_mesa = + (PFNEGLGETTYPEDDISPLAYMESA) eglGetProcAddress("eglGetTypedDisplayMESA"); + if (get_typed_display_mesa == NULL) { + fprintf(stderr, "eglGetDisplayMESA() not found\n"); + return NULL; + } + + d->dpy = get_typed_display_mesa(EGL_DRM_DISPLAY_TYPE_MESA, + (void *) fd); + if (!eglInitialize(d->dpy, &major, &minor)) { + fprintf(stderr, "failed to initialize display\n"); + return NULL; + } + + if (!eglChooseConfig(d->dpy, config_attribs, &config, 1, &count) || + count == 0) { + fprintf(stderr, "eglChooseConfig() failed\n"); + return NULL; + } + + eglBindAPI(EGL_OPENGL_API); + + d->ctx = eglCreateContext(d->dpy, config, EGL_NO_CONTEXT, NULL); + if (d->ctx == NULL) { + fprintf(stderr, "failed to create context\n"); + return NULL; + } + + if (!eglMakeCurrent(d->dpy, NULL, NULL, d->ctx)) { + fprintf(stderr, "faile to make context current\n"); + return NULL; + } + d->display = display; - d->device = cairo_drm_device_get_for_fd(fd); + d->device = cairo_egl_device_create(d->dpy, d->ctx); if (d->device == NULL) { fprintf(stderr, "failed to get cairo drm device\n"); return NULL; diff --git a/clients/window.h b/clients/window.h index 78e7734f..95d619a2 100644 --- a/clients/window.h +++ b/clients/window.h @@ -68,14 +68,20 @@ void window_set_child_size(struct window *window, struct rectangle *rectangle); void -window_copy(struct window *window, - struct rectangle *rectangle, - uint32_t name, uint32_t stride); +window_copy_image(struct window *window, + struct rectangle *rectangle, + void *image); + +void +window_move(struct window *window, int32_t x, int32_t y); cairo_surface_t * window_create_surface(struct window *window, struct rectangle *rectangle); +cairo_surface_t * +window_get_surface(struct window *window); + void window_copy_surface(struct window *window, struct rectangle *rectangle, @@ -84,6 +90,9 @@ window_copy_surface(struct window *window, void window_set_fullscreen(struct window *window, int fullscreen); +void +window_set_decoration(struct window *window, int decoration); + void window_set_resize_handler(struct window *window, window_resize_handler_t handler, void *data); @@ -101,4 +110,8 @@ void window_set_keyboard_focus_handler(struct window *window, window_keyboard_focus_handler_t handler, void *data); + +void +window_set_frame_handler(struct window *window, + window_frame_handler_t handler, void *data); #endif