blob: 74767795446ef67d1cdba537d444c72369f45124 [file] [log] [blame]
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001/*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <cairo.h>
28#include <math.h>
29#include <assert.h>
30#include <pixman.h>
31#include <sys/epoll.h>
32#include <sys/socket.h>
33#include <unistd.h>
34
35#include <EGL/egl.h>
36#include <EGL/eglext.h>
37#include <GLES2/gl2.h>
38#include <GLES2/gl2ext.h>
39
40#include <cairo-gl.h>
41
42#include <wayland-client.h>
Kristian Høgsberg3c179332013-08-06 19:27:04 -070043#define WL_HIDE_DEPRECATED
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040044#include <wayland-server.h>
45
46#include "window.h"
47
Kristian Høgsberg919cddb2013-07-08 19:03:57 -040048#define MIN(x,y) (((x) < (y)) ? (x) : (y))
49
Kristian Høgsbergc2010b32013-12-17 10:40:01 -080050#ifndef EGL_WL_create_wayland_buffer_from_image
51#define EGL_WL_create_wayland_buffer_from_image 1
52
53#ifdef EGL_EGLEXT_PROTOTYPES
54EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
55#endif
56typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
57
58#endif
59
Neil Robertsa5059eb2013-09-09 00:59:35 +010060static int option_blit;
61
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040062struct nested {
63 struct display *display;
64 struct window *window;
65 struct widget *widget;
66 struct wl_display *child_display;
67 struct task child_task;
68
69 EGLDisplay egl_display;
70 struct program *texture_program;
71
72 struct wl_list surface_list;
Neil Roberts47b87d52013-09-08 20:52:36 +010073
74 const struct nested_renderer *renderer;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040075};
76
77struct nested_region {
Kristian Høgsberg88dab172013-06-24 16:35:54 -040078 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -040079 pixman_region32_t region;
80};
81
Neil Roberts1f020a12013-09-09 00:41:29 +010082struct nested_buffer_reference {
83 struct nested_buffer *buffer;
84 struct wl_listener destroy_listener;
85};
86
Neil Roberts6bf23872013-09-08 18:49:15 +010087struct nested_buffer {
88 struct wl_resource *resource;
89 struct wl_signal destroy_signal;
90 struct wl_listener destroy_listener;
91 uint32_t busy_count;
Neil Roberts6bf23872013-09-08 18:49:15 +010092
Neil Roberts1f020a12013-09-09 00:41:29 +010093 /* A buffer in the parent compositor representing the same
94 * data. This is created on-demand when the subsurface
95 * renderer is used */
96 struct wl_buffer *parent_buffer;
97 /* This reference is used to mark when the parent buffer has
98 * been attached to the subsurface. It will be unrefenced when
99 * we receive a buffer release event. That way we won't inform
100 * the client that the buffer is free until the parent
101 * compositor is also finished with it */
102 struct nested_buffer_reference parent_ref;
Neil Roberts6bf23872013-09-08 18:49:15 +0100103};
104
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400105struct nested_surface {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400106 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400107 struct nested *nested;
108 EGLImageKHR *image;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400109 struct wl_list link;
Neil Roberts15a8d342013-09-08 19:49:02 +0100110
Neil Robertsf9b25412013-09-09 15:13:09 +0100111 struct wl_list frame_callback_list;
112
Neil Roberts15a8d342013-09-08 19:49:02 +0100113 struct {
114 /* wl_surface.attach */
115 int newly_attached;
116 struct nested_buffer *buffer;
117 struct wl_listener buffer_destroy_listener;
118
119 /* wl_surface.frame */
120 struct wl_list frame_callback_list;
Neil Roberts28557662013-09-08 20:24:14 +0100121
122 /* wl_surface.damage */
123 pixman_region32_t damage;
Neil Roberts15a8d342013-09-08 19:49:02 +0100124 } pending;
Neil Roberts47b87d52013-09-08 20:52:36 +0100125
126 void *renderer_data;
127};
128
129/* Data used for the blit renderer */
130struct nested_blit_surface {
131 struct nested_buffer_reference buffer_ref;
132 GLuint texture;
133 cairo_surface_t *cairo_surface;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400134};
135
Neil Roberts1f020a12013-09-09 00:41:29 +0100136/* Data used for the subsurface renderer */
137struct nested_ss_surface {
138 struct widget *widget;
139 struct wl_surface *surface;
140 struct wl_subsurface *subsurface;
141 struct wl_callback *frame_callback;
142};
143
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400144struct nested_frame_callback {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400145 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400146 struct wl_list link;
147};
148
Neil Roberts47b87d52013-09-08 20:52:36 +0100149struct nested_renderer {
150 void (* surface_init)(struct nested_surface *surface);
151 void (* surface_fini)(struct nested_surface *surface);
152 void (* render_clients)(struct nested *nested, cairo_t *cr);
153 void (* surface_attach)(struct nested_surface *surface,
154 struct nested_buffer *buffer);
155};
156
Neil Robertsa5059eb2013-09-09 00:59:35 +0100157static const struct weston_option nested_options[] = {
158 { WESTON_OPTION_BOOLEAN, "blit", 'b', &option_blit },
159};
160
Neil Roberts47b87d52013-09-08 20:52:36 +0100161static const struct nested_renderer nested_blit_renderer;
Neil Roberts1f020a12013-09-09 00:41:29 +0100162static const struct nested_renderer nested_ss_renderer;
Neil Roberts47b87d52013-09-08 20:52:36 +0100163
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400164static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
165static PFNEGLCREATEIMAGEKHRPROC create_image;
166static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
167static PFNEGLBINDWAYLANDDISPLAYWL bind_display;
168static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
169static PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
Neil Roberts1f020a12013-09-09 00:41:29 +0100170static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400171
172static void
Neil Roberts6bf23872013-09-08 18:49:15 +0100173nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
174{
175 struct nested_buffer *buffer =
176 container_of(listener, struct nested_buffer, destroy_listener);
177
178 wl_signal_emit(&buffer->destroy_signal, buffer);
Neil Roberts1f020a12013-09-09 00:41:29 +0100179
180 if (buffer->parent_buffer)
181 wl_buffer_destroy(buffer->parent_buffer);
182
Neil Roberts6bf23872013-09-08 18:49:15 +0100183 free(buffer);
184}
185
186static struct nested_buffer *
187nested_buffer_from_resource(struct wl_resource *resource)
188{
189 struct nested_buffer *buffer;
190 struct wl_listener *listener;
191
192 listener =
193 wl_resource_get_destroy_listener(resource,
194 nested_buffer_destroy_handler);
195
196 if (listener)
197 return container_of(listener, struct nested_buffer,
198 destroy_listener);
199
200 buffer = zalloc(sizeof *buffer);
201 if (buffer == NULL)
202 return NULL;
203
204 buffer->resource = resource;
205 wl_signal_init(&buffer->destroy_signal);
206 buffer->destroy_listener.notify = nested_buffer_destroy_handler;
207 wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
208
209 return buffer;
210}
211
212static void
213nested_buffer_reference_handle_destroy(struct wl_listener *listener,
214 void *data)
215{
216 struct nested_buffer_reference *ref =
217 container_of(listener, struct nested_buffer_reference,
218 destroy_listener);
219
220 assert((struct nested_buffer *)data == ref->buffer);
221 ref->buffer = NULL;
222}
223
224static void
225nested_buffer_reference(struct nested_buffer_reference *ref,
226 struct nested_buffer *buffer)
227{
228 if (buffer == ref->buffer)
229 return;
230
231 if (ref->buffer) {
232 ref->buffer->busy_count--;
233 if (ref->buffer->busy_count == 0) {
234 assert(wl_resource_get_client(ref->buffer->resource));
235 wl_resource_queue_event(ref->buffer->resource,
236 WL_BUFFER_RELEASE);
237 }
238 wl_list_remove(&ref->destroy_listener.link);
239 }
240
241 if (buffer) {
242 buffer->busy_count++;
243 wl_signal_add(&buffer->destroy_signal,
244 &ref->destroy_listener);
245
246 ref->destroy_listener.notify =
247 nested_buffer_reference_handle_destroy;
248 }
249
250 ref->buffer = buffer;
251}
252
253static void
Neil Robertsf9b25412013-09-09 15:13:09 +0100254flush_surface_frame_callback_list(struct nested_surface *surface,
255 uint32_t time)
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400256{
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400257 struct nested_frame_callback *nc, *next;
258
Neil Robertsf9b25412013-09-09 15:13:09 +0100259 wl_list_for_each_safe(nc, next, &surface->frame_callback_list, link) {
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400260 wl_callback_send_done(nc->resource, time);
261 wl_resource_destroy(nc->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400262 }
Neil Robertsf9b25412013-09-09 15:13:09 +0100263 wl_list_init(&surface->frame_callback_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400264
265 /* FIXME: toytoolkit need a pre-block handler where we can
266 * call this. */
Neil Robertsf9b25412013-09-09 15:13:09 +0100267 wl_display_flush_clients(surface->nested->child_display);
268}
269
270static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400271redraw_handler(struct widget *widget, void *data)
272{
273 struct nested *nested = data;
274 cairo_surface_t *surface;
275 cairo_t *cr;
276 struct rectangle allocation;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400277
278 widget_get_allocation(nested->widget, &allocation);
279
280 surface = window_get_surface(nested->window);
281
282 cr = cairo_create(surface);
283 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
284 cairo_rectangle(cr,
285 allocation.x,
286 allocation.y,
287 allocation.width,
288 allocation.height);
289 cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
290 cairo_fill(cr);
291
Neil Roberts47b87d52013-09-08 20:52:36 +0100292 nested->renderer->render_clients(nested, cr);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400293
294 cairo_destroy(cr);
295
296 cairo_surface_destroy(surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400297}
298
299static void
300keyboard_focus_handler(struct window *window,
301 struct input *device, void *data)
302{
303 struct nested *nested = data;
304
305 window_schedule_redraw(nested->window);
306}
307
308static void
309handle_child_data(struct task *task, uint32_t events)
310{
311 struct nested *nested = container_of(task, struct nested, child_task);
312 struct wl_event_loop *loop;
313
314 loop = wl_display_get_event_loop(nested->child_display);
315
316 wl_event_loop_dispatch(loop, -1);
317 wl_display_flush_clients(nested->child_display);
318}
319
320struct nested_client {
321 struct wl_client *client;
322 pid_t pid;
323};
324
325static struct nested_client *
326launch_client(struct nested *nested, const char *path)
327{
328 int sv[2];
329 pid_t pid;
330 struct nested_client *client;
331
332 client = malloc(sizeof *client);
333 if (client == NULL)
334 return NULL;
335
336 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
337 fprintf(stderr, "launch_client: "
338 "socketpair failed while launching '%s': %m\n",
339 path);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700340 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400341 return NULL;
342 }
343
344 pid = fork();
345 if (pid == -1) {
346 close(sv[0]);
347 close(sv[1]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700348 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400349 fprintf(stderr, "launch_client: "
350 "fork failed while launching '%s': %m\n", path);
351 return NULL;
352 }
353
354 if (pid == 0) {
355 int clientfd;
356 char s[32];
357
358 /* SOCK_CLOEXEC closes both ends, so we dup the fd to
359 * get a non-CLOEXEC fd to pass through exec. */
360 clientfd = dup(sv[1]);
361 if (clientfd == -1) {
362 fprintf(stderr, "compositor: dup failed: %m\n");
363 exit(-1);
364 }
365
366 snprintf(s, sizeof s, "%d", clientfd);
367 setenv("WAYLAND_SOCKET", s, 1);
368
369 execl(path, path, NULL);
370
371 fprintf(stderr, "compositor: executing '%s' failed: %m\n",
372 path);
373 exit(-1);
374 }
375
376 close(sv[1]);
377
378 client->client = wl_client_create(nested->child_display, sv[0]);
379 if (!client->client) {
380 close(sv[0]);
Kristian Høgsberg67733942013-10-09 13:30:58 -0700381 free(client);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400382 fprintf(stderr, "launch_client: "
383 "wl_client_create failed while launching '%s'.\n",
384 path);
385 return NULL;
386 }
387
388 client->pid = pid;
389
390 return client;
391}
392
393static void
394destroy_surface(struct wl_resource *resource)
395{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400396 struct nested_surface *surface = wl_resource_get_user_data(resource);
Neil Roberts47b87d52013-09-08 20:52:36 +0100397 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100398 struct nested_frame_callback *cb, *next;
399
400 wl_list_for_each_safe(cb, next,
Neil Robertsf9b25412013-09-09 15:13:09 +0100401 &surface->frame_callback_list, link)
402 wl_resource_destroy(cb->resource);
403
404 wl_list_for_each_safe(cb, next,
Neil Roberts15a8d342013-09-08 19:49:02 +0100405 &surface->pending.frame_callback_list, link)
406 wl_resource_destroy(cb->resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400407
Neil Roberts28557662013-09-08 20:24:14 +0100408 pixman_region32_fini(&surface->pending.damage);
409
Neil Roberts47b87d52013-09-08 20:52:36 +0100410 nested->renderer->surface_fini(surface);
411
Neil Roberts8fbe3a62013-11-22 15:41:53 +0000412 wl_list_remove(&surface->link);
413
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400414 free(surface);
415}
416
417static void
418surface_destroy(struct wl_client *client, struct wl_resource *resource)
419{
420 wl_resource_destroy(resource);
421}
422
423static void
424surface_attach(struct wl_client *client,
425 struct wl_resource *resource,
426 struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
427{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400428 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400429 struct nested *nested = surface->nested;
Neil Roberts15a8d342013-09-08 19:49:02 +0100430 struct nested_buffer *buffer = NULL;
431
432 if (buffer_resource) {
433 int format;
434
435 if (!query_buffer(nested->egl_display, (void *) buffer_resource,
436 EGL_TEXTURE_FORMAT, &format)) {
437 wl_resource_post_error(buffer_resource,
438 WL_DISPLAY_ERROR_INVALID_OBJECT,
439 "attaching non-egl wl_buffer");
440 return;
441 }
442
443 switch (format) {
444 case EGL_TEXTURE_RGB:
445 case EGL_TEXTURE_RGBA:
446 break;
447 default:
448 wl_resource_post_error(buffer_resource,
449 WL_DISPLAY_ERROR_INVALID_OBJECT,
450 "invalid format");
451 return;
452 }
453
454 buffer = nested_buffer_from_resource(buffer_resource);
455 if (buffer == NULL) {
456 wl_client_post_no_memory(client);
457 return;
458 }
459 }
460
461 if (surface->pending.buffer)
462 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
463
464 surface->pending.buffer = buffer;
465 surface->pending.newly_attached = 1;
466 if (buffer) {
467 wl_signal_add(&buffer->destroy_signal,
468 &surface->pending.buffer_destroy_listener);
469 }
470}
471
472static void
473nested_surface_attach(struct nested_surface *surface,
474 struct nested_buffer *buffer)
475{
476 struct nested *nested = surface->nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400477
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400478 if (surface->image != EGL_NO_IMAGE_KHR)
479 destroy_image(nested->egl_display, surface->image);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400480
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400481 surface->image = create_image(nested->egl_display, NULL,
Neil Roberts15a8d342013-09-08 19:49:02 +0100482 EGL_WAYLAND_BUFFER_WL, buffer->resource,
Kristian Høgsberg0d5fe3a2013-08-15 15:17:57 -0700483 NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400484 if (surface->image == EGL_NO_IMAGE_KHR) {
485 fprintf(stderr, "failed to create img\n");
486 return;
487 }
488
Neil Roberts47b87d52013-09-08 20:52:36 +0100489 nested->renderer->surface_attach(surface, buffer);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400490}
491
492static void
493surface_damage(struct wl_client *client,
494 struct wl_resource *resource,
495 int32_t x, int32_t y, int32_t width, int32_t height)
496{
Neil Roberts28557662013-09-08 20:24:14 +0100497 struct nested_surface *surface = wl_resource_get_user_data(resource);
498
499 pixman_region32_union_rect(&surface->pending.damage,
500 &surface->pending.damage,
501 x, y, width, height);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400502}
503
504static void
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400505destroy_frame_callback(struct wl_resource *resource)
506{
507 struct nested_frame_callback *callback = wl_resource_get_user_data(resource);
508
509 wl_list_remove(&callback->link);
510 free(callback);
511}
512
513static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400514surface_frame(struct wl_client *client,
515 struct wl_resource *resource, uint32_t id)
516{
517 struct nested_frame_callback *callback;
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400518 struct nested_surface *surface = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400519
520 callback = malloc(sizeof *callback);
521 if (callback == NULL) {
522 wl_resource_post_no_memory(resource);
523 return;
524 }
525
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400526 callback->resource = wl_resource_create(client,
527 &wl_callback_interface, 1, id);
528 wl_resource_set_implementation(callback->resource, NULL, callback,
529 destroy_frame_callback);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400530
Neil Roberts15a8d342013-09-08 19:49:02 +0100531 wl_list_insert(surface->pending.frame_callback_list.prev,
532 &callback->link);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400533}
534
535static void
536surface_set_opaque_region(struct wl_client *client,
537 struct wl_resource *resource,
538 struct wl_resource *region_resource)
539{
540 fprintf(stderr, "surface_set_opaque_region\n");
541}
542
543static void
544surface_set_input_region(struct wl_client *client,
545 struct wl_resource *resource,
546 struct wl_resource *region_resource)
547{
548 fprintf(stderr, "surface_set_input_region\n");
549}
550
551static void
Neil Roberts28557662013-09-08 20:24:14 +0100552empty_region(pixman_region32_t *region)
553{
554 pixman_region32_fini(region);
555 pixman_region32_init(region);
556}
557
558static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400559surface_commit(struct wl_client *client, struct wl_resource *resource)
560{
Neil Roberts15a8d342013-09-08 19:49:02 +0100561 struct nested_surface *surface = wl_resource_get_user_data(resource);
562 struct nested *nested = surface->nested;
563
564 /* wl_surface.attach */
565 if (surface->pending.newly_attached)
566 nested_surface_attach(surface, surface->pending.buffer);
567
568 if (surface->pending.buffer) {
569 wl_list_remove(&surface->pending.buffer_destroy_listener.link);
570 surface->pending.buffer = NULL;
571 }
572 surface->pending.newly_attached = 0;
573
Neil Roberts28557662013-09-08 20:24:14 +0100574 /* wl_surface.damage */
575 empty_region(&surface->pending.damage);
576
Neil Roberts15a8d342013-09-08 19:49:02 +0100577 /* wl_surface.frame */
Neil Robertsf9b25412013-09-09 15:13:09 +0100578 wl_list_insert_list(&surface->frame_callback_list,
Neil Roberts15a8d342013-09-08 19:49:02 +0100579 &surface->pending.frame_callback_list);
580 wl_list_init(&surface->pending.frame_callback_list);
581
Neil Roberts1f020a12013-09-09 00:41:29 +0100582 /* FIXME: For the subsurface renderer we don't need to
583 * actually redraw the window. However we do want to cause a
584 * commit because the subsurface is synchronized. Ideally we
585 * would just queue the commit */
Neil Roberts15a8d342013-09-08 19:49:02 +0100586 window_schedule_redraw(nested->window);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400587}
588
589static void
590surface_set_buffer_transform(struct wl_client *client,
591 struct wl_resource *resource, int transform)
592{
593 fprintf(stderr, "surface_set_buffer_transform\n");
594}
595
596static const struct wl_surface_interface surface_interface = {
597 surface_destroy,
598 surface_attach,
599 surface_damage,
600 surface_frame,
601 surface_set_opaque_region,
602 surface_set_input_region,
603 surface_commit,
604 surface_set_buffer_transform
605};
606
607static void
Neil Roberts15a8d342013-09-08 19:49:02 +0100608surface_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
609{
610 struct nested_surface *surface =
611 container_of(listener, struct nested_surface,
612 pending.buffer_destroy_listener);
613
614 surface->pending.buffer = NULL;
615}
616
617static void
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400618compositor_create_surface(struct wl_client *client,
619 struct wl_resource *resource, uint32_t id)
620{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400621 struct nested *nested = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400622 struct nested_surface *surface;
623
Peter Huttererf3d62272013-08-08 11:57:05 +1000624 surface = zalloc(sizeof *surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400625 if (surface == NULL) {
626 wl_resource_post_no_memory(resource);
627 return;
628 }
629
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400630 surface->nested = nested;
631
Neil Robertsf9b25412013-09-09 15:13:09 +0100632 wl_list_init(&surface->frame_callback_list);
633
Neil Roberts15a8d342013-09-08 19:49:02 +0100634 wl_list_init(&surface->pending.frame_callback_list);
635 surface->pending.buffer_destroy_listener.notify =
636 surface_handle_pending_buffer_destroy;
Neil Roberts28557662013-09-08 20:24:14 +0100637 pixman_region32_init(&surface->pending.damage);
Neil Roberts15a8d342013-09-08 19:49:02 +0100638
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400639 display_acquire_window_surface(nested->display,
640 nested->window, NULL);
641
Neil Roberts47b87d52013-09-08 20:52:36 +0100642 nested->renderer->surface_init(surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400643
644 display_release_window_surface(nested->display, nested->window);
645
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400646 surface->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400647 wl_resource_create(client, &wl_surface_interface, 1, id);
648
649 wl_resource_set_implementation(surface->resource,
650 &surface_interface, surface,
651 destroy_surface);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400652
653 wl_list_insert(nested->surface_list.prev, &surface->link);
654}
655
656static void
657destroy_region(struct wl_resource *resource)
658{
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400659 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400660
661 pixman_region32_fini(&region->region);
662 free(region);
663}
664
665static void
666region_destroy(struct wl_client *client, struct wl_resource *resource)
667{
668 wl_resource_destroy(resource);
669}
670
671static void
672region_add(struct wl_client *client, struct wl_resource *resource,
673 int32_t x, int32_t y, int32_t width, int32_t height)
674{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400675 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400676
677 pixman_region32_union_rect(&region->region, &region->region,
678 x, y, width, height);
679}
680
681static void
682region_subtract(struct wl_client *client, struct wl_resource *resource,
683 int32_t x, int32_t y, int32_t width, int32_t height)
684{
Kristian Høgsberg1d7d8f02013-06-25 16:15:27 -0400685 struct nested_region *region = wl_resource_get_user_data(resource);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400686 pixman_region32_t rect;
687
688 pixman_region32_init_rect(&rect, x, y, width, height);
689 pixman_region32_subtract(&region->region, &region->region, &rect);
690 pixman_region32_fini(&rect);
691}
692
693static const struct wl_region_interface region_interface = {
694 region_destroy,
695 region_add,
696 region_subtract
697};
698
699static void
700compositor_create_region(struct wl_client *client,
701 struct wl_resource *resource, uint32_t id)
702{
703 struct nested_region *region;
704
705 region = malloc(sizeof *region);
706 if (region == NULL) {
707 wl_resource_post_no_memory(resource);
708 return;
709 }
710
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400711 pixman_region32_init(&region->region);
712
Kristian Høgsberg88dab172013-06-24 16:35:54 -0400713 region->resource =
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400714 wl_resource_create(client, &wl_region_interface, 1, id);
715 wl_resource_set_implementation(region->resource, &region_interface,
716 region, destroy_region);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400717}
718
719static const struct wl_compositor_interface compositor_interface = {
720 compositor_create_surface,
721 compositor_create_region
722};
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400723
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400724static void
725compositor_bind(struct wl_client *client,
726 void *data, uint32_t version, uint32_t id)
727{
728 struct nested *nested = data;
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400729 struct wl_resource *resource;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400730
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400731 resource = wl_resource_create(client, &wl_compositor_interface,
732 MIN(version, 3), id);
733 wl_resource_set_implementation(resource, &compositor_interface,
734 nested, NULL);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400735}
736
737static int
738nested_init_compositor(struct nested *nested)
739{
740 const char *extensions;
741 struct wl_event_loop *loop;
Neil Roberts1f020a12013-09-09 00:41:29 +0100742 int use_ss_renderer = 0;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400743 int fd, ret;
744
745 wl_list_init(&nested->surface_list);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400746 nested->child_display = wl_display_create();
747 loop = wl_display_get_event_loop(nested->child_display);
748 fd = wl_event_loop_get_fd(loop);
749 nested->child_task.run = handle_child_data;
750 display_watch_fd(nested->display, fd,
751 EPOLLIN, &nested->child_task);
752
Kristian Høgsberg919cddb2013-07-08 19:03:57 -0400753 if (!wl_global_create(nested->child_display,
754 &wl_compositor_interface, 1,
755 nested, compositor_bind))
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400756 return -1;
757
758 wl_display_init_shm(nested->child_display);
759
760 nested->egl_display = display_get_egl_display(nested->display);
761 extensions = eglQueryString(nested->egl_display, EGL_EXTENSIONS);
762 if (strstr(extensions, "EGL_WL_bind_wayland_display") == NULL) {
763 fprintf(stderr, "no EGL_WL_bind_wayland_display extension\n");
764 return -1;
765 }
766
767 bind_display = (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
768 unbind_display = (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
769 create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
770 destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
771 query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
772 image_target_texture_2d =
773 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
774
775 ret = bind_display(nested->egl_display, nested->child_display);
776 if (!ret) {
777 fprintf(stderr, "failed to bind wl_display\n");
778 return -1;
779 }
780
Neil Roberts1f020a12013-09-09 00:41:29 +0100781 if (display_has_subcompositor(nested->display)) {
782 const char *func = "eglCreateWaylandBufferFromImageWL";
783 const char *ext = "EGL_WL_create_wayland_buffer_from_image";
784
785 if (strstr(extensions, ext)) {
786 create_wayland_buffer_from_image =
787 (void *) eglGetProcAddress(func);
788 use_ss_renderer = 1;
789 }
790 }
791
Neil Robertsa5059eb2013-09-09 00:59:35 +0100792 if (option_blit)
793 use_ss_renderer = 0;
794
Neil Roberts1f020a12013-09-09 00:41:29 +0100795 if (use_ss_renderer) {
796 printf("Using subsurfaces to render client surfaces\n");
797 nested->renderer = &nested_ss_renderer;
798 } else {
799 printf("Using local compositing with blits to "
800 "render client surfaces\n");
801 nested->renderer = &nested_blit_renderer;
802 }
Neil Roberts47b87d52013-09-08 20:52:36 +0100803
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400804 return 0;
805}
806
807static struct nested *
808nested_create(struct display *display)
809{
810 struct nested *nested;
811
Peter Huttererf3d62272013-08-08 11:57:05 +1000812 nested = zalloc(sizeof *nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400813 if (nested == NULL)
814 return nested;
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400815
816 nested->window = window_create(display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -0500817 nested->widget = window_frame_create(nested->window, nested);
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -0400818 window_set_title(nested->window, "Wayland Nested");
819 nested->display = display;
820
821 window_set_user_data(nested->window, nested);
822 widget_set_redraw_handler(nested->widget, redraw_handler);
823 window_set_keyboard_focus_handler(nested->window,
824 keyboard_focus_handler);
825
826 nested_init_compositor(nested);
827
828 widget_schedule_resize(nested->widget, 400, 400);
829
830 return nested;
831}
832
833static void
834nested_destroy(struct nested *nested)
835{
836 widget_destroy(nested->widget);
837 window_destroy(nested->window);
838 free(nested);
839}
840
Neil Roberts1f020a12013-09-09 00:41:29 +0100841/*** blit renderer ***/
842
Neil Roberts47b87d52013-09-08 20:52:36 +0100843static void
844blit_surface_init(struct nested_surface *surface)
845{
846 struct nested_blit_surface *blit_surface =
847 zalloc(sizeof *blit_surface);
848
849 glGenTextures(1, &blit_surface->texture);
850 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
851 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
852 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
853 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
854 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
855
856 surface->renderer_data = blit_surface;
857}
858
859static void
860blit_surface_fini(struct nested_surface *surface)
861{
862 struct nested_blit_surface *blit_surface = surface->renderer_data;
863
864 nested_buffer_reference(&blit_surface->buffer_ref, NULL);
865
866 glDeleteTextures(1, &blit_surface->texture);
867
868 free(blit_surface);
869}
870
871static void
872blit_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
873{
874 struct nested *nested = data;
875 struct nested_surface *surface;
876
877 wl_list_for_each(surface, &nested->surface_list, link)
878 flush_surface_frame_callback_list(surface, time);
879
880 if (callback)
881 wl_callback_destroy(callback);
882}
883
884static const struct wl_callback_listener blit_frame_listener = {
885 blit_frame_callback
886};
887
888static void
889blit_render_clients(struct nested *nested,
890 cairo_t *cr)
891{
892 struct nested_surface *s;
893 struct rectangle allocation;
894 struct wl_callback *callback;
895
896 widget_get_allocation(nested->widget, &allocation);
897
898 wl_list_for_each(s, &nested->surface_list, link) {
899 struct nested_blit_surface *blit_surface = s->renderer_data;
900
901 display_acquire_window_surface(nested->display,
902 nested->window, NULL);
903
904 glBindTexture(GL_TEXTURE_2D, blit_surface->texture);
905 image_target_texture_2d(GL_TEXTURE_2D, s->image);
906
907 display_release_window_surface(nested->display,
908 nested->window);
909
910 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
911 cairo_set_source_surface(cr, blit_surface->cairo_surface,
912 allocation.x + 10,
913 allocation.y + 10);
914 cairo_rectangle(cr, allocation.x + 10,
915 allocation.y + 10,
916 allocation.width - 10,
917 allocation.height - 10);
918
919 cairo_fill(cr);
920 }
921
922 callback = wl_surface_frame(window_get_wl_surface(nested->window));
923 wl_callback_add_listener(callback, &blit_frame_listener, nested);
924}
925
926static void
927blit_surface_attach(struct nested_surface *surface,
928 struct nested_buffer *buffer)
929{
930 struct nested *nested = surface->nested;
931 struct nested_blit_surface *blit_surface = surface->renderer_data;
932 EGLint width, height;
933 cairo_device_t *device;
934
935 nested_buffer_reference(&blit_surface->buffer_ref, buffer);
936
937 if (blit_surface->cairo_surface)
938 cairo_surface_destroy(blit_surface->cairo_surface);
939
940 query_buffer(nested->egl_display, (void *) buffer->resource,
941 EGL_WIDTH, &width);
942 query_buffer(nested->egl_display, (void *) buffer->resource,
943 EGL_HEIGHT, &height);
944
945 device = display_get_cairo_device(nested->display);
946 blit_surface->cairo_surface =
947 cairo_gl_surface_create_for_texture(device,
948 CAIRO_CONTENT_COLOR_ALPHA,
949 blit_surface->texture,
950 width, height);
951}
952
953static const struct nested_renderer
954nested_blit_renderer = {
955 .surface_init = blit_surface_init,
956 .surface_fini = blit_surface_fini,
957 .render_clients = blit_render_clients,
958 .surface_attach = blit_surface_attach
959};
960
Neil Roberts1f020a12013-09-09 00:41:29 +0100961/*** subsurface renderer ***/
962
963static void
964ss_surface_init(struct nested_surface *surface)
965{
966 struct nested *nested = surface->nested;
967 struct wl_compositor *compositor =
968 display_get_compositor(nested->display);
969 struct nested_ss_surface *ss_surface =
970 zalloc(sizeof *ss_surface);
971 struct rectangle allocation;
972 struct wl_region *region;
973
974 ss_surface->widget =
975 window_add_subsurface(nested->window,
976 nested,
977 SUBSURFACE_SYNCHRONIZED);
978
979 ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
980 ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
981
982 /* The toy toolkit gets confused about the pointer position
983 * when it gets motion events for a subsurface so we'll just
984 * disable input on it */
985 region = wl_compositor_create_region(compositor);
986 wl_surface_set_input_region(ss_surface->surface, region);
987 wl_region_destroy(region);
988
989 widget_get_allocation(nested->widget, &allocation);
990 wl_subsurface_set_position(ss_surface->subsurface,
991 allocation.x + 10,
992 allocation.y + 10);
993
994 surface->renderer_data = ss_surface;
995}
996
997static void
998ss_surface_fini(struct nested_surface *surface)
999{
1000 struct nested_ss_surface *ss_surface = surface->renderer_data;
1001
1002 widget_destroy(ss_surface->widget);
1003
1004 if (ss_surface->frame_callback)
1005 wl_callback_destroy(ss_surface->frame_callback);
1006
1007 free(ss_surface);
1008}
1009
1010static void
1011ss_render_clients(struct nested *nested,
1012 cairo_t *cr)
1013{
1014 /* The clients are composited by the parent compositor so we
1015 * don't need to do anything here */
1016}
1017
1018static void
1019ss_buffer_release(void *data, struct wl_buffer *wl_buffer)
1020{
1021 struct nested_buffer *buffer = data;
1022
1023 nested_buffer_reference(&buffer->parent_ref, NULL);
1024}
1025
1026static struct wl_buffer_listener ss_buffer_listener = {
1027 ss_buffer_release
1028};
1029
1030static void
1031ss_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
1032{
1033 struct nested_surface *surface = data;
1034 struct nested_ss_surface *ss_surface = surface->renderer_data;
1035
1036 flush_surface_frame_callback_list(surface, time);
1037
1038 if (callback)
1039 wl_callback_destroy(callback);
1040
1041 ss_surface->frame_callback = NULL;
1042}
1043
1044static const struct wl_callback_listener ss_frame_listener = {
1045 ss_frame_callback
1046};
1047
1048static void
1049ss_surface_attach(struct nested_surface *surface,
1050 struct nested_buffer *buffer)
1051{
1052 struct nested *nested = surface->nested;
1053 struct nested_ss_surface *ss_surface = surface->renderer_data;
1054 struct wl_buffer *parent_buffer;
1055 const pixman_box32_t *rects;
1056 int n_rects, i;
1057
1058 if (buffer) {
1059 /* Create a representation of the buffer in the parent
1060 * compositor if we haven't already */
1061 if (buffer->parent_buffer == NULL) {
1062 EGLDisplay *edpy = nested->egl_display;
1063 EGLImageKHR image = surface->image;
1064
1065 buffer->parent_buffer =
1066 create_wayland_buffer_from_image(edpy, image);
1067
1068 wl_buffer_add_listener(buffer->parent_buffer,
1069 &ss_buffer_listener,
1070 buffer);
1071 }
1072
1073 parent_buffer = buffer->parent_buffer;
1074
1075 /* We'll take a reference to the buffer while the parent
1076 * compositor is using it so that we won't report the release
1077 * event until the parent has also finished with it */
1078 nested_buffer_reference(&buffer->parent_ref, buffer);
1079 } else {
1080 parent_buffer = NULL;
1081 }
1082
1083 wl_surface_attach(ss_surface->surface, parent_buffer, 0, 0);
1084
1085 rects = pixman_region32_rectangles(&surface->pending.damage, &n_rects);
1086
1087 for (i = 0; i < n_rects; i++) {
1088 const pixman_box32_t *rect = rects + i;
1089 wl_surface_damage(ss_surface->surface,
1090 rect->x1,
1091 rect->y1,
1092 rect->x2 - rect->x1,
1093 rect->y2 - rect->y1);
1094 }
1095
1096 if (ss_surface->frame_callback)
1097 wl_callback_destroy(ss_surface->frame_callback);
1098
1099 ss_surface->frame_callback = wl_surface_frame(ss_surface->surface);
1100 wl_callback_add_listener(ss_surface->frame_callback,
1101 &ss_frame_listener,
1102 surface);
1103
1104 wl_surface_commit(ss_surface->surface);
1105}
1106
1107static const struct nested_renderer
1108nested_ss_renderer = {
1109 .surface_init = ss_surface_init,
1110 .surface_fini = ss_surface_fini,
1111 .render_clients = ss_render_clients,
1112 .surface_attach = ss_surface_attach
1113};
1114
Kristian Høgsberg1cc5ac32013-04-11 21:47:41 -04001115int
1116main(int argc, char *argv[])
1117{
1118 struct display *display;
1119 struct nested *nested;
1120
Neil Robertsa5059eb2013-09-09 00:59:35 +01001121 parse_options(nested_options,
1122 ARRAY_LENGTH(nested_options), &argc, argv);
1123
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}