• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&region->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(&region->region, &region->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(&region->region, &region->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(&region->region);
703 
704 	region->resource =
705 		wl_resource_create(client, &wl_region_interface, 1, id);
706 	wl_resource_set_implementation(region->resource, &region_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