blob: e9070e9bbccb6f8f954589db47d01b584ae5d067 [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"
U. Artie Eoff2dd10e02016-04-22 13:11:12 -070050#include "shared/xalloc.h"
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040051#include "window.h"
52
Emil Velikov885a9fe2016-07-04 15:27:13 +010053#include "weston-egl-ext.h"
Kristian Høgsbergc2010b32013-12-17 10:40:01 -080054
Kristian Høgsbergc2010b32013-12-17 10:40:01 -080055
Neil Robertsa5059eb2013-09-09 00:59:35 +010056static int option_blit;
57
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040058struct nested {
59 struct display *display;
60 struct window *window;
61 struct widget *widget;
62 struct wl_display *child_display;
63 struct task child_task;
64
65 EGLDisplay egl_display;
66 struct program *texture_program;
67
68 struct wl_list surface_list;
Neil Roberts47b87d52013-09-08 20:52:36 +010069
70 const struct nested_renderer *renderer;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040071};
72
73struct nested_region {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040074 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040075 pixman_region32_t region;
76};
77
Neil Roberts1f020a12013-09-09 00:41:29 +010078struct nested_buffer_reference {
79 struct nested_buffer *buffer;
80 struct wl_listener destroy_listener;
81};
82
Neil Roberts6bf23872013-09-08 18:49:15 +010083struct nested_buffer {
84 struct wl_resource *resource;
85 struct wl_signal destroy_signal;
86 struct wl_listener destroy_listener;
87 uint32_t busy_count;
Neil Roberts6bf23872013-09-08 18:49:15 +010088
Neil Roberts1f020a12013-09-09 00:41:29 +010089 /* A buffer in the parent compositor representing the same
90 * data. This is created on-demand when the subsurface
91 * renderer is used */
92 struct wl_buffer *parent_buffer;
93 /* This reference is used to mark when the parent buffer has
94 * been attached to the subsurface. It will be unrefenced when
95 * we receive a buffer release event. That way we won't inform
96 * the client that the buffer is free until the parent
97 * compositor is also finished with it */
98 struct nested_buffer_reference parent_ref;
Neil Roberts6bf23872013-09-08 18:49:15 +010099};
100
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400101struct nested_surface {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400102 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400103 struct nested *nested;
104 EGLImageKHR *image;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400105 struct wl_list link;
Neil Roberts15a8d342013-09-08 19:49:02 +0100106
Neil Robertsf9b25412013-09-09 15:13:09 +0100107 struct wl_list frame_callback_list;
108
Neil Roberts15a8d342013-09-08 19:49:02 +0100109 struct {
110 /* wl_surface.attach */
111 int newly_attached;
112 struct nested_buffer *buffer;
113 struct wl_listener buffer_destroy_listener;
114
115 /* wl_surface.frame */
116 struct wl_list frame_callback_list;
Neil Roberts28557662013-09-08 20:24:14 +0100117
118 /* wl_surface.damage */
119 pixman_region32_t damage;
Neil Roberts15a8d342013-09-08 19:49:02 +0100120 } pending;
Neil Roberts47b87d52013-09-08 20:52:36 +0100121
122 void *renderer_data;
123};
124
125/* Data used for the blit renderer */
126struct nested_blit_surface {
127 struct nested_buffer_reference buffer_ref;
128 GLuint texture;
129 cairo_surface_t *cairo_surface;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400130};
131
Neil Roberts1f020a12013-09-09 00:41:29 +0100132/* Data used for the subsurface renderer */
133struct nested_ss_surface {
134 struct widget *widget;
135 struct wl_surface *surface;
136 struct wl_subsurface *subsurface;
137 struct wl_callback *frame_callback;
138};
139
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400140struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400141 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400142 struct wl_list link;
143};
144
Neil Roberts47b87d52013-09-08 20:52:36 +0100145struct nested_renderer {
146 void (* surface_init)(struct nested_surface *surface);
147 void (* surface_fini)(struct nested_surface *surface);
148 void (* render_clients)(struct nested *nested, cairo_t *cr);
149 void (* surface_attach)(struct nested_surface *surface,
150 struct nested_buffer *buffer);
151};
152
Neil Robertsa5059eb2013-09-09 00:59:35 +0100153static const struct weston_option nested_options[] = {
154 { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
155};
156
Neil Roberts47b87d52013-09-08 20:52:36 +0100157static const struct nested_renderer nested_blit_renderer;
Neil Roberts1f020a12013-09-09 00:41:29 +0100158static const struct nested_renderer nested_ss_renderer;
Neil Roberts47b87d52013-09-08 20:52:36 +0100159
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400160static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
161static PFNEGLCREATEIMAGEKHRPROC create_image;
162static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
163static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
164static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
165static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
Neil Roberts1f020a12013-09-09 00:41:29 +0100166static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400167
168static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100169nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
170{
171 struct nested_buffer *buffer =
172 container_of(listener, struct nested_buffer, destroy_listener);
173
174 wl_signal_emit(&buffer->destroy_signal, buffer);
Neil Roberts1f020a12013-09-09 00:41:29 +0100175
176 if (buffer->parent_buffer)
177 wl_buffer_destroy(buffer->parent_buffer);
178
Neil Roberts6bf23872013-09-08 18:49:15 +0100179 free(buffer);
180}
181
182static struct nested_buffer *
183nested_buffer_from_resource(struct wl_resource *resource)
184{
185 struct nested_buffer *buffer;
186 struct wl_listener *listener;
187
188 listener =
189 wl_resource_get_destroy_listener(resource,
190 nested_buffer_destroy_handler);
191
192 if (listener)
193 return container_of(listener, struct nested_buffer,
194 destroy_listener);
195
196 buffer = zalloc(sizeof *buffer);
197 if (buffer == NULL)
198 return NULL;
199
200 buffer->resource = resource;
201 wl_signal_init(&buffer->destroy_signal);
202 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
203 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
204
205 return buffer;
206}
207
208static void
209nested_buffer_reference_handle_destroy(struct wl_listener *listener,
210 void *data)
211{
212 struct nested_buffer_reference *ref =
213 container_of(listener, struct nested_buffer_reference,
214 destroy_listener);
215
216 assert((struct nested_buffer *)data == ref->buffer);
217 ref->buffer = NULL;
218}
219
220static void
221nested_buffer_reference(struct nested_buffer_reference *ref,
222 struct nested_buffer *buffer)
223{
224 if (buffer == ref->buffer)
225 return;
226
227 if (ref->buffer) {
228 ref->buffer->busy_count--;
229 if (ref->buffer->busy_count == 0) {
230 assert(wl_resource_get_client(ref->buffer->resource));
231 wl_resource_queue_event(ref->buffer->resource,
232 WL_BUFFER_RELEASE);
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
249static void
Neil Robertsf9b25412013-09-09 15:13:09 +0100250flush_surface_frame_callback_list(struct nested_surface *surface,
251 uint32_t time)
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400252{
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400253 struct nested_frame_callback *nc, *next;
254
Neil Robertsf9b25412013-09-09 15:13:09 +0100255 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400256 wl_callback_send_done(nc->resource, time);
257 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400258 }
Neil Robertsf9b25412013-09-09 15:13:09 +0100259 wl_list_init(&surface->frame_callback_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400260
261 /* FIXME: toytoolkit need a pre-block handler where we can
262 * call this. */
Neil Robertsf9b25412013-09-09 15:13:09 +0100263 wl_display_flush_clients(surface->nested->child_display);
264}
265
266static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400267redraw_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;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400273
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
Neil Roberts47b87d52013-09-08 20:52:36 +0100288 nested->renderer->render_clients(nested, cr);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400289
290 cairo_destroy(cr);
291
292 cairo_surface_destroy(surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400293}
294
295static void
296keyboard_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
304static void
305handle_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
316struct nested_client {
317 struct wl_client *client;
318 pid_t pid;
319};
320
321static struct nested_client *
322launch_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': %m\n",
335 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700336 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400337 return NULL;
338 }
339
340 pid = fork();
341 if (pid == -1) {
342 close(sv[0]);
343 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700344 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400345 fprintf(stderr, "launch_client: "
346 "fork failed while launching '%s': %m\n", path);
347 return NULL;
348 }
349
350 if (pid == 0) {
351 int clientfd;
352 char s[32];
353
354 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
355 * get a non-CLOEXEC fd to pass through exec. */
356 clientfd = dup(sv[1]);
357 if (clientfd == -1) {
358 fprintf(stderr, "compositor: dup failed: %m\n");
359 exit(-1);
360 }
361
362 snprintf(s, sizeof s, "%d", clientfd);
363 setenv("WAYLAND_SOCKET", s, 1);
364
365 execl(path, path, NULL);
366
367 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
368 path);
369 exit(-1);
370 }
371
372 close(sv[1]);
373
374 client->client = wl_client_create(nested->child_display, sv[0]);
375 if (!client->client) {
376 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700377 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400378 fprintf(stderr, "launch_client: "
379 "wl_client_create failed while launching '%s'.\n",
380 path);
381 return NULL;
382 }
383
384 client->pid = pid;
385
386 return client;
387}
388
389static void
390destroy_surface(struct wl_resource *resource)
391{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400392 struct nested_surface *surface = wl_resource_get_user_data(resource);
Neil Roberts47b87d52013-09-08 20:52:36 +0100393 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100394 struct nested_frame_callback *cb, *next;
395
396 wl_list_for_each_safe(cb, next,
Neil Robertsf9b25412013-09-09 15:13:09 +0100397 &surface->frame_callback_list, link)
398 wl_resource_destroy(cb->resource);
399
400 wl_list_for_each_safe(cb, next,
Neil Roberts15a8d342013-09-08 19:49:02 +0100401 &surface->pending.frame_callback_list, link)
402 wl_resource_destroy(cb->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400403
Neil Roberts28557662013-09-08 20:24:14 +0100404 pixman_region32_fini(&surface->pending.damage);
405
Neil Roberts47b87d52013-09-08 20:52:36 +0100406 nested->renderer->surface_fini(surface);
407
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000408 wl_list_remove(&surface->link);
409
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400410 free(surface);
411}
412
413static void
414surface_destroy(struct wl_client *client, struct wl_resource *resource)
415{
416 wl_resource_destroy(resource);
417}
418
419static void
420surface_attach(struct wl_client *client,
421 struct wl_resource *resource,
422 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
423{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400424 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400425 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100426 struct nested_buffer *buffer = NULL;
427
428 if (buffer_resource) {
429 int format;
430
431 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
432 EGL_TEXTURE_FORMAT, &format)) {
433 wl_resource_post_error(buffer_resource,
434 WL_DISPLAY_ERROR_INVALID_OBJECT,
435 "attaching non-egl wl_buffer");
436 return;
437 }
438
439 switch (format) {
440 case EGL_TEXTURE_RGB:
441 case EGL_TEXTURE_RGBA:
442 break;
443 default:
444 wl_resource_post_error(buffer_resource,
445 WL_DISPLAY_ERROR_INVALID_OBJECT,
446 "invalid format");
447 return;
448 }
449
450 buffer = nested_buffer_from_resource(buffer_resource);
451 if (buffer == NULL) {
452 wl_client_post_no_memory(client);
453 return;
454 }
455 }
456
457 if (surface->pending.buffer)
458 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
459
460 surface->pending.buffer = buffer;
461 surface->pending.newly_attached = 1;
462 if (buffer) {
463 wl_signal_add(&buffer->destroy_signal,
464 &surface->pending.buffer_destroy_listener);
465 }
466}
467
468static void
469nested_surface_attach(struct nested_surface *surface,
470 struct nested_buffer *buffer)
471{
472 struct nested *nested = surface->nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400473
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400474 if (surface->image != EGL_NO_IMAGE_KHR)
475 destroy_image(nested->egl_display, surface->image);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400476
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400477 surface->image = create_image(nested->egl_display, NULL,
Neil Roberts15a8d342013-09-08 19:49:02 +0100478 EGL_WAYLAND_BUFFER_WL, buffer->resource,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700479 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400480 if (surface->image == EGL_NO_IMAGE_KHR) {
481 fprintf(stderr, "failed to create img\n");
482 return;
483 }
484
Neil Roberts47b87d52013-09-08 20:52:36 +0100485 nested->renderer->surface_attach(surface, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400486}
487
488static void
489surface_damage(struct wl_client *client,
490 struct wl_resource *resource,
491 int32_t x, int32_t y, int32_t width, int32_t height)
492{
Neil Roberts28557662013-09-08 20:24:14 +0100493 struct nested_surface *surface = wl_resource_get_user_data(resource);
494
495 pixman_region32_union_rect(&surface->pending.damage,
496 &surface->pending.damage,
497 x, y, width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400498}
499
500static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400501destroy_frame_callback(struct wl_resource *resource)
502{
503 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
504
505 wl_list_remove(&callback->link);
506 free(callback);
507}
508
509static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400510surface_frame(struct wl_client *client,
511 struct wl_resource *resource, uint32_t id)
512{
513 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400514 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400515
516 callback = malloc(sizeof *callback);
517 if (callback == NULL) {
518 wl_resource_post_no_memory(resource);
519 return;
520 }
521
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400522 callback->resource = wl_resource_create(client,
523 &wl_callback_interface, 1, id);
524 wl_resource_set_implementation(callback->resource, NULL, callback,
525 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400526
Neil Roberts15a8d342013-09-08 19:49:02 +0100527 wl_list_insert(surface->pending.frame_callback_list.prev,
528 &callback->link);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400529}
530
531static void
532surface_set_opaque_region(struct wl_client *client,
533 struct wl_resource *resource,
534 struct wl_resource *region_resource)
535{
536 fprintf(stderr, "surface_set_opaque_region\n");
537}
538
539static void
540surface_set_input_region(struct wl_client *client,
541 struct wl_resource *resource,
542 struct wl_resource *region_resource)
543{
544 fprintf(stderr, "surface_set_input_region\n");
545}
546
547static void
548surface_commit(struct wl_client *client, struct wl_resource *resource)
549{
Neil Roberts15a8d342013-09-08 19:49:02 +0100550 struct nested_surface *surface = wl_resource_get_user_data(resource);
551 struct nested *nested = surface->nested;
552
553 /* wl_surface.attach */
554 if (surface->pending.newly_attached)
555 nested_surface_attach(surface, surface->pending.buffer);
556
557 if (surface->pending.buffer) {
558 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
559 surface->pending.buffer = NULL;
560 }
561 surface->pending.newly_attached = 0;
562
Neil Roberts28557662013-09-08 20:24:14 +0100563 /* wl_surface.damage */
Jason Ekstrandef540082014-06-26 10:37:36 -0700564 pixman_region32_clear(&surface->pending.damage);
Neil Roberts28557662013-09-08 20:24:14 +0100565
Neil Roberts15a8d342013-09-08 19:49:02 +0100566 /* wl_surface.frame */
Neil Robertsf9b25412013-09-09 15:13:09 +0100567 wl_list_insert_list(&surface->frame_callback_list,
Neil Roberts15a8d342013-09-08 19:49:02 +0100568 &surface->pending.frame_callback_list);
569 wl_list_init(&surface->pending.frame_callback_list);
570
Neil Roberts1f020a12013-09-09 00:41:29 +0100571 /* FIXME: For the subsurface renderer we don't need to
572 * actually redraw the window. However we do want to cause a
573 * commit because the subsurface is synchronized. Ideally we
574 * would just queue the commit */
Neil Roberts15a8d342013-09-08 19:49:02 +0100575 window_schedule_redraw(nested->window);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400576}
577
578static void
579surface_set_buffer_transform(struct wl_client *client,
580 struct wl_resource *resource, int transform)
581{
582 fprintf(stderr, "surface_set_buffer_transform\n");
583}
584
585static const struct wl_surface_interface surface_interface = {
586 surface_destroy,
587 surface_attach,
588 surface_damage,
589 surface_frame,
590 surface_set_opaque_region,
591 surface_set_input_region,
592 surface_commit,
593 surface_set_buffer_transform
594};
595
596static void
Neil Roberts15a8d342013-09-08 19:49:02 +0100597surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
598{
599 struct nested_surface *surface =
600 container_of(listener, struct nested_surface,
601 pending.buffer_destroy_listener);
602
603 surface->pending.buffer = NULL;
604}
605
606static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400607compositor_create_surface(struct wl_client *client,
608 struct wl_resource *resource, uint32_t id)
609{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400610 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400611 struct nested_surface *surface;
Michael Vetter2a18a522015-05-15 17:17:47 +0200612
Peter Huttererf3d62272013-08-08 11:57:05 +1000613 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400614 if (surface == NULL) {
615 wl_resource_post_no_memory(resource);
616 return;
617 }
618
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400619 surface->nested = nested;
620
Neil Robertsf9b25412013-09-09 15:13:09 +0100621 wl_list_init(&surface->frame_callback_list);
622
Neil Roberts15a8d342013-09-08 19:49:02 +0100623 wl_list_init(&surface->pending.frame_callback_list);
624 surface->pending.buffer_destroy_listener.notify =
625 surface_handle_pending_buffer_destroy;
Neil Roberts28557662013-09-08 20:24:14 +0100626 pixman_region32_init(&surface->pending.damage);
Neil Roberts15a8d342013-09-08 19:49:02 +0100627
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400628 display_acquire_window_surface(nested->display,
629 nested->window, NULL);
630
Neil Roberts47b87d52013-09-08 20:52:36 +0100631 nested->renderer->surface_init(surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400632
633 display_release_window_surface(nested->display, nested->window);
634
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400635 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400636 wl_resource_create(client, &wl_surface_interface, 1, id);
637
638 wl_resource_set_implementation(surface->resource,
639 &surface_interface, surface,
640 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400641
642 wl_list_insert(nested->surface_list.prev, &surface->link);
643}
644
645static void
646destroy_region(struct wl_resource *resource)
647{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400648 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400649
650 pixman_region32_fini(&region->region);
651 free(region);
652}
653
654static void
655region_destroy(struct wl_client *client, struct wl_resource *resource)
656{
657 wl_resource_destroy(resource);
658}
659
660static void
661region_add(struct wl_client *client, struct wl_resource *resource,
662 int32_t x, int32_t y, int32_t width, int32_t height)
663{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400664 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400665
666 pixman_region32_union_rect(&region->region, &region->region,
667 x, y, width, height);
668}
669
670static void
671region_subtract(struct wl_client *client, struct wl_resource *resource,
672 int32_t x, int32_t y, int32_t width, int32_t height)
673{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400674 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400675 pixman_region32_t rect;
676
677 pixman_region32_init_rect(&rect, x, y, width, height);
678 pixman_region32_subtract(&region->region, &region->region, &rect);
679 pixman_region32_fini(&rect);
680}
681
682static const struct wl_region_interface region_interface = {
683 region_destroy,
684 region_add,
685 region_subtract
686};
687
688static void
689compositor_create_region(struct wl_client *client,
690 struct wl_resource *resource, uint32_t id)
691{
692 struct nested_region *region;
693
694 region = malloc(sizeof *region);
695 if (region == NULL) {
696 wl_resource_post_no_memory(resource);
697 return;
698 }
699
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400700 pixman_region32_init(&region->region);
701
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400702 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400703 wl_resource_create(client, &wl_region_interface, 1, id);
704 wl_resource_set_implementation(region->resource, &region_interface,
705 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400706}
707
708static const struct wl_compositor_interface compositor_interface = {
709 compositor_create_surface,
710 compositor_create_region
711};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400712
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400713static void
714compositor_bind(struct wl_client *client,
715 void *data, uint32_t version, uint32_t id)
716{
717 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400718 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400719
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400720 resource = wl_resource_create(client, &wl_compositor_interface,
721 MIN(version, 3), id);
722 wl_resource_set_implementation(resource, &compositor_interface,
723 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400724}
725
726static int
727nested_init_compositor(struct nested *nested)
728{
729 const char *extensions;
730 struct wl_event_loop *loop;
Neil Roberts1f020a12013-09-09 00:41:29 +0100731 int use_ss_renderer = 0;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400732 int fd, ret;
733
734 wl_list_init(&nested->surface_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400735 nested->child_display = wl_display_create();
736 loop = wl_display_get_event_loop(nested->child_display);
737 fd = wl_event_loop_get_fd(loop);
738 nested->child_task.run = handle_child_data;
739 display_watch_fd(nested->display, fd,
740 EPOLLIN, &nested->child_task);
741
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400742 if (!wl_global_create(nested->child_display,
743 &wl_compositor_interface, 1,
744 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400745 return -1;
746
747 wl_display_init_shm(nested->child_display);
748
749 nested->egl_display = display_get_egl_display(nested->display);
750 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
Eric Engestromc05ee892017-09-11 13:52:28 +0100751 if (!weston_check_egl_extension(extensions, "EGL_WL_bind_wayland_display")) {
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400752 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
753 return -1;
754 }
755
756 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
757 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
758 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
759 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
760 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
761 image_target_texture_2d =
762 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
763
764 ret = bind_display(nested->egl_display, nested->child_display);
765 if (!ret) {
766 fprintf(stderr, "failed to bind wl_display\n");
767 return -1;
768 }
769
Neil Roberts1f020a12013-09-09 00:41:29 +0100770 if (display_has_subcompositor(nested->display)) {
771 const char *func = "eglCreateWaylandBufferFromImageWL";
772 const char *ext = "EGL_WL_create_wayland_buffer_from_image";
773
Emil Velikovce5b6142016-07-04 15:34:20 +0100774 if (weston_check_egl_extension(extensions, ext)) {
Neil Roberts1f020a12013-09-09 00:41:29 +0100775 create_wayland_buffer_from_image =
776 (void *) eglGetProcAddress(func);
777 use_ss_renderer = 1;
778 }
779 }
780
Neil Robertsa5059eb2013-09-09 00:59:35 +0100781 if (option_blit)
782 use_ss_renderer = 0;
783
Neil Roberts1f020a12013-09-09 00:41:29 +0100784 if (use_ss_renderer) {
785 printf("Using subsurfaces to render client surfaces\n");
786 nested->renderer = &nested_ss_renderer;
787 } else {
788 printf("Using local compositing with blits to "
789 "render client surfaces\n");
790 nested->renderer = &nested_blit_renderer;
791 }
Neil Roberts47b87d52013-09-08 20:52:36 +0100792
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400793 return 0;
794}
795
796static struct nested *
797nested_create(struct display *display)
798{
799 struct nested *nested;
800
Peter Huttererf3d62272013-08-08 11:57:05 +1000801 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400802 if (nested == NULL)
803 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400804
805 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500806 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400807 window_set_title(nested->window, "Wayland Nested");
808 nested->display = display;
809
810 window_set_user_data(nested->window, nested);
811 widget_set_redraw_handler(nested->widget, redraw_handler);
812 window_set_keyboard_focus_handler(nested->window,
813 keyboard_focus_handler);
814
815 nested_init_compositor(nested);
816
817 widget_schedule_resize(nested->widget, 400, 400);
818
819 return nested;
820}
821
822static void
823nested_destroy(struct nested *nested)
824{
825 widget_destroy(nested->widget);
826 window_destroy(nested->window);
827 free(nested);
828}
829
Neil Roberts1f020a12013-09-09 00:41:29 +0100830/*** blit renderer ***/
831
Neil Roberts47b87d52013-09-08 20:52:36 +0100832static void
833blit_surface_init(struct nested_surface *surface)
834{
835 struct nested_blit_surface *blit_surface =
U. Artie Eoff5cda4e32014-01-15 11:13:38 -0800836 xzalloc(sizeof *blit_surface);
Neil Roberts47b87d52013-09-08 20:52:36 +0100837
838 glGenTextures(1, &blit_surface->texture);
839 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
840 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
841 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
842 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
843 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
844
845 surface->renderer_data = blit_surface;
846}
847
848static void
849blit_surface_fini(struct nested_surface *surface)
850{
851 struct nested_blit_surface *blit_surface = surface->renderer_data;
852
853 nested_buffer_reference(&blit_surface->buffer_ref, NULL);
854
855 glDeleteTextures(1, &blit_surface->texture);
856
857 free(blit_surface);
858}
859
860static void
861blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
862{
863 struct nested *nested = data;
864 struct nested_surface *surface;
865
866 wl_list_for_each(surface, &nested->surface_list, link)
867 flush_surface_frame_callback_list(surface, time);
868
869 if (callback)
870 wl_callback_destroy(callback);
871}
872
873static const struct wl_callback_listener blit_frame_listener = {
874 blit_frame_callback
875};
876
877static void
878blit_render_clients(struct nested *nested,
879 cairo_t *cr)
880{
881 struct nested_surface *s;
882 struct rectangle allocation;
883 struct wl_callback *callback;
884
885 widget_get_allocation(nested->widget, &allocation);
886
887 wl_list_for_each(s, &nested->surface_list, link) {
888 struct nested_blit_surface *blit_surface = s->renderer_data;
889
890 display_acquire_window_surface(nested->display,
891 nested->window, NULL);
892
893 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
894 image_target_texture_2d(GL_TEXTURE_2D, s->image);
895
896 display_release_window_surface(nested->display,
897 nested->window);
898
899 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
900 cairo_set_source_surface(cr, blit_surface->cairo_surface,
901 allocation.x + 10,
902 allocation.y + 10);
903 cairo_rectangle(cr, allocation.x + 10,
904 allocation.y + 10,
905 allocation.width - 10,
906 allocation.height - 10);
907
908 cairo_fill(cr);
909 }
910
911 callback = wl_surface_frame(window_get_wl_surface(nested->window));
912 wl_callback_add_listener(callback, &blit_frame_listener, nested);
913}
914
915static void
916blit_surface_attach(struct nested_surface *surface,
917 struct nested_buffer *buffer)
918{
919 struct nested *nested = surface->nested;
920 struct nested_blit_surface *blit_surface = surface->renderer_data;
921 EGLint width, height;
922 cairo_device_t *device;
923
924 nested_buffer_reference(&blit_surface->buffer_ref, buffer);
925
926 if (blit_surface->cairo_surface)
927 cairo_surface_destroy(blit_surface->cairo_surface);
928
929 query_buffer(nested->egl_display, (void *) buffer->resource,
930 EGL_WIDTH, &width);
931 query_buffer(nested->egl_display, (void *) buffer->resource,
932 EGL_HEIGHT, &height);
933
934 device = display_get_cairo_device(nested->display);
935 blit_surface->cairo_surface =
936 cairo_gl_surface_create_for_texture(device,
937 CAIRO_CONTENT_COLOR_ALPHA,
938 blit_surface->texture,
939 width, height);
940}
941
942static const struct nested_renderer
943nested_blit_renderer = {
944 .surface_init = blit_surface_init,
945 .surface_fini = blit_surface_fini,
946 .render_clients = blit_render_clients,
947 .surface_attach = blit_surface_attach
948};
949
Neil Roberts1f020a12013-09-09 00:41:29 +0100950/*** subsurface renderer ***/
951
952static void
953ss_surface_init(struct nested_surface *surface)
954{
955 struct nested *nested = surface->nested;
956 struct wl_compositor *compositor =
957 display_get_compositor(nested->display);
958 struct nested_ss_surface *ss_surface =
U. Artie Eoff5cda4e32014-01-15 11:13:38 -0800959 xzalloc(sizeof *ss_surface);
Neil Roberts1f020a12013-09-09 00:41:29 +0100960 struct rectangle allocation;
961 struct wl_region *region;
962
963 ss_surface->widget =
964 window_add_subsurface(nested->window,
965 nested,
966 SUBSURFACE_SYNCHRONIZED);
967
Neil Roberts40d02282014-02-24 19:07:08 +0000968 widget_set_use_cairo(ss_surface->widget, 0);
969
Neil Roberts1f020a12013-09-09 00:41:29 +0100970 ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
971 ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
972
973 /* The toy toolkit gets confused about the pointer position
974 * when it gets motion events for a subsurface so we'll just
975 * disable input on it */
976 region = wl_compositor_create_region(compositor);
977 wl_surface_set_input_region(ss_surface->surface, region);
978 wl_region_destroy(region);
979
980 widget_get_allocation(nested->widget, &allocation);
981 wl_subsurface_set_position(ss_surface->subsurface,
982 allocation.x + 10,
983 allocation.y + 10);
984
985 surface->renderer_data = ss_surface;
986}
987
988static void
989ss_surface_fini(struct nested_surface *surface)
990{
991 struct nested_ss_surface *ss_surface = surface->renderer_data;
992
993 widget_destroy(ss_surface->widget);
994
995 if (ss_surface->frame_callback)
996 wl_callback_destroy(ss_surface->frame_callback);
997
998 free(ss_surface);
999}
1000
1001static void
1002ss_render_clients(struct nested *nested,
1003 cairo_t *cr)
1004{
1005 /* The clients are composited by the parent compositor so we
1006 * don't need to do anything here */
1007}
1008
1009static void
1010ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
1011{
1012 struct nested_buffer *buffer = data;
1013
1014 nested_buffer_reference(&buffer->parent_ref, NULL);
1015}
1016
1017static struct wl_buffer_listener ss_buffer_listener = {
1018 ss_buffer_release
1019};
1020
1021static void
1022ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
1023{
1024 struct nested_surface *surface = data;
1025 struct nested_ss_surface *ss_surface = surface->renderer_data;
1026
1027 flush_surface_frame_callback_list(surface, time);
1028
1029 if (callback)
1030 wl_callback_destroy(callback);
1031
1032 ss_surface->frame_callback = NULL;
1033}
1034
1035static const struct wl_callback_listener ss_frame_listener = {
1036 ss_frame_callback
1037};
1038
1039static void
1040ss_surface_attach(struct nested_surface *surface,
1041 struct nested_buffer *buffer)
1042{
1043 struct nested *nested = surface->nested;
1044 struct nested_ss_surface *ss_surface = surface->renderer_data;
1045 struct wl_buffer *parent_buffer;
1046 const pixman_box32_t *rects;
1047 int n_rects, i;
1048
1049 if (buffer) {
1050 /* Create a representation of the buffer in the parent
1051 * compositor if we haven't already */
1052 if (buffer->parent_buffer == NULL) {
1053 EGLDisplay *edpy = nested->egl_display;
1054 EGLImageKHR image = surface->image;
1055
1056 buffer->parent_buffer =
1057 create_wayland_buffer_from_image(edpy, image);
1058
1059 wl_buffer_add_listener(buffer->parent_buffer,
1060 &ss_buffer_listener,
1061 buffer);
1062 }
1063
1064 parent_buffer = buffer->parent_buffer;
1065
1066 /* We'll take a reference to the buffer while the parent
1067 * compositor is using it so that we won't report the release
1068 * event until the parent has also finished with it */
1069 nested_buffer_reference(&buffer->parent_ref, buffer);
1070 } else {
1071 parent_buffer = NULL;
1072 }
1073
1074 wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
1075
1076 rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
1077
1078 for (i = 0; i < n_rects; i++) {
1079 const pixman_box32_t *rect = rects + i;
1080 wl_surface_damage(ss_surface->surface,
1081 rect->x1,
1082 rect->y1,
1083 rect->x2 - rect->x1,
1084 rect->y2 - rect->y1);
1085 }
1086
1087 if (ss_surface->frame_callback)
1088 wl_callback_destroy(ss_surface->frame_callback);
1089
1090 ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
1091 wl_callback_add_listener(ss_surface->frame_callback,
1092 &ss_frame_listener,
1093 surface);
1094
1095 wl_surface_commit(ss_surface->surface);
1096}
1097
1098static const struct nested_renderer
1099nested_ss_renderer = {
1100 .surface_init = ss_surface_init,
1101 .surface_fini = ss_surface_fini,
1102 .render_clients = ss_render_clients,
1103 .surface_attach = ss_surface_attach
1104};
1105
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001106int
1107main(int argc, char *argv[])
1108{
1109 struct display *display;
1110 struct nested *nested;
1111
Bill Spitzak6df71aa2014-08-08 12:59:52 -07001112 if (parse_options(nested_options,
1113 ARRAY_LENGTH(nested_options), &argc, argv) > 1) {
1114 printf("Usage: %s [OPTIONS]\n --blit or -b\n", argv[0]);
1115 exit(1);
1116 }
Neil Robertsa5059eb2013-09-09 00:59:35 +01001117
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001118 display = display_create(&argc, argv);
1119 if (display == NULL) {
1120 fprintf(stderr, "failed to create display: %m\n");
1121 return -1;
1122 }
1123
1124 nested = nested_create(display);
1125
Kristian Høgsbergcb61dcf2013-08-07 09:50:12 -07001126 launch_client(nested, "weston-nested-client");
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001127
1128 display_run(display);
1129
1130 nested_destroy(nested);
1131 display_destroy(display);
1132
1133 return 0;
1134}