blob: e78f08c396f4311ddade9b83230cf4198caca692 [file] [log] [blame]
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001/*
2 * Copyright © 2013 Intel Corporation
3 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07004 * 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:
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040010 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070011 * 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.
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040022 */
23
Andrew Wedgbury9cd661e2014-04-07 12:40:35 +010024#include "config.h"
25
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040026#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
38#include <EGL/egl.h>
39#include <EGL/eglext.h>
40#include <GLES2/gl2.h>
41#include <GLES2/gl2ext.h>
42
43#include <cairo-gl.h>
44
45#include <wayland-client.h>
Kristian Høgsberg3c179332013-08-06 19:27:04 -070046#define WL_HIDE_DEPRECATED
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040047#include <wayland-server.h>
48
Jon Cruz35b2eaa2015-06-15 15:37:08 -070049#include "shared/helpers.h"
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040050#include "window.h"
51
Kristian Høgsbergc2010b32013-12-17 10:40:01 -080052#ifndef EGL_WL_create_wayland_buffer_from_image
53#define EGL_WL_create_wayland_buffer_from_image 1
54
55#ifdef EGL_EGLEXT_PROTOTYPES
56EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
57#endif
58typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
59
60#endif
61
Neil Robertsa5059eb2013-09-09 00:59:35 +010062static int option_blit;
63
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040064struct nested {
65 struct display *display;
66 struct window *window;
67 struct widget *widget;
68 struct wl_display *child_display;
69 struct task child_task;
70
71 EGLDisplay egl_display;
72 struct program *texture_program;
73
74 struct wl_list surface_list;
Neil Roberts47b87d52013-09-08 20:52:36 +010075
76 const struct nested_renderer *renderer;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040077};
78
79struct nested_region {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040080 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040081 pixman_region32_t region;
82};
83
Neil Roberts1f020a12013-09-09 00:41:29 +010084struct nested_buffer_reference {
85 struct nested_buffer *buffer;
86 struct wl_listener destroy_listener;
87};
88
Neil Roberts6bf23872013-09-08 18:49:15 +010089struct nested_buffer {
90 struct wl_resource *resource;
91 struct wl_signal destroy_signal;
92 struct wl_listener destroy_listener;
93 uint32_t busy_count;
Neil Roberts6bf23872013-09-08 18:49:15 +010094
Neil Roberts1f020a12013-09-09 00:41:29 +010095 /* A buffer in the parent compositor representing the same
96 * data. This is created on-demand when the subsurface
97 * renderer is used */
98 struct wl_buffer *parent_buffer;
99 /* This reference is used to mark when the parent buffer has
100 * been attached to the subsurface. It will be unrefenced when
101 * we receive a buffer release event. That way we won't inform
102 * the client that the buffer is free until the parent
103 * compositor is also finished with it */
104 struct nested_buffer_reference parent_ref;
Neil Roberts6bf23872013-09-08 18:49:15 +0100105};
106
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400107struct nested_surface {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400108 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400109 struct nested *nested;
110 EGLImageKHR *image;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400111 struct wl_list link;
Neil Roberts15a8d342013-09-08 19:49:02 +0100112
Neil Robertsf9b25412013-09-09 15:13:09 +0100113 struct wl_list frame_callback_list;
114
Neil Roberts15a8d342013-09-08 19:49:02 +0100115 struct {
116 /* wl_surface.attach */
117 int newly_attached;
118 struct nested_buffer *buffer;
119 struct wl_listener buffer_destroy_listener;
120
121 /* wl_surface.frame */
122 struct wl_list frame_callback_list;
Neil Roberts28557662013-09-08 20:24:14 +0100123
124 /* wl_surface.damage */
125 pixman_region32_t damage;
Neil Roberts15a8d342013-09-08 19:49:02 +0100126 } pending;
Neil Roberts47b87d52013-09-08 20:52:36 +0100127
128 void *renderer_data;
129};
130
131/* Data used for the blit renderer */
132struct nested_blit_surface {
133 struct nested_buffer_reference buffer_ref;
134 GLuint texture;
135 cairo_surface_t *cairo_surface;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400136};
137
Neil Roberts1f020a12013-09-09 00:41:29 +0100138/* Data used for the subsurface renderer */
139struct nested_ss_surface {
140 struct widget *widget;
141 struct wl_surface *surface;
142 struct wl_subsurface *subsurface;
143 struct wl_callback *frame_callback;
144};
145
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400146struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400147 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400148 struct wl_list link;
149};
150
Neil Roberts47b87d52013-09-08 20:52:36 +0100151struct nested_renderer {
152 void (* surface_init)(struct nested_surface *surface);
153 void (* surface_fini)(struct nested_surface *surface);
154 void (* render_clients)(struct nested *nested, cairo_t *cr);
155 void (* surface_attach)(struct nested_surface *surface,
156 struct nested_buffer *buffer);
157};
158
Neil Robertsa5059eb2013-09-09 00:59:35 +0100159static const struct weston_option nested_options[] = {
160 { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
161};
162
Neil Roberts47b87d52013-09-08 20:52:36 +0100163static const struct nested_renderer nested_blit_renderer;
Neil Roberts1f020a12013-09-09 00:41:29 +0100164static const struct nested_renderer nested_ss_renderer;
Neil Roberts47b87d52013-09-08 20:52:36 +0100165
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400166static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
167static PFNEGLCREATEIMAGEKHRPROC create_image;
168static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
169static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
170static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
171static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
Neil Roberts1f020a12013-09-09 00:41:29 +0100172static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400173
174static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100175nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
176{
177 struct nested_buffer *buffer =
178 container_of(listener, struct nested_buffer, destroy_listener);
179
180 wl_signal_emit(&buffer->destroy_signal, buffer);
Neil Roberts1f020a12013-09-09 00:41:29 +0100181
182 if (buffer->parent_buffer)
183 wl_buffer_destroy(buffer->parent_buffer);
184
Neil Roberts6bf23872013-09-08 18:49:15 +0100185 free(buffer);
186}
187
188static struct nested_buffer *
189nested_buffer_from_resource(struct wl_resource *resource)
190{
191 struct nested_buffer *buffer;
192 struct wl_listener *listener;
193
194 listener =
195 wl_resource_get_destroy_listener(resource,
196 nested_buffer_destroy_handler);
197
198 if (listener)
199 return container_of(listener, struct nested_buffer,
200 destroy_listener);
201
202 buffer = zalloc(sizeof *buffer);
203 if (buffer == NULL)
204 return NULL;
205
206 buffer->resource = resource;
207 wl_signal_init(&buffer->destroy_signal);
208 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
209 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
210
211 return buffer;
212}
213
214static void
215nested_buffer_reference_handle_destroy(struct wl_listener *listener,
216 void *data)
217{
218 struct nested_buffer_reference *ref =
219 container_of(listener, struct nested_buffer_reference,
220 destroy_listener);
221
222 assert((struct nested_buffer *)data == ref->buffer);
223 ref->buffer = NULL;
224}
225
226static void
227nested_buffer_reference(struct nested_buffer_reference *ref,
228 struct nested_buffer *buffer)
229{
230 if (buffer == ref->buffer)
231 return;
232
233 if (ref->buffer) {
234 ref->buffer->busy_count--;
235 if (ref->buffer->busy_count == 0) {
236 assert(wl_resource_get_client(ref->buffer->resource));
237 wl_resource_queue_event(ref->buffer->resource,
238 WL_BUFFER_RELEASE);
239 }
240 wl_list_remove(&ref->destroy_listener.link);
241 }
242
243 if (buffer) {
244 buffer->busy_count++;
245 wl_signal_add(&buffer->destroy_signal,
246 &ref->destroy_listener);
247
248 ref->destroy_listener.notify =
249 nested_buffer_reference_handle_destroy;
250 }
251
252 ref->buffer = buffer;
253}
254
255static void
Neil Robertsf9b25412013-09-09 15:13:09 +0100256flush_surface_frame_callback_list(struct nested_surface *surface,
257 uint32_t time)
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400258{
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400259 struct nested_frame_callback *nc, *next;
260
Neil Robertsf9b25412013-09-09 15:13:09 +0100261 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400262 wl_callback_send_done(nc->resource, time);
263 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400264 }
Neil Robertsf9b25412013-09-09 15:13:09 +0100265 wl_list_init(&surface->frame_callback_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400266
267 /* FIXME: toytoolkit need a pre-block handler where we can
268 * call this. */
Neil Robertsf9b25412013-09-09 15:13:09 +0100269 wl_display_flush_clients(surface->nested->child_display);
270}
271
272static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400273redraw_handler(struct widget *widget, void *data)
274{
275 struct nested *nested = data;
276 cairo_surface_t *surface;
277 cairo_t *cr;
278 struct rectangle allocation;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400279
280 widget_get_allocation(nested->widget, &allocation);
281
282 surface = window_get_surface(nested->window);
283
284 cr = cairo_create(surface);
285 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
286 cairo_rectangle(cr,
287 allocation.x,
288 allocation.y,
289 allocation.width,
290 allocation.height);
291 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
292 cairo_fill(cr);
293
Neil Roberts47b87d52013-09-08 20:52:36 +0100294 nested->renderer->render_clients(nested, cr);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400295
296 cairo_destroy(cr);
297
298 cairo_surface_destroy(surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400299}
300
301static void
302keyboard_focus_handler(struct window *window,
303 struct input *device, void *data)
304{
305 struct nested *nested = data;
306
307 window_schedule_redraw(nested->window);
308}
309
310static void
311handle_child_data(struct task *task, uint32_t events)
312{
313 struct nested *nested = container_of(task, struct nested, child_task);
314 struct wl_event_loop *loop;
315
316 loop = wl_display_get_event_loop(nested->child_display);
317
318 wl_event_loop_dispatch(loop, -1);
319 wl_display_flush_clients(nested->child_display);
320}
321
322struct nested_client {
323 struct wl_client *client;
324 pid_t pid;
325};
326
327static struct nested_client *
328launch_client(struct nested *nested, const char *path)
329{
330 int sv[2];
331 pid_t pid;
332 struct nested_client *client;
333
334 client = malloc(sizeof *client);
335 if (client == NULL)
336 return NULL;
337
338 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
339 fprintf(stderr, "launch_client: "
340 "socketpair failed while launching '%s': %m\n",
341 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700342 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400343 return NULL;
344 }
345
346 pid = fork();
347 if (pid == -1) {
348 close(sv[0]);
349 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700350 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400351 fprintf(stderr, "launch_client: "
352 "fork failed while launching '%s': %m\n", path);
353 return NULL;
354 }
355
356 if (pid == 0) {
357 int clientfd;
358 char s[32];
359
360 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
361 * get a non-CLOEXEC fd to pass through exec. */
362 clientfd = dup(sv[1]);
363 if (clientfd == -1) {
364 fprintf(stderr, "compositor: dup failed: %m\n");
365 exit(-1);
366 }
367
368 snprintf(s, sizeof s, "%d", clientfd);
369 setenv("WAYLAND_SOCKET", s, 1);
370
371 execl(path, path, NULL);
372
373 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
374 path);
375 exit(-1);
376 }
377
378 close(sv[1]);
379
380 client->client = wl_client_create(nested->child_display, sv[0]);
381 if (!client->client) {
382 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700383 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400384 fprintf(stderr, "launch_client: "
385 "wl_client_create failed while launching '%s'.\n",
386 path);
387 return NULL;
388 }
389
390 client->pid = pid;
391
392 return client;
393}
394
395static void
396destroy_surface(struct wl_resource *resource)
397{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400398 struct nested_surface *surface = wl_resource_get_user_data(resource);
Neil Roberts47b87d52013-09-08 20:52:36 +0100399 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100400 struct nested_frame_callback *cb, *next;
401
402 wl_list_for_each_safe(cb, next,
Neil Robertsf9b25412013-09-09 15:13:09 +0100403 &surface->frame_callback_list, link)
404 wl_resource_destroy(cb->resource);
405
406 wl_list_for_each_safe(cb, next,
Neil Roberts15a8d342013-09-08 19:49:02 +0100407 &surface->pending.frame_callback_list, link)
408 wl_resource_destroy(cb->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400409
Neil Roberts28557662013-09-08 20:24:14 +0100410 pixman_region32_fini(&surface->pending.damage);
411
Neil Roberts47b87d52013-09-08 20:52:36 +0100412 nested->renderer->surface_fini(surface);
413
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000414 wl_list_remove(&surface->link);
415
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400416 free(surface);
417}
418
419static void
420surface_destroy(struct wl_client *client, struct wl_resource *resource)
421{
422 wl_resource_destroy(resource);
423}
424
425static void
426surface_attach(struct wl_client *client,
427 struct wl_resource *resource,
428 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
429{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400430 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400431 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100432 struct nested_buffer *buffer = NULL;
433
434 if (buffer_resource) {
435 int format;
436
437 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
438 EGL_TEXTURE_FORMAT, &format)) {
439 wl_resource_post_error(buffer_resource,
440 WL_DISPLAY_ERROR_INVALID_OBJECT,
441 "attaching non-egl wl_buffer");
442 return;
443 }
444
445 switch (format) {
446 case EGL_TEXTURE_RGB:
447 case EGL_TEXTURE_RGBA:
448 break;
449 default:
450 wl_resource_post_error(buffer_resource,
451 WL_DISPLAY_ERROR_INVALID_OBJECT,
452 "invalid format");
453 return;
454 }
455
456 buffer = nested_buffer_from_resource(buffer_resource);
457 if (buffer == NULL) {
458 wl_client_post_no_memory(client);
459 return;
460 }
461 }
462
463 if (surface->pending.buffer)
464 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
465
466 surface->pending.buffer = buffer;
467 surface->pending.newly_attached = 1;
468 if (buffer) {
469 wl_signal_add(&buffer->destroy_signal,
470 &surface->pending.buffer_destroy_listener);
471 }
472}
473
474static void
475nested_surface_attach(struct nested_surface *surface,
476 struct nested_buffer *buffer)
477{
478 struct nested *nested = surface->nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400479
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400480 if (surface->image != EGL_NO_IMAGE_KHR)
481 destroy_image(nested->egl_display, surface->image);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400482
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400483 surface->image = create_image(nested->egl_display, NULL,
Neil Roberts15a8d342013-09-08 19:49:02 +0100484 EGL_WAYLAND_BUFFER_WL, buffer->resource,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700485 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400486 if (surface->image == EGL_NO_IMAGE_KHR) {
487 fprintf(stderr, "failed to create img\n");
488 return;
489 }
490
Neil Roberts47b87d52013-09-08 20:52:36 +0100491 nested->renderer->surface_attach(surface, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400492}
493
494static void
495surface_damage(struct wl_client *client,
496 struct wl_resource *resource,
497 int32_t x, int32_t y, int32_t width, int32_t height)
498{
Neil Roberts28557662013-09-08 20:24:14 +0100499 struct nested_surface *surface = wl_resource_get_user_data(resource);
500
501 pixman_region32_union_rect(&surface->pending.damage,
502 &surface->pending.damage,
503 x, y, width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400504}
505
506static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400507destroy_frame_callback(struct wl_resource *resource)
508{
509 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
510
511 wl_list_remove(&callback->link);
512 free(callback);
513}
514
515static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400516surface_frame(struct wl_client *client,
517 struct wl_resource *resource, uint32_t id)
518{
519 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400520 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400521
522 callback = malloc(sizeof *callback);
523 if (callback == NULL) {
524 wl_resource_post_no_memory(resource);
525 return;
526 }
527
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400528 callback->resource = wl_resource_create(client,
529 &wl_callback_interface, 1, id);
530 wl_resource_set_implementation(callback->resource, NULL, callback,
531 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400532
Neil Roberts15a8d342013-09-08 19:49:02 +0100533 wl_list_insert(surface->pending.frame_callback_list.prev,
534 &callback->link);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400535}
536
537static void
538surface_set_opaque_region(struct wl_client *client,
539 struct wl_resource *resource,
540 struct wl_resource *region_resource)
541{
542 fprintf(stderr, "surface_set_opaque_region\n");
543}
544
545static void
546surface_set_input_region(struct wl_client *client,
547 struct wl_resource *resource,
548 struct wl_resource *region_resource)
549{
550 fprintf(stderr, "surface_set_input_region\n");
551}
552
553static void
554surface_commit(struct wl_client *client, struct wl_resource *resource)
555{
Neil Roberts15a8d342013-09-08 19:49:02 +0100556 struct nested_surface *surface = wl_resource_get_user_data(resource);
557 struct nested *nested = surface->nested;
558
559 /* wl_surface.attach */
560 if (surface->pending.newly_attached)
561 nested_surface_attach(surface, surface->pending.buffer);
562
563 if (surface->pending.buffer) {
564 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
565 surface->pending.buffer = NULL;
566 }
567 surface->pending.newly_attached = 0;
568
Neil Roberts28557662013-09-08 20:24:14 +0100569 /* wl_surface.damage */
Jason Ekstrandef540082014-06-26 10:37:36 -0700570 pixman_region32_clear(&surface->pending.damage);
Neil Roberts28557662013-09-08 20:24:14 +0100571
Neil Roberts15a8d342013-09-08 19:49:02 +0100572 /* wl_surface.frame */
Neil Robertsf9b25412013-09-09 15:13:09 +0100573 wl_list_insert_list(&surface->frame_callback_list,
Neil Roberts15a8d342013-09-08 19:49:02 +0100574 &surface->pending.frame_callback_list);
575 wl_list_init(&surface->pending.frame_callback_list);
576
Neil Roberts1f020a12013-09-09 00:41:29 +0100577 /* FIXME: For the subsurface renderer we don't need to
578 * actually redraw the window. However we do want to cause a
579 * commit because the subsurface is synchronized. Ideally we
580 * would just queue the commit */
Neil Roberts15a8d342013-09-08 19:49:02 +0100581 window_schedule_redraw(nested->window);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400582}
583
584static void
585surface_set_buffer_transform(struct wl_client *client,
586 struct wl_resource *resource, int transform)
587{
588 fprintf(stderr, "surface_set_buffer_transform\n");
589}
590
591static const struct wl_surface_interface surface_interface = {
592 surface_destroy,
593 surface_attach,
594 surface_damage,
595 surface_frame,
596 surface_set_opaque_region,
597 surface_set_input_region,
598 surface_commit,
599 surface_set_buffer_transform
600};
601
602static void
Neil Roberts15a8d342013-09-08 19:49:02 +0100603surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
604{
605 struct nested_surface *surface =
606 container_of(listener, struct nested_surface,
607 pending.buffer_destroy_listener);
608
609 surface->pending.buffer = NULL;
610}
611
612static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400613compositor_create_surface(struct wl_client *client,
614 struct wl_resource *resource, uint32_t id)
615{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400616 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400617 struct nested_surface *surface;
Michael Vetter2a18a522015-05-15 17:17:47 +0200618
Peter Huttererf3d62272013-08-08 11:57:05 +1000619 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400620 if (surface == NULL) {
621 wl_resource_post_no_memory(resource);
622 return;
623 }
624
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400625 surface->nested = nested;
626
Neil Robertsf9b25412013-09-09 15:13:09 +0100627 wl_list_init(&surface->frame_callback_list);
628
Neil Roberts15a8d342013-09-08 19:49:02 +0100629 wl_list_init(&surface->pending.frame_callback_list);
630 surface->pending.buffer_destroy_listener.notify =
631 surface_handle_pending_buffer_destroy;
Neil Roberts28557662013-09-08 20:24:14 +0100632 pixman_region32_init(&surface->pending.damage);
Neil Roberts15a8d342013-09-08 19:49:02 +0100633
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400634 display_acquire_window_surface(nested->display,
635 nested->window, NULL);
636
Neil Roberts47b87d52013-09-08 20:52:36 +0100637 nested->renderer->surface_init(surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400638
639 display_release_window_surface(nested->display, nested->window);
640
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400641 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400642 wl_resource_create(client, &wl_surface_interface, 1, id);
643
644 wl_resource_set_implementation(surface->resource,
645 &surface_interface, surface,
646 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400647
648 wl_list_insert(nested->surface_list.prev, &surface->link);
649}
650
651static void
652destroy_region(struct wl_resource *resource)
653{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400654 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400655
656 pixman_region32_fini(&region->region);
657 free(region);
658}
659
660static void
661region_destroy(struct wl_client *client, struct wl_resource *resource)
662{
663 wl_resource_destroy(resource);
664}
665
666static void
667region_add(struct wl_client *client, struct wl_resource *resource,
668 int32_t x, int32_t y, int32_t width, int32_t height)
669{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400670 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400671
672 pixman_region32_union_rect(&region->region, &region->region,
673 x, y, width, height);
674}
675
676static void
677region_subtract(struct wl_client *client, struct wl_resource *resource,
678 int32_t x, int32_t y, int32_t width, int32_t height)
679{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400680 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400681 pixman_region32_t rect;
682
683 pixman_region32_init_rect(&rect, x, y, width, height);
684 pixman_region32_subtract(&region->region, &region->region, &rect);
685 pixman_region32_fini(&rect);
686}
687
688static const struct wl_region_interface region_interface = {
689 region_destroy,
690 region_add,
691 region_subtract
692};
693
694static void
695compositor_create_region(struct wl_client *client,
696 struct wl_resource *resource, uint32_t id)
697{
698 struct nested_region *region;
699
700 region = malloc(sizeof *region);
701 if (region == NULL) {
702 wl_resource_post_no_memory(resource);
703 return;
704 }
705
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400706 pixman_region32_init(&region->region);
707
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400708 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400709 wl_resource_create(client, &wl_region_interface, 1, id);
710 wl_resource_set_implementation(region->resource, &region_interface,
711 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400712}
713
714static const struct wl_compositor_interface compositor_interface = {
715 compositor_create_surface,
716 compositor_create_region
717};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400718
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400719static void
720compositor_bind(struct wl_client *client,
721 void *data, uint32_t version, uint32_t id)
722{
723 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400724 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400725
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400726 resource = wl_resource_create(client, &wl_compositor_interface,
727 MIN(version, 3), id);
728 wl_resource_set_implementation(resource, &compositor_interface,
729 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400730}
731
732static int
733nested_init_compositor(struct nested *nested)
734{
735 const char *extensions;
736 struct wl_event_loop *loop;
Neil Roberts1f020a12013-09-09 00:41:29 +0100737 int use_ss_renderer = 0;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400738 int fd, ret;
739
740 wl_list_init(&nested->surface_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400741 nested->child_display = wl_display_create();
742 loop = wl_display_get_event_loop(nested->child_display);
743 fd = wl_event_loop_get_fd(loop);
744 nested->child_task.run = handle_child_data;
745 display_watch_fd(nested->display, fd,
746 EPOLLIN, &nested->child_task);
747
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400748 if (!wl_global_create(nested->child_display,
749 &wl_compositor_interface, 1,
750 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400751 return -1;
752
753 wl_display_init_shm(nested->child_display);
754
755 nested->egl_display = display_get_egl_display(nested->display);
756 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
757 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
758 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
759 return -1;
760 }
761
762 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
763 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
764 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
765 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
766 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
767 image_target_texture_2d =
768 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
769
770 ret = bind_display(nested->egl_display, nested->child_display);
771 if (!ret) {
772 fprintf(stderr, "failed to bind wl_display\n");
773 return -1;
774 }
775
Neil Roberts1f020a12013-09-09 00:41:29 +0100776 if (display_has_subcompositor(nested->display)) {
777 const char *func = "eglCreateWaylandBufferFromImageWL";
778 const char *ext = "EGL_WL_create_wayland_buffer_from_image";
779
780 if (strstr(extensions, ext)) {
781 create_wayland_buffer_from_image =
782 (void *) eglGetProcAddress(func);
783 use_ss_renderer = 1;
784 }
785 }
786
Neil Robertsa5059eb2013-09-09 00:59:35 +0100787 if (option_blit)
788 use_ss_renderer = 0;
789
Neil Roberts1f020a12013-09-09 00:41:29 +0100790 if (use_ss_renderer) {
791 printf("Using subsurfaces to render client surfaces\n");
792 nested->renderer = &nested_ss_renderer;
793 } else {
794 printf("Using local compositing with blits to "
795 "render client surfaces\n");
796 nested->renderer = &nested_blit_renderer;
797 }
Neil Roberts47b87d52013-09-08 20:52:36 +0100798
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400799 return 0;
800}
801
802static struct nested *
803nested_create(struct display *display)
804{
805 struct nested *nested;
806
Peter Huttererf3d62272013-08-08 11:57:05 +1000807 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400808 if (nested == NULL)
809 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400810
811 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500812 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400813 window_set_title(nested->window, "Wayland Nested");
814 nested->display = display;
815
816 window_set_user_data(nested->window, nested);
817 widget_set_redraw_handler(nested->widget, redraw_handler);
818 window_set_keyboard_focus_handler(nested->window,
819 keyboard_focus_handler);
820
821 nested_init_compositor(nested);
822
823 widget_schedule_resize(nested->widget, 400, 400);
824
825 return nested;
826}
827
828static void
829nested_destroy(struct nested *nested)
830{
831 widget_destroy(nested->widget);
832 window_destroy(nested->window);
833 free(nested);
834}
835
Neil Roberts1f020a12013-09-09 00:41:29 +0100836/*** blit renderer ***/
837
Neil Roberts47b87d52013-09-08 20:52:36 +0100838static void
839blit_surface_init(struct nested_surface *surface)
840{
841 struct nested_blit_surface *blit_surface =
U. Artie Eoff5cda4e32014-01-15 11:13:38 -0800842 xzalloc(sizeof *blit_surface);
Neil Roberts47b87d52013-09-08 20:52:36 +0100843
844 glGenTextures(1, &blit_surface->texture);
845 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
846 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
847 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
848 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
849 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
850
851 surface->renderer_data = blit_surface;
852}
853
854static void
855blit_surface_fini(struct nested_surface *surface)
856{
857 struct nested_blit_surface *blit_surface = surface->renderer_data;
858
859 nested_buffer_reference(&blit_surface->buffer_ref, NULL);
860
861 glDeleteTextures(1, &blit_surface->texture);
862
863 free(blit_surface);
864}
865
866static void
867blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
868{
869 struct nested *nested = data;
870 struct nested_surface *surface;
871
872 wl_list_for_each(surface, &nested->surface_list, link)
873 flush_surface_frame_callback_list(surface, time);
874
875 if (callback)
876 wl_callback_destroy(callback);
877}
878
879static const struct wl_callback_listener blit_frame_listener = {
880 blit_frame_callback
881};
882
883static void
884blit_render_clients(struct nested *nested,
885 cairo_t *cr)
886{
887 struct nested_surface *s;
888 struct rectangle allocation;
889 struct wl_callback *callback;
890
891 widget_get_allocation(nested->widget, &allocation);
892
893 wl_list_for_each(s, &nested->surface_list, link) {
894 struct nested_blit_surface *blit_surface = s->renderer_data;
895
896 display_acquire_window_surface(nested->display,
897 nested->window, NULL);
898
899 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
900 image_target_texture_2d(GL_TEXTURE_2D, s->image);
901
902 display_release_window_surface(nested->display,
903 nested->window);
904
905 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
906 cairo_set_source_surface(cr, blit_surface->cairo_surface,
907 allocation.x + 10,
908 allocation.y + 10);
909 cairo_rectangle(cr, allocation.x + 10,
910 allocation.y + 10,
911 allocation.width - 10,
912 allocation.height - 10);
913
914 cairo_fill(cr);
915 }
916
917 callback = wl_surface_frame(window_get_wl_surface(nested->window));
918 wl_callback_add_listener(callback, &blit_frame_listener, nested);
919}
920
921static void
922blit_surface_attach(struct nested_surface *surface,
923 struct nested_buffer *buffer)
924{
925 struct nested *nested = surface->nested;
926 struct nested_blit_surface *blit_surface = surface->renderer_data;
927 EGLint width, height;
928 cairo_device_t *device;
929
930 nested_buffer_reference(&blit_surface->buffer_ref, buffer);
931
932 if (blit_surface->cairo_surface)
933 cairo_surface_destroy(blit_surface->cairo_surface);
934
935 query_buffer(nested->egl_display, (void *) buffer->resource,
936 EGL_WIDTH, &width);
937 query_buffer(nested->egl_display, (void *) buffer->resource,
938 EGL_HEIGHT, &height);
939
940 device = display_get_cairo_device(nested->display);
941 blit_surface->cairo_surface =
942 cairo_gl_surface_create_for_texture(device,
943 CAIRO_CONTENT_COLOR_ALPHA,
944 blit_surface->texture,
945 width, height);
946}
947
948static const struct nested_renderer
949nested_blit_renderer = {
950 .surface_init = blit_surface_init,
951 .surface_fini = blit_surface_fini,
952 .render_clients = blit_render_clients,
953 .surface_attach = blit_surface_attach
954};
955
Neil Roberts1f020a12013-09-09 00:41:29 +0100956/*** subsurface renderer ***/
957
958static void
959ss_surface_init(struct nested_surface *surface)
960{
961 struct nested *nested = surface->nested;
962 struct wl_compositor *compositor =
963 display_get_compositor(nested->display);
964 struct nested_ss_surface *ss_surface =
U. Artie Eoff5cda4e32014-01-15 11:13:38 -0800965 xzalloc(sizeof *ss_surface);
Neil Roberts1f020a12013-09-09 00:41:29 +0100966 struct rectangle allocation;
967 struct wl_region *region;
968
969 ss_surface->widget =
970 window_add_subsurface(nested->window,
971 nested,
972 SUBSURFACE_SYNCHRONIZED);
973
Neil Roberts40d02282014-02-24 19:07:08 +0000974 widget_set_use_cairo(ss_surface->widget, 0);
975
Neil Roberts1f020a12013-09-09 00:41:29 +0100976 ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
977 ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
978
979 /* The toy toolkit gets confused about the pointer position
980 * when it gets motion events for a subsurface so we'll just
981 * disable input on it */
982 region = wl_compositor_create_region(compositor);
983 wl_surface_set_input_region(ss_surface->surface, region);
984 wl_region_destroy(region);
985
986 widget_get_allocation(nested->widget, &allocation);
987 wl_subsurface_set_position(ss_surface->subsurface,
988 allocation.x + 10,
989 allocation.y + 10);
990
991 surface->renderer_data = ss_surface;
992}
993
994static void
995ss_surface_fini(struct nested_surface *surface)
996{
997 struct nested_ss_surface *ss_surface = surface->renderer_data;
998
999 widget_destroy(ss_surface->widget);
1000
1001 if (ss_surface->frame_callback)
1002 wl_callback_destroy(ss_surface->frame_callback);
1003
1004 free(ss_surface);
1005}
1006
1007static void
1008ss_render_clients(struct nested *nested,
1009 cairo_t *cr)
1010{
1011 /* The clients are composited by the parent compositor so we
1012 * don't need to do anything here */
1013}
1014
1015static void
1016ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
1017{
1018 struct nested_buffer *buffer = data;
1019
1020 nested_buffer_reference(&buffer->parent_ref, NULL);
1021}
1022
1023static struct wl_buffer_listener ss_buffer_listener = {
1024 ss_buffer_release
1025};
1026
1027static void
1028ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
1029{
1030 struct nested_surface *surface = data;
1031 struct nested_ss_surface *ss_surface = surface->renderer_data;
1032
1033 flush_surface_frame_callback_list(surface, time);
1034
1035 if (callback)
1036 wl_callback_destroy(callback);
1037
1038 ss_surface->frame_callback = NULL;
1039}
1040
1041static const struct wl_callback_listener ss_frame_listener = {
1042 ss_frame_callback
1043};
1044
1045static void
1046ss_surface_attach(struct nested_surface *surface,
1047 struct nested_buffer *buffer)
1048{
1049 struct nested *nested = surface->nested;
1050 struct nested_ss_surface *ss_surface = surface->renderer_data;
1051 struct wl_buffer *parent_buffer;
1052 const pixman_box32_t *rects;
1053 int n_rects, i;
1054
1055 if (buffer) {
1056 /* Create a representation of the buffer in the parent
1057 * compositor if we haven't already */
1058 if (buffer->parent_buffer == NULL) {
1059 EGLDisplay *edpy = nested->egl_display;
1060 EGLImageKHR image = surface->image;
1061
1062 buffer->parent_buffer =
1063 create_wayland_buffer_from_image(edpy, image);
1064
1065 wl_buffer_add_listener(buffer->parent_buffer,
1066 &ss_buffer_listener,
1067 buffer);
1068 }
1069
1070 parent_buffer = buffer->parent_buffer;
1071
1072 /* We'll take a reference to the buffer while the parent
1073 * compositor is using it so that we won't report the release
1074 * event until the parent has also finished with it */
1075 nested_buffer_reference(&buffer->parent_ref, buffer);
1076 } else {
1077 parent_buffer = NULL;
1078 }
1079
1080 wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
1081
1082 rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
1083
1084 for (i = 0; i < n_rects; i++) {
1085 const pixman_box32_t *rect = rects + i;
1086 wl_surface_damage(ss_surface->surface,
1087 rect->x1,
1088 rect->y1,
1089 rect->x2 - rect->x1,
1090 rect->y2 - rect->y1);
1091 }
1092
1093 if (ss_surface->frame_callback)
1094 wl_callback_destroy(ss_surface->frame_callback);
1095
1096 ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
1097 wl_callback_add_listener(ss_surface->frame_callback,
1098 &ss_frame_listener,
1099 surface);
1100
1101 wl_surface_commit(ss_surface->surface);
1102}
1103
1104static const struct nested_renderer
1105nested_ss_renderer = {
1106 .surface_init = ss_surface_init,
1107 .surface_fini = ss_surface_fini,
1108 .render_clients = ss_render_clients,
1109 .surface_attach = ss_surface_attach
1110};
1111
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001112int
1113main(int argc, char *argv[])
1114{
1115 struct display *display;
1116 struct nested *nested;
1117
Bill Spitzak6df71aa2014-08-08 12:59:52 -07001118 if (parse_options(nested_options,
1119 ARRAY_LENGTH(nested_options), &argc, argv) > 1) {
1120 printf("Usage: %s [OPTIONS]\n --blit or -b\n", argv[0]);
1121 exit(1);
1122 }
Neil Robertsa5059eb2013-09-09 00:59:35 +01001123
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001124 display = display_create(&argc, argv);
1125 if (display == NULL) {
1126 fprintf(stderr, "failed to create display: %m\n");
1127 return -1;
1128 }
1129
1130 nested = nested_create(display);
1131
Kristian Høgsbergcb61dcf2013-08-07 09:50:12 -07001132 launch_client(nested, "weston-nested-client");
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001133
1134 display_run(display);
1135
1136 nested_destroy(nested);
1137 display_destroy(display);
1138
1139 return 0;
1140}