1 /*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "config.h"
25
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <cairo.h>
31 #include <math.h>
32 #include <assert.h>
33 #include <pixman.h>
34 #include <sys/epoll.h>
35 #include <sys/socket.h>
36 #include <unistd.h>
37 #include <errno.h>
38
39 #include <EGL/egl.h>
40 #include <EGL/eglext.h>
41 #include <GLES2/gl2.h>
42 #include <GLES2/gl2ext.h>
43
44 #include <cairo-gl.h>
45
46 #include <wayland-client.h>
47 #define WL_HIDE_DEPRECATED
48 #include <wayland-server.h>
49
50 #include "shared/helpers.h"
51 #include "shared/xalloc.h"
52 #include "window.h"
53
54 #include "shared/weston-egl-ext.h"
55
56
57 static bool option_blit;
58
59 struct nested {
60 struct display *display;
61 struct window *window;
62 struct widget *widget;
63 struct wl_display *child_display;
64 struct task child_task;
65
66 EGLDisplay egl_display;
67 struct program *texture_program;
68
69 struct wl_list surface_list;
70
71 const struct nested_renderer *renderer;
72 };
73
74 struct nested_region {
75 struct wl_resource *resource;
76 pixman_region32_t region;
77 };
78
79 struct nested_buffer_reference {
80 struct nested_buffer *buffer;
81 struct wl_listener destroy_listener;
82 };
83
84 struct nested_buffer {
85 struct wl_resource *resource;
86 struct wl_signal destroy_signal;
87 struct wl_listener destroy_listener;
88 uint32_t busy_count;
89
90 /* A buffer in the parent compositor representing the same
91 * data. This is created on-demand when the subsurface
92 * renderer is used */
93 struct wl_buffer *parent_buffer;
94 /* This reference is used to mark when the parent buffer has
95 * been attached to the subsurface. It will be unrefenced when
96 * we receive a buffer release event. That way we won't inform
97 * the client that the buffer is free until the parent
98 * compositor is also finished with it */
99 struct nested_buffer_reference parent_ref;
100 };
101
102 struct nested_surface {
103 struct wl_resource *resource;
104 struct nested *nested;
105 EGLImageKHR *image;
106 struct wl_list link;
107
108 struct wl_list frame_callback_list;
109
110 struct {
111 /* wl_surface.attach */
112 int newly_attached;
113 struct nested_buffer *buffer;
114 struct wl_listener buffer_destroy_listener;
115
116 /* wl_surface.frame */
117 struct wl_list frame_callback_list;
118
119 /* wl_surface.damage */
120 pixman_region32_t damage;
121 } pending;
122
123 void *renderer_data;
124 };
125
126 /* Data used for the blit renderer */
127 struct nested_blit_surface {
128 struct nested_buffer_reference buffer_ref;
129 GLuint texture;
130 cairo_surface_t *cairo_surface;
131 };
132
133 /* Data used for the subsurface renderer */
134 struct nested_ss_surface {
135 struct widget *widget;
136 struct wl_surface *surface;
137 struct wl_subsurface *subsurface;
138 struct wl_callback *frame_callback;
139 };
140
141 struct nested_frame_callback {
142 struct wl_resource *resource;
143 struct wl_list link;
144 };
145
146 struct nested_renderer {
147 void (* surface_init)(struct nested_surface *surface);
148 void (* surface_fini)(struct nested_surface *surface);
149 void (* render_clients)(struct nested *nested, cairo_t *cr);
150 void (* surface_attach)(struct nested_surface *surface,
151 struct nested_buffer *buffer);
152 };
153
154 static const struct weston_option nested_options[] = {
155 { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
156 };
157
158 static const struct nested_renderer nested_blit_renderer;
159 static const struct nested_renderer nested_ss_renderer;
160
161 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
162 static PFNEGLCREATEIMAGEKHRPROC create_image;
163 static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
164 static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
165 static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
166 static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
167 static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
168
169 static void
nested_buffer_destroy_handler(struct wl_listener * listener,void * data)170 nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
171 {
172 struct nested_buffer *buffer =
173 container_of(listener, struct nested_buffer, destroy_listener);
174
175 wl_signal_emit(&buffer->destroy_signal, buffer);
176
177 if (buffer->parent_buffer)
178 wl_buffer_destroy(buffer->parent_buffer);
179
180 free(buffer);
181 }
182
183 static struct nested_buffer *
nested_buffer_from_resource(struct wl_resource * resource)184 nested_buffer_from_resource(struct wl_resource *resource)
185 {
186 struct nested_buffer *buffer;
187 struct wl_listener *listener;
188
189 listener =
190 wl_resource_get_destroy_listener(resource,
191 nested_buffer_destroy_handler);
192
193 if (listener)
194 return container_of(listener, struct nested_buffer,
195 destroy_listener);
196
197 buffer = zalloc(sizeof *buffer);
198 if (buffer == NULL)
199 return NULL;
200
201 buffer->resource = resource;
202 wl_signal_init(&buffer->destroy_signal);
203 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
204 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
205
206 return buffer;
207 }
208
209 static void
nested_buffer_reference_handle_destroy(struct wl_listener * listener,void * data)210 nested_buffer_reference_handle_destroy(struct wl_listener *listener,
211 void *data)
212 {
213 struct nested_buffer_reference *ref =
214 container_of(listener, struct nested_buffer_reference,
215 destroy_listener);
216
217 assert((struct nested_buffer *)data == ref->buffer);
218 ref->buffer = NULL;
219 }
220
221 static void
nested_buffer_reference(struct nested_buffer_reference * ref,struct nested_buffer * buffer)222 nested_buffer_reference(struct nested_buffer_reference *ref,
223 struct nested_buffer *buffer)
224 {
225 if (buffer == ref->buffer)
226 return;
227
228 if (ref->buffer) {
229 ref->buffer->busy_count--;
230 if (ref->buffer->busy_count == 0) {
231 assert(wl_resource_get_client(ref->buffer->resource));
232 wl_buffer_send_release(ref->buffer->resource);
233 }
234 wl_list_remove(&ref->destroy_listener.link);
235 }
236
237 if (buffer) {
238 buffer->busy_count++;
239 wl_signal_add(&buffer->destroy_signal,
240 &ref->destroy_listener);
241
242 ref->destroy_listener.notify =
243 nested_buffer_reference_handle_destroy;
244 }
245
246 ref->buffer = buffer;
247 }
248
249 static void
flush_surface_frame_callback_list(struct nested_surface * surface,uint32_t time)250 flush_surface_frame_callback_list(struct nested_surface *surface,
251 uint32_t time)
252 {
253 struct nested_frame_callback *nc, *next;
254
255 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
256 wl_callback_send_done(nc->resource, time);
257 wl_resource_destroy(nc->resource);
258 }
259 wl_list_init(&surface->frame_callback_list);
260
261 /* FIXME: toytoolkit need a pre-block handler where we can
262 * call this. */
263 wl_display_flush_clients(surface->nested->child_display);
264 }
265
266 static void
redraw_handler(struct widget * widget,void * data)267 redraw_handler(struct widget *widget, void *data)
268 {
269 struct nested *nested = data;
270 cairo_surface_t *surface;
271 cairo_t *cr;
272 struct rectangle allocation;
273
274 widget_get_allocation(nested->widget, &allocation);
275
276 surface = window_get_surface(nested->window);
277
278 cr = cairo_create(surface);
279 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
280 cairo_rectangle(cr,
281 allocation.x,
282 allocation.y,
283 allocation.width,
284 allocation.height);
285 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
286 cairo_fill(cr);
287
288 nested->renderer->render_clients(nested, cr);
289
290 cairo_destroy(cr);
291
292 cairo_surface_destroy(surface);
293 }
294
295 static void
keyboard_focus_handler(struct window * window,struct input * device,void * data)296 keyboard_focus_handler(struct window *window,
297 struct input *device, void *data)
298 {
299 struct nested *nested = data;
300
301 window_schedule_redraw(nested->window);
302 }
303
304 static void
handle_child_data(struct task * task,uint32_t events)305 handle_child_data(struct task *task, uint32_t events)
306 {
307 struct nested *nested = container_of(task, struct nested, child_task);
308 struct wl_event_loop *loop;
309
310 loop = wl_display_get_event_loop(nested->child_display);
311
312 wl_event_loop_dispatch(loop, -1);
313 wl_display_flush_clients(nested->child_display);
314 }
315
316 struct nested_client {
317 struct wl_client *client;
318 pid_t pid;
319 };
320
321 static struct nested_client *
launch_client(struct nested * nested,const char * path)322 launch_client(struct nested *nested, const char *path)
323 {
324 int sv[2];
325 pid_t pid;
326 struct nested_client *client;
327
328 client = malloc(sizeof *client);
329 if (client == NULL)
330 return NULL;
331
332 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
333 fprintf(stderr, "launch_client: "
334 "socketpair failed while launching '%s': %s\n",
335 path, strerror(errno));
336 free(client);
337 return NULL;
338 }
339
340 pid = fork();
341 if (pid == -1) {
342 close(sv[0]);
343 close(sv[1]);
344 free(client);
345 fprintf(stderr, "launch_client: "
346 "fork failed while launching '%s': %s\n", path,
347 strerror(errno));
348 return NULL;
349 }
350
351 if (pid == 0) {
352 int clientfd;
353 char s[32];
354
355 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
356 * get a non-CLOEXEC fd to pass through exec. */
357 clientfd = dup(sv[1]);
358 if (clientfd == -1) {
359 fprintf(stderr, "compositor: dup failed: %s\n",
360 strerror(errno));
361 exit(-1);
362 }
363
364 snprintf(s, sizeof s, "%d", clientfd);
365 setenv("WAYLAND_SOCKET", s, 1);
366
367 execl(path, path, NULL);
368
369 fprintf(stderr, "compositor: executing '%s' failed: %s\n",
370 path, strerror(errno));
371 exit(-1);
372 }
373
374 close(sv[1]);
375
376 client->client = wl_client_create(nested->child_display, sv[0]);
377 if (!client->client) {
378 close(sv[0]);
379 free(client);
380 fprintf(stderr, "launch_client: "
381 "wl_client_create failed while launching '%s'.\n",
382 path);
383 return NULL;
384 }
385
386 client->pid = pid;
387
388 return client;
389 }
390
391 static void
destroy_surface(struct wl_resource * resource)392 destroy_surface(struct wl_resource *resource)
393 {
394 struct nested_surface *surface = wl_resource_get_user_data(resource);
395 struct nested *nested = surface->nested;
396 struct nested_frame_callback *cb, *next;
397
398 wl_list_for_each_safe(cb, next,
399 &surface->frame_callback_list, link)
400 wl_resource_destroy(cb->resource);
401
402 wl_list_for_each_safe(cb, next,
403 &surface->pending.frame_callback_list, link)
404 wl_resource_destroy(cb->resource);
405
406 pixman_region32_fini(&surface->pending.damage);
407
408 nested->renderer->surface_fini(surface);
409
410 wl_list_remove(&surface->link);
411
412 free(surface);
413 }
414
415 static void
surface_destroy(struct wl_client * client,struct wl_resource * resource)416 surface_destroy(struct wl_client *client, struct wl_resource *resource)
417 {
418 wl_resource_destroy(resource);
419 }
420
421 static void
surface_attach(struct wl_client * client,struct wl_resource * resource,struct wl_resource * buffer_resource,int32_t sx,int32_t sy)422 surface_attach(struct wl_client *client,
423 struct wl_resource *resource,
424 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
425 {
426 struct nested_surface *surface = wl_resource_get_user_data(resource);
427 struct nested *nested = surface->nested;
428 struct nested_buffer *buffer = NULL;
429
430 if (buffer_resource) {
431 int format;
432
433 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
434 EGL_TEXTURE_FORMAT, &format)) {
435 wl_resource_post_error(buffer_resource,
436 WL_DISPLAY_ERROR_INVALID_OBJECT,
437 "attaching non-egl wl_buffer");
438 return;
439 }
440
441 switch (format) {
442 case EGL_TEXTURE_RGB:
443 case EGL_TEXTURE_RGBA:
444 break;
445 default:
446 wl_resource_post_error(buffer_resource,
447 WL_DISPLAY_ERROR_INVALID_OBJECT,
448 "invalid format");
449 return;
450 }
451
452 buffer = nested_buffer_from_resource(buffer_resource);
453 if (buffer == NULL) {
454 wl_client_post_no_memory(client);
455 return;
456 }
457 }
458
459 if (surface->pending.buffer)
460 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
461
462 surface->pending.buffer = buffer;
463 surface->pending.newly_attached = 1;
464 if (buffer) {
465 wl_signal_add(&buffer->destroy_signal,
466 &surface->pending.buffer_destroy_listener);
467 }
468 }
469
470 static void
nested_surface_attach(struct nested_surface * surface,struct nested_buffer * buffer)471 nested_surface_attach(struct nested_surface *surface,
472 struct nested_buffer *buffer)
473 {
474 struct nested *nested = surface->nested;
475
476 if (surface->image != EGL_NO_IMAGE_KHR)
477 destroy_image(nested->egl_display, surface->image);
478
479 surface->image = create_image(nested->egl_display, NULL,
480 EGL_WAYLAND_BUFFER_WL, buffer->resource,
481 NULL);
482 if (surface->image == EGL_NO_IMAGE_KHR) {
483 fprintf(stderr, "failed to create img\n");
484 return;
485 }
486
487 nested->renderer->surface_attach(surface, buffer);
488 }
489
490 static void
surface_damage(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)491 surface_damage(struct wl_client *client,
492 struct wl_resource *resource,
493 int32_t x, int32_t y, int32_t width, int32_t height)
494 {
495 struct nested_surface *surface = wl_resource_get_user_data(resource);
496
497 pixman_region32_union_rect(&surface->pending.damage,
498 &surface->pending.damage,
499 x, y, width, height);
500 }
501
502 static void
destroy_frame_callback(struct wl_resource * resource)503 destroy_frame_callback(struct wl_resource *resource)
504 {
505 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
506
507 wl_list_remove(&callback->link);
508 free(callback);
509 }
510
511 static void
surface_frame(struct wl_client * client,struct wl_resource * resource,uint32_t id)512 surface_frame(struct wl_client *client,
513 struct wl_resource *resource, uint32_t id)
514 {
515 struct nested_frame_callback *callback;
516 struct nested_surface *surface = wl_resource_get_user_data(resource);
517
518 callback = malloc(sizeof *callback);
519 if (callback == NULL) {
520 wl_resource_post_no_memory(resource);
521 return;
522 }
523
524 callback->resource = wl_resource_create(client,
525 &wl_callback_interface, 1, id);
526 wl_resource_set_implementation(callback->resource, NULL, callback,
527 destroy_frame_callback);
528
529 wl_list_insert(surface->pending.frame_callback_list.prev,
530 &callback->link);
531 }
532
533 static void
surface_set_opaque_region(struct wl_client * client,struct wl_resource * resource,struct wl_resource * region_resource)534 surface_set_opaque_region(struct wl_client *client,
535 struct wl_resource *resource,
536 struct wl_resource *region_resource)
537 {
538 fprintf(stderr, "surface_set_opaque_region\n");
539 }
540
541 static void
surface_set_input_region(struct wl_client * client,struct wl_resource * resource,struct wl_resource * region_resource)542 surface_set_input_region(struct wl_client *client,
543 struct wl_resource *resource,
544 struct wl_resource *region_resource)
545 {
546 fprintf(stderr, "surface_set_input_region\n");
547 }
548
549 static void
surface_commit(struct wl_client * client,struct wl_resource * resource)550 surface_commit(struct wl_client *client, struct wl_resource *resource)
551 {
552 struct nested_surface *surface = wl_resource_get_user_data(resource);
553 struct nested *nested = surface->nested;
554
555 /* wl_surface.attach */
556 if (surface->pending.newly_attached)
557 nested_surface_attach(surface, surface->pending.buffer);
558
559 if (surface->pending.buffer) {
560 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
561 surface->pending.buffer = NULL;
562 }
563 surface->pending.newly_attached = 0;
564
565 /* wl_surface.damage */
566 pixman_region32_clear(&surface->pending.damage);
567
568 /* wl_surface.frame */
569 wl_list_insert_list(&surface->frame_callback_list,
570 &surface->pending.frame_callback_list);
571 wl_list_init(&surface->pending.frame_callback_list);
572
573 /* FIXME: For the subsurface renderer we don't need to
574 * actually redraw the window. However we do want to cause a
575 * commit because the subsurface is synchronized. Ideally we
576 * would just queue the commit */
577 window_schedule_redraw(nested->window);
578 }
579
580 static void
surface_set_buffer_transform(struct wl_client * client,struct wl_resource * resource,int transform)581 surface_set_buffer_transform(struct wl_client *client,
582 struct wl_resource *resource, int transform)
583 {
584 fprintf(stderr, "surface_set_buffer_transform\n");
585 }
586
587 static const struct wl_surface_interface surface_interface = {
588 surface_destroy,
589 surface_attach,
590 surface_damage,
591 surface_frame,
592 surface_set_opaque_region,
593 surface_set_input_region,
594 surface_commit,
595 surface_set_buffer_transform
596 };
597
598 static void
surface_handle_pending_buffer_destroy(struct wl_listener * listener,void * data)599 surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
600 {
601 struct nested_surface *surface =
602 container_of(listener, struct nested_surface,
603 pending.buffer_destroy_listener);
604
605 surface->pending.buffer = NULL;
606 }
607
608 static void
compositor_create_surface(struct wl_client * client,struct wl_resource * resource,uint32_t id)609 compositor_create_surface(struct wl_client *client,
610 struct wl_resource *resource, uint32_t id)
611 {
612 struct nested *nested = wl_resource_get_user_data(resource);
613 struct nested_surface *surface;
614
615 surface = zalloc(sizeof *surface);
616 if (surface == NULL) {
617 wl_resource_post_no_memory(resource);
618 return;
619 }
620
621 surface->nested = nested;
622
623 wl_list_init(&surface->frame_callback_list);
624
625 wl_list_init(&surface->pending.frame_callback_list);
626 surface->pending.buffer_destroy_listener.notify =
627 surface_handle_pending_buffer_destroy;
628 pixman_region32_init(&surface->pending.damage);
629
630 display_acquire_window_surface(nested->display,
631 nested->window, NULL);
632
633 nested->renderer->surface_init(surface);
634
635 display_release_window_surface(nested->display, nested->window);
636
637 surface->resource =
638 wl_resource_create(client, &wl_surface_interface, 1, id);
639
640 wl_resource_set_implementation(surface->resource,
641 &surface_interface, surface,
642 destroy_surface);
643
644 wl_list_insert(nested->surface_list.prev, &surface->link);
645 }
646
647 static void
destroy_region(struct wl_resource * resource)648 destroy_region(struct wl_resource *resource)
649 {
650 struct nested_region *region = wl_resource_get_user_data(resource);
651
652 pixman_region32_fini(®ion->region);
653 free(region);
654 }
655
656 static void
region_destroy(struct wl_client * client,struct wl_resource * resource)657 region_destroy(struct wl_client *client, struct wl_resource *resource)
658 {
659 wl_resource_destroy(resource);
660 }
661
662 static void
region_add(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)663 region_add(struct wl_client *client, struct wl_resource *resource,
664 int32_t x, int32_t y, int32_t width, int32_t height)
665 {
666 struct nested_region *region = wl_resource_get_user_data(resource);
667
668 pixman_region32_union_rect(®ion->region, ®ion->region,
669 x, y, width, height);
670 }
671
672 static void
region_subtract(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)673 region_subtract(struct wl_client *client, struct wl_resource *resource,
674 int32_t x, int32_t y, int32_t width, int32_t height)
675 {
676 struct nested_region *region = wl_resource_get_user_data(resource);
677 pixman_region32_t rect;
678
679 pixman_region32_init_rect(&rect, x, y, width, height);
680 pixman_region32_subtract(®ion->region, ®ion->region, &rect);
681 pixman_region32_fini(&rect);
682 }
683
684 static const struct wl_region_interface region_interface = {
685 region_destroy,
686 region_add,
687 region_subtract
688 };
689
690 static void
compositor_create_region(struct wl_client * client,struct wl_resource * resource,uint32_t id)691 compositor_create_region(struct wl_client *client,
692 struct wl_resource *resource, uint32_t id)
693 {
694 struct nested_region *region;
695
696 region = malloc(sizeof *region);
697 if (region == NULL) {
698 wl_resource_post_no_memory(resource);
699 return;
700 }
701
702 pixman_region32_init(®ion->region);
703
704 region->resource =
705 wl_resource_create(client, &wl_region_interface, 1, id);
706 wl_resource_set_implementation(region->resource, ®ion_interface,
707 region, destroy_region);
708 }
709
710 static const struct wl_compositor_interface compositor_interface = {
711 compositor_create_surface,
712 compositor_create_region
713 };
714
715 static void
compositor_bind(struct wl_client * client,void * data,uint32_t version,uint32_t id)716 compositor_bind(struct wl_client *client,
717 void *data, uint32_t version, uint32_t id)
718 {
719 struct nested *nested = data;
720 struct wl_resource *resource;
721
722 resource = wl_resource_create(client, &wl_compositor_interface,
723 MIN(version, 3), id);
724 wl_resource_set_implementation(resource, &compositor_interface,
725 nested, NULL);
726 }
727
728 static int
nested_init_compositor(struct nested * nested)729 nested_init_compositor(struct nested *nested)
730 {
731 const char *extensions;
732 struct wl_event_loop *loop;
733 int use_ss_renderer = 0;
734 int fd, ret;
735
736 wl_list_init(&nested->surface_list);
737 nested->child_display = wl_display_create();
738 loop = wl_display_get_event_loop(nested->child_display);
739 fd = wl_event_loop_get_fd(loop);
740 nested->child_task.run = handle_child_data;
741 display_watch_fd(nested->display, fd,
742 EPOLLIN, &nested->child_task);
743
744 if (!wl_global_create(nested->child_display,
745 &wl_compositor_interface, 1,
746 nested, compositor_bind))
747 return -1;
748
749 wl_display_init_shm(nested->child_display);
750
751 nested->egl_display = display_get_egl_display(nested->display);
752 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
753 if (!weston_check_egl_extension(extensions, "EGL_WL_bind_wayland_display")) {
754 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
755 return -1;
756 }
757
758 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
759 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
760 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
761 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
762 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
763 image_target_texture_2d =
764 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
765
766 ret = bind_display(nested->egl_display, nested->child_display);
767 if (!ret) {
768 fprintf(stderr, "failed to bind wl_display\n");
769 return -1;
770 }
771
772 if (display_has_subcompositor(nested->display)) {
773 const char *func = "eglCreateWaylandBufferFromImageWL";
774 const char *ext = "EGL_WL_create_wayland_buffer_from_image";
775
776 if (weston_check_egl_extension(extensions, ext)) {
777 create_wayland_buffer_from_image =
778 (void *) eglGetProcAddress(func);
779 use_ss_renderer = 1;
780 }
781 }
782
783 if (option_blit)
784 use_ss_renderer = 0;
785
786 if (use_ss_renderer) {
787 printf("Using subsurfaces to render client surfaces\n");
788 nested->renderer = &nested_ss_renderer;
789 } else {
790 printf("Using local compositing with blits to "
791 "render client surfaces\n");
792 nested->renderer = &nested_blit_renderer;
793 }
794
795 return 0;
796 }
797
798 static struct nested *
nested_create(struct display * display)799 nested_create(struct display *display)
800 {
801 struct nested *nested;
802
803 nested = zalloc(sizeof *nested);
804 if (nested == NULL)
805 return nested;
806
807 nested->window = window_create(display);
808 nested->widget = window_frame_create(nested->window, nested);
809 window_set_title(nested->window, "Wayland Nested");
810 nested->display = display;
811
812 window_set_user_data(nested->window, nested);
813 widget_set_redraw_handler(nested->widget, redraw_handler);
814 window_set_keyboard_focus_handler(nested->window,
815 keyboard_focus_handler);
816
817 nested_init_compositor(nested);
818
819 widget_schedule_resize(nested->widget, 400, 400);
820
821 return nested;
822 }
823
824 static void
nested_destroy(struct nested * nested)825 nested_destroy(struct nested *nested)
826 {
827 widget_destroy(nested->widget);
828 window_destroy(nested->window);
829 free(nested);
830 }
831
832 /*** blit renderer ***/
833
834 static void
blit_surface_init(struct nested_surface * surface)835 blit_surface_init(struct nested_surface *surface)
836 {
837 struct nested_blit_surface *blit_surface =
838 xzalloc(sizeof *blit_surface);
839
840 glGenTextures(1, &blit_surface->texture);
841 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
842 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
843 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
844 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
845 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
846
847 surface->renderer_data = blit_surface;
848 }
849
850 static void
blit_surface_fini(struct nested_surface * surface)851 blit_surface_fini(struct nested_surface *surface)
852 {
853 struct nested_blit_surface *blit_surface = surface->renderer_data;
854
855 nested_buffer_reference(&blit_surface->buffer_ref, NULL);
856
857 glDeleteTextures(1, &blit_surface->texture);
858
859 free(blit_surface);
860 }
861
862 static void
blit_frame_callback(void * data,struct wl_callback * callback,uint32_t time)863 blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
864 {
865 struct nested *nested = data;
866 struct nested_surface *surface;
867
868 wl_list_for_each(surface, &nested->surface_list, link)
869 flush_surface_frame_callback_list(surface, time);
870
871 if (callback)
872 wl_callback_destroy(callback);
873 }
874
875 static const struct wl_callback_listener blit_frame_listener = {
876 blit_frame_callback
877 };
878
879 static void
blit_render_clients(struct nested * nested,cairo_t * cr)880 blit_render_clients(struct nested *nested,
881 cairo_t *cr)
882 {
883 struct nested_surface *s;
884 struct rectangle allocation;
885 struct wl_callback *callback;
886
887 widget_get_allocation(nested->widget, &allocation);
888
889 wl_list_for_each(s, &nested->surface_list, link) {
890 struct nested_blit_surface *blit_surface = s->renderer_data;
891
892 display_acquire_window_surface(nested->display,
893 nested->window, NULL);
894
895 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
896 image_target_texture_2d(GL_TEXTURE_2D, s->image);
897
898 display_release_window_surface(nested->display,
899 nested->window);
900
901 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
902 cairo_set_source_surface(cr, blit_surface->cairo_surface,
903 allocation.x + 10,
904 allocation.y + 10);
905 cairo_rectangle(cr, allocation.x + 10,
906 allocation.y + 10,
907 allocation.width - 10,
908 allocation.height - 10);
909
910 cairo_fill(cr);
911 }
912
913 callback = wl_surface_frame(window_get_wl_surface(nested->window));
914 wl_callback_add_listener(callback, &blit_frame_listener, nested);
915 }
916
917 static void
blit_surface_attach(struct nested_surface * surface,struct nested_buffer * buffer)918 blit_surface_attach(struct nested_surface *surface,
919 struct nested_buffer *buffer)
920 {
921 struct nested *nested = surface->nested;
922 struct nested_blit_surface *blit_surface = surface->renderer_data;
923 EGLint width, height;
924 cairo_device_t *device;
925
926 nested_buffer_reference(&blit_surface->buffer_ref, buffer);
927
928 if (blit_surface->cairo_surface)
929 cairo_surface_destroy(blit_surface->cairo_surface);
930
931 query_buffer(nested->egl_display, (void *) buffer->resource,
932 EGL_WIDTH, &width);
933 query_buffer(nested->egl_display, (void *) buffer->resource,
934 EGL_HEIGHT, &height);
935
936 device = display_get_cairo_device(nested->display);
937 blit_surface->cairo_surface =
938 cairo_gl_surface_create_for_texture(device,
939 CAIRO_CONTENT_COLOR_ALPHA,
940 blit_surface->texture,
941 width, height);
942 }
943
944 static const struct nested_renderer
945 nested_blit_renderer = {
946 .surface_init = blit_surface_init,
947 .surface_fini = blit_surface_fini,
948 .render_clients = blit_render_clients,
949 .surface_attach = blit_surface_attach
950 };
951
952 /*** subsurface renderer ***/
953
954 static void
ss_surface_init(struct nested_surface * surface)955 ss_surface_init(struct nested_surface *surface)
956 {
957 struct nested *nested = surface->nested;
958 struct wl_compositor *compositor =
959 display_get_compositor(nested->display);
960 struct nested_ss_surface *ss_surface =
961 xzalloc(sizeof *ss_surface);
962 struct rectangle allocation;
963 struct wl_region *region;
964
965 ss_surface->widget =
966 window_add_subsurface(nested->window,
967 nested,
968 SUBSURFACE_SYNCHRONIZED);
969
970 widget_set_use_cairo(ss_surface->widget, 0);
971
972 ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
973 ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
974
975 /* The toy toolkit gets confused about the pointer position
976 * when it gets motion events for a subsurface so we'll just
977 * disable input on it */
978 region = wl_compositor_create_region(compositor);
979 wl_surface_set_input_region(ss_surface->surface, region);
980 wl_region_destroy(region);
981
982 widget_get_allocation(nested->widget, &allocation);
983 wl_subsurface_set_position(ss_surface->subsurface,
984 allocation.x + 10,
985 allocation.y + 10);
986
987 surface->renderer_data = ss_surface;
988 }
989
990 static void
ss_surface_fini(struct nested_surface * surface)991 ss_surface_fini(struct nested_surface *surface)
992 {
993 struct nested_ss_surface *ss_surface = surface->renderer_data;
994
995 widget_destroy(ss_surface->widget);
996
997 if (ss_surface->frame_callback)
998 wl_callback_destroy(ss_surface->frame_callback);
999
1000 free(ss_surface);
1001 }
1002
1003 static void
ss_render_clients(struct nested * nested,cairo_t * cr)1004 ss_render_clients(struct nested *nested,
1005 cairo_t *cr)
1006 {
1007 /* The clients are composited by the parent compositor so we
1008 * don't need to do anything here */
1009 }
1010
1011 static void
ss_buffer_release(void * data,struct wl_buffer * wl_buffer)1012 ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
1013 {
1014 struct nested_buffer *buffer = data;
1015
1016 nested_buffer_reference(&buffer->parent_ref, NULL);
1017 }
1018
1019 static struct wl_buffer_listener ss_buffer_listener = {
1020 ss_buffer_release
1021 };
1022
1023 static void
ss_frame_callback(void * data,struct wl_callback * callback,uint32_t time)1024 ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
1025 {
1026 struct nested_surface *surface = data;
1027 struct nested_ss_surface *ss_surface = surface->renderer_data;
1028
1029 flush_surface_frame_callback_list(surface, time);
1030
1031 if (callback)
1032 wl_callback_destroy(callback);
1033
1034 ss_surface->frame_callback = NULL;
1035 }
1036
1037 static const struct wl_callback_listener ss_frame_listener = {
1038 ss_frame_callback
1039 };
1040
1041 static void
ss_surface_attach(struct nested_surface * surface,struct nested_buffer * buffer)1042 ss_surface_attach(struct nested_surface *surface,
1043 struct nested_buffer *buffer)
1044 {
1045 struct nested *nested = surface->nested;
1046 struct nested_ss_surface *ss_surface = surface->renderer_data;
1047 struct wl_buffer *parent_buffer;
1048 const pixman_box32_t *rects;
1049 int n_rects, i;
1050
1051 if (buffer) {
1052 /* Create a representation of the buffer in the parent
1053 * compositor if we haven't already */
1054 if (buffer->parent_buffer == NULL) {
1055 EGLDisplay *edpy = nested->egl_display;
1056 EGLImageKHR image = surface->image;
1057
1058 buffer->parent_buffer =
1059 create_wayland_buffer_from_image(edpy, image);
1060
1061 wl_buffer_add_listener(buffer->parent_buffer,
1062 &ss_buffer_listener,
1063 buffer);
1064 }
1065
1066 parent_buffer = buffer->parent_buffer;
1067
1068 /* We'll take a reference to the buffer while the parent
1069 * compositor is using it so that we won't report the release
1070 * event until the parent has also finished with it */
1071 nested_buffer_reference(&buffer->parent_ref, buffer);
1072 } else {
1073 parent_buffer = NULL;
1074 }
1075
1076 wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
1077
1078 rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
1079
1080 for (i = 0; i < n_rects; i++) {
1081 const pixman_box32_t *rect = rects + i;
1082 wl_surface_damage(ss_surface->surface,
1083 rect->x1,
1084 rect->y1,
1085 rect->x2 - rect->x1,
1086 rect->y2 - rect->y1);
1087 }
1088
1089 if (ss_surface->frame_callback)
1090 wl_callback_destroy(ss_surface->frame_callback);
1091
1092 ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
1093 wl_callback_add_listener(ss_surface->frame_callback,
1094 &ss_frame_listener,
1095 surface);
1096
1097 wl_surface_commit(ss_surface->surface);
1098 }
1099
1100 static const struct nested_renderer
1101 nested_ss_renderer = {
1102 .surface_init = ss_surface_init,
1103 .surface_fini = ss_surface_fini,
1104 .render_clients = ss_render_clients,
1105 .surface_attach = ss_surface_attach
1106 };
1107
1108 int
main(int argc,char * argv[])1109 main(int argc, char *argv[])
1110 {
1111 struct display *display;
1112 struct nested *nested;
1113
1114 if (parse_options(nested_options,
1115 ARRAY_LENGTH(nested_options), &argc, argv) > 1) {
1116 printf("Usage: %s [OPTIONS]\n --blit or -b\n", argv[0]);
1117 exit(1);
1118 }
1119
1120 display = display_create(&argc, argv);
1121 if (display == NULL) {
1122 fprintf(stderr, "failed to create display: %s\n",
1123 strerror(errno));
1124 return -1;
1125 }
1126
1127 nested = nested_create(display);
1128
1129 launch_client(nested, "weston-nested-client");
1130
1131 display_run(display);
1132
1133 nested_destroy(nested);
1134 display_destroy(display);
1135
1136 return 0;
1137 }
1138