2 * Copyright © 2013 Intel Corporation
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
33 #include <sys/epoll.h>
34 #include <sys/socket.h>
38 #include <EGL/eglext.h>
39 #include <GLES2/gl2.h>
40 #include <GLES2/gl2ext.h>
44 #include <wayland-client.h>
45 #define WL_HIDE_DEPRECATED
46 #include <wayland-server.h>
50 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
52 #ifndef EGL_WL_create_wayland_buffer_from_image
53 #define EGL_WL_create_wayland_buffer_from_image 1
55 #ifdef EGL_EGLEXT_PROTOTYPES
56 EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
58 typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
62 static int option_blit;
65 struct display *display;
66 struct window *window;
67 struct widget *widget;
68 struct wl_display *child_display;
69 struct task child_task;
71 EGLDisplay egl_display;
72 struct program *texture_program;
74 struct wl_list surface_list;
76 const struct nested_renderer *renderer;
79 struct nested_region {
80 struct wl_resource *resource;
81 pixman_region32_t region;
84 struct nested_buffer_reference {
85 struct nested_buffer *buffer;
86 struct wl_listener destroy_listener;
89 struct nested_buffer {
90 struct wl_resource *resource;
91 struct wl_signal destroy_signal;
92 struct wl_listener destroy_listener;
95 /* A buffer in the parent compositor representing the same
96 * data. This is created on-demand when the subsurface
98 struct wl_buffer *parent_buffer;
99 /* This reference is used to mark when the parent buffer has
100 * been attached to the subsurface. It will be unrefenced when
101 * we receive a buffer release event. That way we won't inform
102 * the client that the buffer is free until the parent
103 * compositor is also finished with it */
104 struct nested_buffer_reference parent_ref;
107 struct nested_surface {
108 struct wl_resource *resource;
109 struct nested *nested;
113 struct wl_list frame_callback_list;
116 /* wl_surface.attach */
118 struct nested_buffer *buffer;
119 struct wl_listener buffer_destroy_listener;
121 /* wl_surface.frame */
122 struct wl_list frame_callback_list;
124 /* wl_surface.damage */
125 pixman_region32_t damage;
131 /* Data used for the blit renderer */
132 struct nested_blit_surface {
133 struct nested_buffer_reference buffer_ref;
135 cairo_surface_t *cairo_surface;
138 /* Data used for the subsurface renderer */
139 struct nested_ss_surface {
140 struct widget *widget;
141 struct wl_surface *surface;
142 struct wl_subsurface *subsurface;
143 struct wl_callback *frame_callback;
146 struct nested_frame_callback {
147 struct wl_resource *resource;
151 struct nested_renderer {
152 void (* surface_init)(struct nested_surface *surface);
153 void (* surface_fini)(struct nested_surface *surface);
154 void (* render_clients)(struct nested *nested, cairo_t *cr);
155 void (* surface_attach)(struct nested_surface *surface,
156 struct nested_buffer *buffer);
159 static const struct weston_option nested_options[] = {
160 { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
163 static const struct nested_renderer nested_blit_renderer;
164 static const struct nested_renderer nested_ss_renderer;
166 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
167 static PFNEGLCREATEIMAGEKHRPROC create_image;
168 static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
169 static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
170 static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
171 static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
172 static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
175 nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
177 struct nested_buffer *buffer =
178 container_of(listener, struct nested_buffer, destroy_listener);
180 wl_signal_emit(&buffer->destroy_signal, buffer);
182 if (buffer->parent_buffer)
183 wl_buffer_destroy(buffer->parent_buffer);
188 static struct nested_buffer *
189 nested_buffer_from_resource(struct wl_resource *resource)
191 struct nested_buffer *buffer;
192 struct wl_listener *listener;
195 wl_resource_get_destroy_listener(resource,
196 nested_buffer_destroy_handler);
199 return container_of(listener, struct nested_buffer,
202 buffer = zalloc(sizeof *buffer);
206 buffer->resource = resource;
207 wl_signal_init(&buffer->destroy_signal);
208 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
209 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
215 nested_buffer_reference_handle_destroy(struct wl_listener *listener,
218 struct nested_buffer_reference *ref =
219 container_of(listener, struct nested_buffer_reference,
222 assert((struct nested_buffer *)data == ref->buffer);
227 nested_buffer_reference(struct nested_buffer_reference *ref,
228 struct nested_buffer *buffer)
230 if (buffer == ref->buffer)
234 ref->buffer->busy_count--;
235 if (ref->buffer->busy_count == 0) {
236 assert(wl_resource_get_client(ref->buffer->resource));
237 wl_resource_queue_event(ref->buffer->resource,
240 wl_list_remove(&ref->destroy_listener.link);
244 buffer->busy_count++;
245 wl_signal_add(&buffer->destroy_signal,
246 &ref->destroy_listener);
248 ref->destroy_listener.notify =
249 nested_buffer_reference_handle_destroy;
252 ref->buffer = buffer;
256 flush_surface_frame_callback_list(struct nested_surface *surface,
259 struct nested_frame_callback *nc, *next;
261 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
262 wl_callback_send_done(nc->resource, time);
263 wl_resource_destroy(nc->resource);
265 wl_list_init(&surface->frame_callback_list);
267 /* FIXME: toytoolkit need a pre-block handler where we can
269 wl_display_flush_clients(surface->nested->child_display);
273 redraw_handler(struct widget *widget, void *data)
275 struct nested *nested = data;
276 cairo_surface_t *surface;
278 struct rectangle allocation;
280 widget_get_allocation(nested->widget, &allocation);
282 surface = window_get_surface(nested->window);
284 cr = cairo_create(surface);
285 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
291 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
294 nested->renderer->render_clients(nested, cr);
298 cairo_surface_destroy(surface);
302 keyboard_focus_handler(struct window *window,
303 struct input *device, void *data)
305 struct nested *nested = data;
307 window_schedule_redraw(nested->window);
311 handle_child_data(struct task *task, uint32_t events)
313 struct nested *nested = container_of(task, struct nested, child_task);
314 struct wl_event_loop *loop;
316 loop = wl_display_get_event_loop(nested->child_display);
318 wl_event_loop_dispatch(loop, -1);
319 wl_display_flush_clients(nested->child_display);
322 struct nested_client {
323 struct wl_client *client;
327 static struct nested_client *
328 launch_client(struct nested *nested, const char *path)
332 struct nested_client *client;
334 client = malloc(sizeof *client);
338 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
339 fprintf(stderr, "launch_client: "
340 "socketpair failed while launching '%s': %m\n",
351 fprintf(stderr, "launch_client: "
352 "fork failed while launching '%s': %m\n", path);
360 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
361 * get a non-CLOEXEC fd to pass through exec. */
362 clientfd = dup(sv[1]);
363 if (clientfd == -1) {
364 fprintf(stderr, "compositor: dup failed: %m\n");
368 snprintf(s, sizeof s, "%d", clientfd);
369 setenv("WAYLAND_SOCKET", s, 1);
371 execl(path, path, NULL);
373 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
380 client->client = wl_client_create(nested->child_display, sv[0]);
381 if (!client->client) {
384 fprintf(stderr, "launch_client: "
385 "wl_client_create failed while launching '%s'.\n",
396 destroy_surface(struct wl_resource *resource)
398 struct nested_surface *surface = wl_resource_get_user_data(resource);
399 struct nested *nested = surface->nested;
400 struct nested_frame_callback *cb, *next;
402 wl_list_for_each_safe(cb, next,
403 &surface->frame_callback_list, link)
404 wl_resource_destroy(cb->resource);
406 wl_list_for_each_safe(cb, next,
407 &surface->pending.frame_callback_list, link)
408 wl_resource_destroy(cb->resource);
410 pixman_region32_fini(&surface->pending.damage);
412 nested->renderer->surface_fini(surface);
414 wl_list_remove(&surface->link);
420 surface_destroy(struct wl_client *client, struct wl_resource *resource)
422 wl_resource_destroy(resource);
426 surface_attach(struct wl_client *client,
427 struct wl_resource *resource,
428 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
430 struct nested_surface *surface = wl_resource_get_user_data(resource);
431 struct nested *nested = surface->nested;
432 struct nested_buffer *buffer = NULL;
434 if (buffer_resource) {
437 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
438 EGL_TEXTURE_FORMAT, &format)) {
439 wl_resource_post_error(buffer_resource,
440 WL_DISPLAY_ERROR_INVALID_OBJECT,
441 "attaching non-egl wl_buffer");
446 case EGL_TEXTURE_RGB:
447 case EGL_TEXTURE_RGBA:
450 wl_resource_post_error(buffer_resource,
451 WL_DISPLAY_ERROR_INVALID_OBJECT,
456 buffer = nested_buffer_from_resource(buffer_resource);
457 if (buffer == NULL) {
458 wl_client_post_no_memory(client);
463 if (surface->pending.buffer)
464 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
466 surface->pending.buffer = buffer;
467 surface->pending.newly_attached = 1;
469 wl_signal_add(&buffer->destroy_signal,
470 &surface->pending.buffer_destroy_listener);
475 nested_surface_attach(struct nested_surface *surface,
476 struct nested_buffer *buffer)
478 struct nested *nested = surface->nested;
480 if (surface->image != EGL_NO_IMAGE_KHR)
481 destroy_image(nested->egl_display, surface->image);
483 surface->image = create_image(nested->egl_display, NULL,
484 EGL_WAYLAND_BUFFER_WL, buffer->resource,
486 if (surface->image == EGL_NO_IMAGE_KHR) {
487 fprintf(stderr, "failed to create img\n");
491 nested->renderer->surface_attach(surface, buffer);
495 surface_damage(struct wl_client *client,
496 struct wl_resource *resource,
497 int32_t x, int32_t y, int32_t width, int32_t height)
499 struct nested_surface *surface = wl_resource_get_user_data(resource);
501 pixman_region32_union_rect(&surface->pending.damage,
502 &surface->pending.damage,
503 x, y, width, height);
507 destroy_frame_callback(struct wl_resource *resource)
509 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
511 wl_list_remove(&callback->link);
516 surface_frame(struct wl_client *client,
517 struct wl_resource *resource, uint32_t id)
519 struct nested_frame_callback *callback;
520 struct nested_surface *surface = wl_resource_get_user_data(resource);
522 callback = malloc(sizeof *callback);
523 if (callback == NULL) {
524 wl_resource_post_no_memory(resource);
528 callback->resource = wl_resource_create(client,
529 &wl_callback_interface, 1, id);
530 wl_resource_set_implementation(callback->resource, NULL, callback,
531 destroy_frame_callback);
533 wl_list_insert(surface->pending.frame_callback_list.prev,
538 surface_set_opaque_region(struct wl_client *client,
539 struct wl_resource *resource,
540 struct wl_resource *region_resource)
542 fprintf(stderr, "surface_set_opaque_region\n");
546 surface_set_input_region(struct wl_client *client,
547 struct wl_resource *resource,
548 struct wl_resource *region_resource)
550 fprintf(stderr, "surface_set_input_region\n");
554 empty_region(pixman_region32_t *region)
556 pixman_region32_fini(region);
557 pixman_region32_init(region);
561 surface_commit(struct wl_client *client, struct wl_resource *resource)
563 struct nested_surface *surface = wl_resource_get_user_data(resource);
564 struct nested *nested = surface->nested;
566 /* wl_surface.attach */
567 if (surface->pending.newly_attached)
568 nested_surface_attach(surface, surface->pending.buffer);
570 if (surface->pending.buffer) {
571 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
572 surface->pending.buffer = NULL;
574 surface->pending.newly_attached = 0;
576 /* wl_surface.damage */
577 empty_region(&surface->pending.damage);
579 /* wl_surface.frame */
580 wl_list_insert_list(&surface->frame_callback_list,
581 &surface->pending.frame_callback_list);
582 wl_list_init(&surface->pending.frame_callback_list);
584 /* FIXME: For the subsurface renderer we don't need to
585 * actually redraw the window. However we do want to cause a
586 * commit because the subsurface is synchronized. Ideally we
587 * would just queue the commit */
588 window_schedule_redraw(nested->window);
592 surface_set_buffer_transform(struct wl_client *client,
593 struct wl_resource *resource, int transform)
595 fprintf(stderr, "surface_set_buffer_transform\n");
598 static const struct wl_surface_interface surface_interface = {
603 surface_set_opaque_region,
604 surface_set_input_region,
606 surface_set_buffer_transform
610 surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
612 struct nested_surface *surface =
613 container_of(listener, struct nested_surface,
614 pending.buffer_destroy_listener);
616 surface->pending.buffer = NULL;
620 compositor_create_surface(struct wl_client *client,
621 struct wl_resource *resource, uint32_t id)
623 struct nested *nested = wl_resource_get_user_data(resource);
624 struct nested_surface *surface;
626 surface = zalloc(sizeof *surface);
627 if (surface == NULL) {
628 wl_resource_post_no_memory(resource);
632 surface->nested = nested;
634 wl_list_init(&surface->frame_callback_list);
636 wl_list_init(&surface->pending.frame_callback_list);
637 surface->pending.buffer_destroy_listener.notify =
638 surface_handle_pending_buffer_destroy;
639 pixman_region32_init(&surface->pending.damage);
641 display_acquire_window_surface(nested->display,
642 nested->window, NULL);
644 nested->renderer->surface_init(surface);
646 display_release_window_surface(nested->display, nested->window);
649 wl_resource_create(client, &wl_surface_interface, 1, id);
651 wl_resource_set_implementation(surface->resource,
652 &surface_interface, surface,
655 wl_list_insert(nested->surface_list.prev, &surface->link);
659 destroy_region(struct wl_resource *resource)
661 struct nested_region *region = wl_resource_get_user_data(resource);
663 pixman_region32_fini(®ion->region);
668 region_destroy(struct wl_client *client, struct wl_resource *resource)
670 wl_resource_destroy(resource);
674 region_add(struct wl_client *client, struct wl_resource *resource,
675 int32_t x, int32_t y, int32_t width, int32_t height)
677 struct nested_region *region = wl_resource_get_user_data(resource);
679 pixman_region32_union_rect(®ion->region, ®ion->region,
680 x, y, width, height);
684 region_subtract(struct wl_client *client, struct wl_resource *resource,
685 int32_t x, int32_t y, int32_t width, int32_t height)
687 struct nested_region *region = wl_resource_get_user_data(resource);
688 pixman_region32_t rect;
690 pixman_region32_init_rect(&rect, x, y, width, height);
691 pixman_region32_subtract(®ion->region, ®ion->region, &rect);
692 pixman_region32_fini(&rect);
695 static const struct wl_region_interface region_interface = {
702 compositor_create_region(struct wl_client *client,
703 struct wl_resource *resource, uint32_t id)
705 struct nested_region *region;
707 region = malloc(sizeof *region);
708 if (region == NULL) {
709 wl_resource_post_no_memory(resource);
713 pixman_region32_init(®ion->region);
716 wl_resource_create(client, &wl_region_interface, 1, id);
717 wl_resource_set_implementation(region->resource, ®ion_interface,
718 region, destroy_region);
721 static const struct wl_compositor_interface compositor_interface = {
722 compositor_create_surface,
723 compositor_create_region
727 compositor_bind(struct wl_client *client,
728 void *data, uint32_t version, uint32_t id)
730 struct nested *nested = data;
731 struct wl_resource *resource;
733 resource = wl_resource_create(client, &wl_compositor_interface,
734 MIN(version, 3), id);
735 wl_resource_set_implementation(resource, &compositor_interface,
740 nested_init_compositor(struct nested *nested)
742 const char *extensions;
743 struct wl_event_loop *loop;
744 int use_ss_renderer = 0;
747 wl_list_init(&nested->surface_list);
748 nested->child_display = wl_display_create();
749 loop = wl_display_get_event_loop(nested->child_display);
750 fd = wl_event_loop_get_fd(loop);
751 nested->child_task.run = handle_child_data;
752 display_watch_fd(nested->display, fd,
753 EPOLLIN, &nested->child_task);
755 if (!wl_global_create(nested->child_display,
756 &wl_compositor_interface, 1,
757 nested, compositor_bind))
760 wl_display_init_shm(nested->child_display);
762 nested->egl_display = display_get_egl_display(nested->display);
763 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
764 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
765 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
769 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
770 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
771 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
772 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
773 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
774 image_target_texture_2d =
775 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
777 ret = bind_display(nested->egl_display, nested->child_display);
779 fprintf(stderr, "failed to bind wl_display\n");
783 if (display_has_subcompositor(nested->display)) {
784 const char *func = "eglCreateWaylandBufferFromImageWL";
785 const char *ext = "EGL_WL_create_wayland_buffer_from_image";
787 if (strstr(extensions, ext)) {
788 create_wayland_buffer_from_image =
789 (void *) eglGetProcAddress(func);
797 if (use_ss_renderer) {
798 printf("Using subsurfaces to render client surfaces\n");
799 nested->renderer = &nested_ss_renderer;
801 printf("Using local compositing with blits to "
802 "render client surfaces\n");
803 nested->renderer = &nested_blit_renderer;
809 static struct nested *
810 nested_create(struct display *display)
812 struct nested *nested;
814 nested = zalloc(sizeof *nested);
818 nested->window = window_create(display);
819 nested->widget = window_frame_create(nested->window, nested);
820 window_set_title(nested->window, "Wayland Nested");
821 nested->display = display;
823 window_set_user_data(nested->window, nested);
824 widget_set_redraw_handler(nested->widget, redraw_handler);
825 window_set_keyboard_focus_handler(nested->window,
826 keyboard_focus_handler);
828 nested_init_compositor(nested);
830 widget_schedule_resize(nested->widget, 400, 400);
836 nested_destroy(struct nested *nested)
838 widget_destroy(nested->widget);
839 window_destroy(nested->window);
843 /*** blit renderer ***/
846 blit_surface_init(struct nested_surface *surface)
848 struct nested_blit_surface *blit_surface =
849 xzalloc(sizeof *blit_surface);
851 glGenTextures(1, &blit_surface->texture);
852 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
853 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
854 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
855 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
856 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
858 surface->renderer_data = blit_surface;
862 blit_surface_fini(struct nested_surface *surface)
864 struct nested_blit_surface *blit_surface = surface->renderer_data;
866 nested_buffer_reference(&blit_surface->buffer_ref, NULL);
868 glDeleteTextures(1, &blit_surface->texture);
874 blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
876 struct nested *nested = data;
877 struct nested_surface *surface;
879 wl_list_for_each(surface, &nested->surface_list, link)
880 flush_surface_frame_callback_list(surface, time);
883 wl_callback_destroy(callback);
886 static const struct wl_callback_listener blit_frame_listener = {
891 blit_render_clients(struct nested *nested,
894 struct nested_surface *s;
895 struct rectangle allocation;
896 struct wl_callback *callback;
898 widget_get_allocation(nested->widget, &allocation);
900 wl_list_for_each(s, &nested->surface_list, link) {
901 struct nested_blit_surface *blit_surface = s->renderer_data;
903 display_acquire_window_surface(nested->display,
904 nested->window, NULL);
906 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
907 image_target_texture_2d(GL_TEXTURE_2D, s->image);
909 display_release_window_surface(nested->display,
912 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
913 cairo_set_source_surface(cr, blit_surface->cairo_surface,
916 cairo_rectangle(cr, allocation.x + 10,
918 allocation.width - 10,
919 allocation.height - 10);
924 callback = wl_surface_frame(window_get_wl_surface(nested->window));
925 wl_callback_add_listener(callback, &blit_frame_listener, nested);
929 blit_surface_attach(struct nested_surface *surface,
930 struct nested_buffer *buffer)
932 struct nested *nested = surface->nested;
933 struct nested_blit_surface *blit_surface = surface->renderer_data;
934 EGLint width, height;
935 cairo_device_t *device;
937 nested_buffer_reference(&blit_surface->buffer_ref, buffer);
939 if (blit_surface->cairo_surface)
940 cairo_surface_destroy(blit_surface->cairo_surface);
942 query_buffer(nested->egl_display, (void *) buffer->resource,
944 query_buffer(nested->egl_display, (void *) buffer->resource,
945 EGL_HEIGHT, &height);
947 device = display_get_cairo_device(nested->display);
948 blit_surface->cairo_surface =
949 cairo_gl_surface_create_for_texture(device,
950 CAIRO_CONTENT_COLOR_ALPHA,
951 blit_surface->texture,
955 static const struct nested_renderer
956 nested_blit_renderer = {
957 .surface_init = blit_surface_init,
958 .surface_fini = blit_surface_fini,
959 .render_clients = blit_render_clients,
960 .surface_attach = blit_surface_attach
963 /*** subsurface renderer ***/
966 ss_surface_init(struct nested_surface *surface)
968 struct nested *nested = surface->nested;
969 struct wl_compositor *compositor =
970 display_get_compositor(nested->display);
971 struct nested_ss_surface *ss_surface =
972 xzalloc(sizeof *ss_surface);
973 struct rectangle allocation;
974 struct wl_region *region;
977 window_add_subsurface(nested->window,
979 SUBSURFACE_SYNCHRONIZED);
981 widget_set_use_cairo(ss_surface->widget, 0);
983 ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
984 ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
986 /* The toy toolkit gets confused about the pointer position
987 * when it gets motion events for a subsurface so we'll just
988 * disable input on it */
989 region = wl_compositor_create_region(compositor);
990 wl_surface_set_input_region(ss_surface->surface, region);
991 wl_region_destroy(region);
993 widget_get_allocation(nested->widget, &allocation);
994 wl_subsurface_set_position(ss_surface->subsurface,
998 surface->renderer_data = ss_surface;
1002 ss_surface_fini(struct nested_surface *surface)
1004 struct nested_ss_surface *ss_surface = surface->renderer_data;
1006 widget_destroy(ss_surface->widget);
1008 if (ss_surface->frame_callback)
1009 wl_callback_destroy(ss_surface->frame_callback);
1015 ss_render_clients(struct nested *nested,
1018 /* The clients are composited by the parent compositor so we
1019 * don't need to do anything here */
1023 ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
1025 struct nested_buffer *buffer = data;
1027 nested_buffer_reference(&buffer->parent_ref, NULL);
1030 static struct wl_buffer_listener ss_buffer_listener = {
1035 ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
1037 struct nested_surface *surface = data;
1038 struct nested_ss_surface *ss_surface = surface->renderer_data;
1040 flush_surface_frame_callback_list(surface, time);
1043 wl_callback_destroy(callback);
1045 ss_surface->frame_callback = NULL;
1048 static const struct wl_callback_listener ss_frame_listener = {
1053 ss_surface_attach(struct nested_surface *surface,
1054 struct nested_buffer *buffer)
1056 struct nested *nested = surface->nested;
1057 struct nested_ss_surface *ss_surface = surface->renderer_data;
1058 struct wl_buffer *parent_buffer;
1059 const pixman_box32_t *rects;
1063 /* Create a representation of the buffer in the parent
1064 * compositor if we haven't already */
1065 if (buffer->parent_buffer == NULL) {
1066 EGLDisplay *edpy = nested->egl_display;
1067 EGLImageKHR image = surface->image;
1069 buffer->parent_buffer =
1070 create_wayland_buffer_from_image(edpy, image);
1072 wl_buffer_add_listener(buffer->parent_buffer,
1073 &ss_buffer_listener,
1077 parent_buffer = buffer->parent_buffer;
1079 /* We'll take a reference to the buffer while the parent
1080 * compositor is using it so that we won't report the release
1081 * event until the parent has also finished with it */
1082 nested_buffer_reference(&buffer->parent_ref, buffer);
1084 parent_buffer = NULL;
1087 wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
1089 rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
1091 for (i = 0; i < n_rects; i++) {
1092 const pixman_box32_t *rect = rects + i;
1093 wl_surface_damage(ss_surface->surface,
1096 rect->x2 - rect->x1,
1097 rect->y2 - rect->y1);
1100 if (ss_surface->frame_callback)
1101 wl_callback_destroy(ss_surface->frame_callback);
1103 ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
1104 wl_callback_add_listener(ss_surface->frame_callback,
1108 wl_surface_commit(ss_surface->surface);
1111 static const struct nested_renderer
1112 nested_ss_renderer = {
1113 .surface_init = ss_surface_init,
1114 .surface_fini = ss_surface_fini,
1115 .render_clients = ss_render_clients,
1116 .surface_attach = ss_surface_attach
1120 main(int argc, char *argv[])
1122 struct display *display;
1123 struct nested *nested;
1125 parse_options(nested_options,
1126 ARRAY_LENGTH(nested_options), &argc, argv);
1128 display = display_create(&argc, argv);
1129 if (display == NULL) {
1130 fprintf(stderr, "failed to create display: %m\n");
1134 nested = nested_create(display);
1136 launch_client(nested, "weston-nested-client");
1138 display_run(display);
1140 nested_destroy(nested);
1141 display_destroy(display);