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
31 #include <sys/epoll.h>
32 #include <sys/socket.h>
36 #include <EGL/eglext.h>
37 #include <GLES2/gl2.h>
38 #include <GLES2/gl2ext.h>
42 #include <wayland-client.h>
43 #define WL_HIDE_DEPRECATED
44 #include <wayland-server.h>
48 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
50 #ifndef EGL_WL_create_wayland_buffer_from_image
51 #define EGL_WL_create_wayland_buffer_from_image 1
53 #ifdef EGL_EGLEXT_PROTOTYPES
54 EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
56 typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
60 static int option_blit;
63 struct display *display;
64 struct window *window;
65 struct widget *widget;
66 struct wl_display *child_display;
67 struct task child_task;
69 EGLDisplay egl_display;
70 struct program *texture_program;
72 struct wl_list surface_list;
74 const struct nested_renderer *renderer;
77 struct nested_region {
78 struct wl_resource *resource;
79 pixman_region32_t region;
82 struct nested_buffer_reference {
83 struct nested_buffer *buffer;
84 struct wl_listener destroy_listener;
87 struct nested_buffer {
88 struct wl_resource *resource;
89 struct wl_signal destroy_signal;
90 struct wl_listener destroy_listener;
93 /* A buffer in the parent compositor representing the same
94 * data. This is created on-demand when the subsurface
96 struct wl_buffer *parent_buffer;
97 /* This reference is used to mark when the parent buffer has
98 * been attached to the subsurface. It will be unrefenced when
99 * we receive a buffer release event. That way we won't inform
100 * the client that the buffer is free until the parent
101 * compositor is also finished with it */
102 struct nested_buffer_reference parent_ref;
105 struct nested_surface {
106 struct wl_resource *resource;
107 struct nested *nested;
111 struct wl_list frame_callback_list;
114 /* wl_surface.attach */
116 struct nested_buffer *buffer;
117 struct wl_listener buffer_destroy_listener;
119 /* wl_surface.frame */
120 struct wl_list frame_callback_list;
122 /* wl_surface.damage */
123 pixman_region32_t damage;
129 /* Data used for the blit renderer */
130 struct nested_blit_surface {
131 struct nested_buffer_reference buffer_ref;
133 cairo_surface_t *cairo_surface;
136 /* Data used for the subsurface renderer */
137 struct nested_ss_surface {
138 struct widget *widget;
139 struct wl_surface *surface;
140 struct wl_subsurface *subsurface;
141 struct wl_callback *frame_callback;
144 struct nested_frame_callback {
145 struct wl_resource *resource;
149 struct nested_renderer {
150 void (* surface_init)(struct nested_surface *surface);
151 void (* surface_fini)(struct nested_surface *surface);
152 void (* render_clients)(struct nested *nested, cairo_t *cr);
153 void (* surface_attach)(struct nested_surface *surface,
154 struct nested_buffer *buffer);
157 static const struct weston_option nested_options[] = {
158 { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
161 static const struct nested_renderer nested_blit_renderer;
162 static const struct nested_renderer nested_ss_renderer;
164 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
165 static PFNEGLCREATEIMAGEKHRPROC create_image;
166 static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
167 static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
168 static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
169 static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
170 static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
173 nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
175 struct nested_buffer *buffer =
176 container_of(listener, struct nested_buffer, destroy_listener);
178 wl_signal_emit(&buffer->destroy_signal, buffer);
180 if (buffer->parent_buffer)
181 wl_buffer_destroy(buffer->parent_buffer);
186 static struct nested_buffer *
187 nested_buffer_from_resource(struct wl_resource *resource)
189 struct nested_buffer *buffer;
190 struct wl_listener *listener;
193 wl_resource_get_destroy_listener(resource,
194 nested_buffer_destroy_handler);
197 return container_of(listener, struct nested_buffer,
200 buffer = zalloc(sizeof *buffer);
204 buffer->resource = resource;
205 wl_signal_init(&buffer->destroy_signal);
206 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
207 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
213 nested_buffer_reference_handle_destroy(struct wl_listener *listener,
216 struct nested_buffer_reference *ref =
217 container_of(listener, struct nested_buffer_reference,
220 assert((struct nested_buffer *)data == ref->buffer);
225 nested_buffer_reference(struct nested_buffer_reference *ref,
226 struct nested_buffer *buffer)
228 if (buffer == ref->buffer)
232 ref->buffer->busy_count--;
233 if (ref->buffer->busy_count == 0) {
234 assert(wl_resource_get_client(ref->buffer->resource));
235 wl_resource_queue_event(ref->buffer->resource,
238 wl_list_remove(&ref->destroy_listener.link);
242 buffer->busy_count++;
243 wl_signal_add(&buffer->destroy_signal,
244 &ref->destroy_listener);
246 ref->destroy_listener.notify =
247 nested_buffer_reference_handle_destroy;
250 ref->buffer = buffer;
254 flush_surface_frame_callback_list(struct nested_surface *surface,
257 struct nested_frame_callback *nc, *next;
259 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
260 wl_callback_send_done(nc->resource, time);
261 wl_resource_destroy(nc->resource);
263 wl_list_init(&surface->frame_callback_list);
265 /* FIXME: toytoolkit need a pre-block handler where we can
267 wl_display_flush_clients(surface->nested->child_display);
271 redraw_handler(struct widget *widget, void *data)
273 struct nested *nested = data;
274 cairo_surface_t *surface;
276 struct rectangle allocation;
278 widget_get_allocation(nested->widget, &allocation);
280 surface = window_get_surface(nested->window);
282 cr = cairo_create(surface);
283 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
289 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
292 nested->renderer->render_clients(nested, cr);
296 cairo_surface_destroy(surface);
300 keyboard_focus_handler(struct window *window,
301 struct input *device, void *data)
303 struct nested *nested = data;
305 window_schedule_redraw(nested->window);
309 handle_child_data(struct task *task, uint32_t events)
311 struct nested *nested = container_of(task, struct nested, child_task);
312 struct wl_event_loop *loop;
314 loop = wl_display_get_event_loop(nested->child_display);
316 wl_event_loop_dispatch(loop, -1);
317 wl_display_flush_clients(nested->child_display);
320 struct nested_client {
321 struct wl_client *client;
325 static struct nested_client *
326 launch_client(struct nested *nested, const char *path)
330 struct nested_client *client;
332 client = malloc(sizeof *client);
336 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
337 fprintf(stderr, "launch_client: "
338 "socketpair failed while launching '%s': %m\n",
349 fprintf(stderr, "launch_client: "
350 "fork failed while launching '%s': %m\n", path);
358 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
359 * get a non-CLOEXEC fd to pass through exec. */
360 clientfd = dup(sv[1]);
361 if (clientfd == -1) {
362 fprintf(stderr, "compositor: dup failed: %m\n");
366 snprintf(s, sizeof s, "%d", clientfd);
367 setenv("WAYLAND_SOCKET", s, 1);
369 execl(path, path, NULL);
371 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
378 client->client = wl_client_create(nested->child_display, sv[0]);
379 if (!client->client) {
382 fprintf(stderr, "launch_client: "
383 "wl_client_create failed while launching '%s'.\n",
394 destroy_surface(struct wl_resource *resource)
396 struct nested_surface *surface = wl_resource_get_user_data(resource);
397 struct nested *nested = surface->nested;
398 struct nested_frame_callback *cb, *next;
400 wl_list_for_each_safe(cb, next,
401 &surface->frame_callback_list, link)
402 wl_resource_destroy(cb->resource);
404 wl_list_for_each_safe(cb, next,
405 &surface->pending.frame_callback_list, link)
406 wl_resource_destroy(cb->resource);
408 pixman_region32_fini(&surface->pending.damage);
410 nested->renderer->surface_fini(surface);
412 wl_list_remove(&surface->link);
418 surface_destroy(struct wl_client *client, struct wl_resource *resource)
420 wl_resource_destroy(resource);
424 surface_attach(struct wl_client *client,
425 struct wl_resource *resource,
426 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
428 struct nested_surface *surface = wl_resource_get_user_data(resource);
429 struct nested *nested = surface->nested;
430 struct nested_buffer *buffer = NULL;
432 if (buffer_resource) {
435 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
436 EGL_TEXTURE_FORMAT, &format)) {
437 wl_resource_post_error(buffer_resource,
438 WL_DISPLAY_ERROR_INVALID_OBJECT,
439 "attaching non-egl wl_buffer");
444 case EGL_TEXTURE_RGB:
445 case EGL_TEXTURE_RGBA:
448 wl_resource_post_error(buffer_resource,
449 WL_DISPLAY_ERROR_INVALID_OBJECT,
454 buffer = nested_buffer_from_resource(buffer_resource);
455 if (buffer == NULL) {
456 wl_client_post_no_memory(client);
461 if (surface->pending.buffer)
462 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
464 surface->pending.buffer = buffer;
465 surface->pending.newly_attached = 1;
467 wl_signal_add(&buffer->destroy_signal,
468 &surface->pending.buffer_destroy_listener);
473 nested_surface_attach(struct nested_surface *surface,
474 struct nested_buffer *buffer)
476 struct nested *nested = surface->nested;
478 if (surface->image != EGL_NO_IMAGE_KHR)
479 destroy_image(nested->egl_display, surface->image);
481 surface->image = create_image(nested->egl_display, NULL,
482 EGL_WAYLAND_BUFFER_WL, buffer->resource,
484 if (surface->image == EGL_NO_IMAGE_KHR) {
485 fprintf(stderr, "failed to create img\n");
489 nested->renderer->surface_attach(surface, buffer);
493 surface_damage(struct wl_client *client,
494 struct wl_resource *resource,
495 int32_t x, int32_t y, int32_t width, int32_t height)
497 struct nested_surface *surface = wl_resource_get_user_data(resource);
499 pixman_region32_union_rect(&surface->pending.damage,
500 &surface->pending.damage,
501 x, y, width, height);
505 destroy_frame_callback(struct wl_resource *resource)
507 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
509 wl_list_remove(&callback->link);
514 surface_frame(struct wl_client *client,
515 struct wl_resource *resource, uint32_t id)
517 struct nested_frame_callback *callback;
518 struct nested_surface *surface = wl_resource_get_user_data(resource);
520 callback = malloc(sizeof *callback);
521 if (callback == NULL) {
522 wl_resource_post_no_memory(resource);
526 callback->resource = wl_resource_create(client,
527 &wl_callback_interface, 1, id);
528 wl_resource_set_implementation(callback->resource, NULL, callback,
529 destroy_frame_callback);
531 wl_list_insert(surface->pending.frame_callback_list.prev,
536 surface_set_opaque_region(struct wl_client *client,
537 struct wl_resource *resource,
538 struct wl_resource *region_resource)
540 fprintf(stderr, "surface_set_opaque_region\n");
544 surface_set_input_region(struct wl_client *client,
545 struct wl_resource *resource,
546 struct wl_resource *region_resource)
548 fprintf(stderr, "surface_set_input_region\n");
552 empty_region(pixman_region32_t *region)
554 pixman_region32_fini(region);
555 pixman_region32_init(region);
559 surface_commit(struct wl_client *client, struct wl_resource *resource)
561 struct nested_surface *surface = wl_resource_get_user_data(resource);
562 struct nested *nested = surface->nested;
564 /* wl_surface.attach */
565 if (surface->pending.newly_attached)
566 nested_surface_attach(surface, surface->pending.buffer);
568 if (surface->pending.buffer) {
569 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
570 surface->pending.buffer = NULL;
572 surface->pending.newly_attached = 0;
574 /* wl_surface.damage */
575 empty_region(&surface->pending.damage);
577 /* wl_surface.frame */
578 wl_list_insert_list(&surface->frame_callback_list,
579 &surface->pending.frame_callback_list);
580 wl_list_init(&surface->pending.frame_callback_list);
582 /* FIXME: For the subsurface renderer we don't need to
583 * actually redraw the window. However we do want to cause a
584 * commit because the subsurface is synchronized. Ideally we
585 * would just queue the commit */
586 window_schedule_redraw(nested->window);
590 surface_set_buffer_transform(struct wl_client *client,
591 struct wl_resource *resource, int transform)
593 fprintf(stderr, "surface_set_buffer_transform\n");
596 static const struct wl_surface_interface surface_interface = {
601 surface_set_opaque_region,
602 surface_set_input_region,
604 surface_set_buffer_transform
608 surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
610 struct nested_surface *surface =
611 container_of(listener, struct nested_surface,
612 pending.buffer_destroy_listener);
614 surface->pending.buffer = NULL;
618 compositor_create_surface(struct wl_client *client,
619 struct wl_resource *resource, uint32_t id)
621 struct nested *nested = wl_resource_get_user_data(resource);
622 struct nested_surface *surface;
624 surface = zalloc(sizeof *surface);
625 if (surface == NULL) {
626 wl_resource_post_no_memory(resource);
630 surface->nested = nested;
632 wl_list_init(&surface->frame_callback_list);
634 wl_list_init(&surface->pending.frame_callback_list);
635 surface->pending.buffer_destroy_listener.notify =
636 surface_handle_pending_buffer_destroy;
637 pixman_region32_init(&surface->pending.damage);
639 display_acquire_window_surface(nested->display,
640 nested->window, NULL);
642 nested->renderer->surface_init(surface);
644 display_release_window_surface(nested->display, nested->window);
647 wl_resource_create(client, &wl_surface_interface, 1, id);
649 wl_resource_set_implementation(surface->resource,
650 &surface_interface, surface,
653 wl_list_insert(nested->surface_list.prev, &surface->link);
657 destroy_region(struct wl_resource *resource)
659 struct nested_region *region = wl_resource_get_user_data(resource);
661 pixman_region32_fini(®ion->region);
666 region_destroy(struct wl_client *client, struct wl_resource *resource)
668 wl_resource_destroy(resource);
672 region_add(struct wl_client *client, struct wl_resource *resource,
673 int32_t x, int32_t y, int32_t width, int32_t height)
675 struct nested_region *region = wl_resource_get_user_data(resource);
677 pixman_region32_union_rect(®ion->region, ®ion->region,
678 x, y, width, height);
682 region_subtract(struct wl_client *client, struct wl_resource *resource,
683 int32_t x, int32_t y, int32_t width, int32_t height)
685 struct nested_region *region = wl_resource_get_user_data(resource);
686 pixman_region32_t rect;
688 pixman_region32_init_rect(&rect, x, y, width, height);
689 pixman_region32_subtract(®ion->region, ®ion->region, &rect);
690 pixman_region32_fini(&rect);
693 static const struct wl_region_interface region_interface = {
700 compositor_create_region(struct wl_client *client,
701 struct wl_resource *resource, uint32_t id)
703 struct nested_region *region;
705 region = malloc(sizeof *region);
706 if (region == NULL) {
707 wl_resource_post_no_memory(resource);
711 pixman_region32_init(®ion->region);
714 wl_resource_create(client, &wl_region_interface, 1, id);
715 wl_resource_set_implementation(region->resource, ®ion_interface,
716 region, destroy_region);
719 static const struct wl_compositor_interface compositor_interface = {
720 compositor_create_surface,
721 compositor_create_region
725 compositor_bind(struct wl_client *client,
726 void *data, uint32_t version, uint32_t id)
728 struct nested *nested = data;
729 struct wl_resource *resource;
731 resource = wl_resource_create(client, &wl_compositor_interface,
732 MIN(version, 3), id);
733 wl_resource_set_implementation(resource, &compositor_interface,
738 nested_init_compositor(struct nested *nested)
740 const char *extensions;
741 struct wl_event_loop *loop;
742 int use_ss_renderer = 0;
745 wl_list_init(&nested->surface_list);
746 nested->child_display = wl_display_create();
747 loop = wl_display_get_event_loop(nested->child_display);
748 fd = wl_event_loop_get_fd(loop);
749 nested->child_task.run = handle_child_data;
750 display_watch_fd(nested->display, fd,
751 EPOLLIN, &nested->child_task);
753 if (!wl_global_create(nested->child_display,
754 &wl_compositor_interface, 1,
755 nested, compositor_bind))
758 wl_display_init_shm(nested->child_display);
760 nested->egl_display = display_get_egl_display(nested->display);
761 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
762 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
763 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
767 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
768 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
769 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
770 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
771 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
772 image_target_texture_2d =
773 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
775 ret = bind_display(nested->egl_display, nested->child_display);
777 fprintf(stderr, "failed to bind wl_display\n");
781 if (display_has_subcompositor(nested->display)) {
782 const char *func = "eglCreateWaylandBufferFromImageWL";
783 const char *ext = "EGL_WL_create_wayland_buffer_from_image";
785 if (strstr(extensions, ext)) {
786 create_wayland_buffer_from_image =
787 (void *) eglGetProcAddress(func);
795 if (use_ss_renderer) {
796 printf("Using subsurfaces to render client surfaces\n");
797 nested->renderer = &nested_ss_renderer;
799 printf("Using local compositing with blits to "
800 "render client surfaces\n");
801 nested->renderer = &nested_blit_renderer;
807 static struct nested *
808 nested_create(struct display *display)
810 struct nested *nested;
812 nested = zalloc(sizeof *nested);
816 nested->window = window_create(display);
817 nested->widget = window_frame_create(nested->window, nested);
818 window_set_title(nested->window, "Wayland Nested");
819 nested->display = display;
821 window_set_user_data(nested->window, nested);
822 widget_set_redraw_handler(nested->widget, redraw_handler);
823 window_set_keyboard_focus_handler(nested->window,
824 keyboard_focus_handler);
826 nested_init_compositor(nested);
828 widget_schedule_resize(nested->widget, 400, 400);
834 nested_destroy(struct nested *nested)
836 widget_destroy(nested->widget);
837 window_destroy(nested->window);
841 /*** blit renderer ***/
844 blit_surface_init(struct nested_surface *surface)
846 struct nested_blit_surface *blit_surface =
847 xzalloc(sizeof *blit_surface);
849 glGenTextures(1, &blit_surface->texture);
850 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
851 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
852 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
853 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
854 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
856 surface->renderer_data = blit_surface;
860 blit_surface_fini(struct nested_surface *surface)
862 struct nested_blit_surface *blit_surface = surface->renderer_data;
864 nested_buffer_reference(&blit_surface->buffer_ref, NULL);
866 glDeleteTextures(1, &blit_surface->texture);
872 blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
874 struct nested *nested = data;
875 struct nested_surface *surface;
877 wl_list_for_each(surface, &nested->surface_list, link)
878 flush_surface_frame_callback_list(surface, time);
881 wl_callback_destroy(callback);
884 static const struct wl_callback_listener blit_frame_listener = {
889 blit_render_clients(struct nested *nested,
892 struct nested_surface *s;
893 struct rectangle allocation;
894 struct wl_callback *callback;
896 widget_get_allocation(nested->widget, &allocation);
898 wl_list_for_each(s, &nested->surface_list, link) {
899 struct nested_blit_surface *blit_surface = s->renderer_data;
901 display_acquire_window_surface(nested->display,
902 nested->window, NULL);
904 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
905 image_target_texture_2d(GL_TEXTURE_2D, s->image);
907 display_release_window_surface(nested->display,
910 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
911 cairo_set_source_surface(cr, blit_surface->cairo_surface,
914 cairo_rectangle(cr, allocation.x + 10,
916 allocation.width - 10,
917 allocation.height - 10);
922 callback = wl_surface_frame(window_get_wl_surface(nested->window));
923 wl_callback_add_listener(callback, &blit_frame_listener, nested);
927 blit_surface_attach(struct nested_surface *surface,
928 struct nested_buffer *buffer)
930 struct nested *nested = surface->nested;
931 struct nested_blit_surface *blit_surface = surface->renderer_data;
932 EGLint width, height;
933 cairo_device_t *device;
935 nested_buffer_reference(&blit_surface->buffer_ref, buffer);
937 if (blit_surface->cairo_surface)
938 cairo_surface_destroy(blit_surface->cairo_surface);
940 query_buffer(nested->egl_display, (void *) buffer->resource,
942 query_buffer(nested->egl_display, (void *) buffer->resource,
943 EGL_HEIGHT, &height);
945 device = display_get_cairo_device(nested->display);
946 blit_surface->cairo_surface =
947 cairo_gl_surface_create_for_texture(device,
948 CAIRO_CONTENT_COLOR_ALPHA,
949 blit_surface->texture,
953 static const struct nested_renderer
954 nested_blit_renderer = {
955 .surface_init = blit_surface_init,
956 .surface_fini = blit_surface_fini,
957 .render_clients = blit_render_clients,
958 .surface_attach = blit_surface_attach
961 /*** subsurface renderer ***/
964 ss_surface_init(struct nested_surface *surface)
966 struct nested *nested = surface->nested;
967 struct wl_compositor *compositor =
968 display_get_compositor(nested->display);
969 struct nested_ss_surface *ss_surface =
970 xzalloc(sizeof *ss_surface);
971 struct rectangle allocation;
972 struct wl_region *region;
975 window_add_subsurface(nested->window,
977 SUBSURFACE_SYNCHRONIZED);
979 ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
980 ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
982 /* The toy toolkit gets confused about the pointer position
983 * when it gets motion events for a subsurface so we'll just
984 * disable input on it */
985 region = wl_compositor_create_region(compositor);
986 wl_surface_set_input_region(ss_surface->surface, region);
987 wl_region_destroy(region);
989 widget_get_allocation(nested->widget, &allocation);
990 wl_subsurface_set_position(ss_surface->subsurface,
994 surface->renderer_data = ss_surface;
998 ss_surface_fini(struct nested_surface *surface)
1000 struct nested_ss_surface *ss_surface = surface->renderer_data;
1002 widget_destroy(ss_surface->widget);
1004 if (ss_surface->frame_callback)
1005 wl_callback_destroy(ss_surface->frame_callback);
1011 ss_render_clients(struct nested *nested,
1014 /* The clients are composited by the parent compositor so we
1015 * don't need to do anything here */
1019 ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
1021 struct nested_buffer *buffer = data;
1023 nested_buffer_reference(&buffer->parent_ref, NULL);
1026 static struct wl_buffer_listener ss_buffer_listener = {
1031 ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
1033 struct nested_surface *surface = data;
1034 struct nested_ss_surface *ss_surface = surface->renderer_data;
1036 flush_surface_frame_callback_list(surface, time);
1039 wl_callback_destroy(callback);
1041 ss_surface->frame_callback = NULL;
1044 static const struct wl_callback_listener ss_frame_listener = {
1049 ss_surface_attach(struct nested_surface *surface,
1050 struct nested_buffer *buffer)
1052 struct nested *nested = surface->nested;
1053 struct nested_ss_surface *ss_surface = surface->renderer_data;
1054 struct wl_buffer *parent_buffer;
1055 const pixman_box32_t *rects;
1059 /* Create a representation of the buffer in the parent
1060 * compositor if we haven't already */
1061 if (buffer->parent_buffer == NULL) {
1062 EGLDisplay *edpy = nested->egl_display;
1063 EGLImageKHR image = surface->image;
1065 buffer->parent_buffer =
1066 create_wayland_buffer_from_image(edpy, image);
1068 wl_buffer_add_listener(buffer->parent_buffer,
1069 &ss_buffer_listener,
1073 parent_buffer = buffer->parent_buffer;
1075 /* We'll take a reference to the buffer while the parent
1076 * compositor is using it so that we won't report the release
1077 * event until the parent has also finished with it */
1078 nested_buffer_reference(&buffer->parent_ref, buffer);
1080 parent_buffer = NULL;
1083 wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
1085 rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
1087 for (i = 0; i < n_rects; i++) {
1088 const pixman_box32_t *rect = rects + i;
1089 wl_surface_damage(ss_surface->surface,
1092 rect->x2 - rect->x1,
1093 rect->y2 - rect->y1);
1096 if (ss_surface->frame_callback)
1097 wl_callback_destroy(ss_surface->frame_callback);
1099 ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
1100 wl_callback_add_listener(ss_surface->frame_callback,
1104 wl_surface_commit(ss_surface->surface);
1107 static const struct nested_renderer
1108 nested_ss_renderer = {
1109 .surface_init = ss_surface_init,
1110 .surface_fini = ss_surface_fini,
1111 .render_clients = ss_render_clients,
1112 .surface_attach = ss_surface_attach
1116 main(int argc, char *argv[])
1118 struct display *display;
1119 struct nested *nested;
1121 parse_options(nested_options,
1122 ARRAY_LENGTH(nested_options), &argc, argv);
1124 display = display_create(&argc, argv);
1125 if (display == NULL) {
1126 fprintf(stderr, "failed to create display: %m\n");
1130 nested = nested_create(display);
1132 launch_client(nested, "weston-nested-client");
1134 display_run(display);
1136 nested_destroy(nested);
1137 display_destroy(display);