egl/wayland: Update to Wayland 0.99 API
[mesa.git] / src / gallium / state_trackers / egl / wayland / native_wayland.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.11
4 *
5 * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #include "util/u_memory.h"
27 #include "util/u_inlines.h"
28
29 #include "pipe/p_compiler.h"
30 #include "pipe/p_screen.h"
31 #include "pipe/p_context.h"
32 #include "pipe/p_state.h"
33 #include "state_tracker/drm_driver.h"
34 #include "egllog.h"
35
36 #include "native_wayland.h"
37
38 static void
39 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
40 {
41 int *done = data;
42
43 *done = 1;
44 wl_callback_destroy(callback);
45 }
46
47 static const struct wl_callback_listener sync_listener = {
48 sync_callback
49 };
50
51 int
52 wayland_roundtrip(struct wayland_display *display)
53 {
54 struct wl_callback *callback;
55 int done = 0, ret = 0;
56
57 callback = wl_display_sync(display->dpy);
58 wl_callback_add_listener(callback, &sync_listener, &done);
59 wl_proxy_set_queue((struct wl_proxy *) callback, display->queue);
60 while (ret == 0 && !done)
61 ret = wl_display_dispatch_queue(display->dpy, display->queue);
62
63 return ret;
64 }
65
66 static const struct native_event_handler *wayland_event_handler;
67
68 const static struct {
69 enum pipe_format format;
70 enum wayland_format_flag flag;
71 } wayland_formats[] = {
72 { PIPE_FORMAT_B8G8R8A8_UNORM, HAS_ARGB8888 },
73 { PIPE_FORMAT_B8G8R8X8_UNORM, HAS_XRGB8888 },
74 };
75
76 static const struct native_config **
77 wayland_display_get_configs(struct native_display *ndpy, int *num_configs)
78 {
79 struct wayland_display *display = wayland_display(ndpy);
80 const struct native_config **configs;
81 int i;
82
83 if (!display->configs) {
84 struct native_config *nconf;
85
86 display->num_configs = 0;
87 display->configs = CALLOC(Elements(wayland_formats),
88 sizeof(*display->configs));
89 if (!display->configs)
90 return NULL;
91
92 for (i = 0; i < Elements(wayland_formats); ++i) {
93 if (!(display->formats & wayland_formats[i].flag))
94 continue;
95
96 nconf = &display->configs[display->num_configs].base;
97 nconf->buffer_mask =
98 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
99 (1 << NATIVE_ATTACHMENT_BACK_LEFT);
100
101 nconf->window_bit = TRUE;
102 nconf->pixmap_bit = TRUE;
103
104 nconf->color_format = wayland_formats[i].format;
105 display->num_configs++;
106 }
107 }
108
109 configs = MALLOC(display->num_configs * sizeof(*configs));
110 if (configs) {
111 for (i = 0; i < display->num_configs; ++i)
112 configs[i] = &display->configs[i].base;
113 if (num_configs)
114 *num_configs = display->num_configs;
115 }
116
117 return configs;
118 }
119
120 static int
121 wayland_display_get_param(struct native_display *ndpy,
122 enum native_param_type param)
123 {
124 int val;
125
126 switch (param) {
127 case NATIVE_PARAM_PREMULTIPLIED_ALPHA:
128 val = 1;
129 break;
130 case NATIVE_PARAM_USE_NATIVE_BUFFER:
131 case NATIVE_PARAM_PRESERVE_BUFFER:
132 case NATIVE_PARAM_MAX_SWAP_INTERVAL:
133 default:
134 val = 0;
135 break;
136 }
137
138 return val;
139 }
140
141 static boolean
142 wayland_display_get_pixmap_format(struct native_display *ndpy,
143 EGLNativePixmapType pix,
144 enum pipe_format *format)
145 {
146 /* all wl_egl_pixmaps are supported */
147 *format = PIPE_FORMAT_NONE;
148
149 return TRUE;
150 }
151
152 static void
153 wayland_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
154 {
155 struct pipe_resource *resource = egl_pixmap->driver_private;
156
157 assert(resource);
158
159 pipe_resource_reference(&resource, NULL);
160 if (egl_pixmap->buffer) {
161 wl_buffer_destroy(egl_pixmap->buffer);
162 egl_pixmap->buffer = NULL;
163 }
164
165 egl_pixmap->driver_private = NULL;
166 egl_pixmap->destroy = NULL;
167 }
168
169 static void
170 wayland_pixmap_surface_initialize(struct wayland_surface *surface)
171 {
172 struct wayland_display *display = wayland_display(&surface->display->base);
173 const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
174
175 if (surface->pix->buffer != NULL)
176 return;
177
178 surface->pix->buffer = display->create_buffer(display, surface, front_natt);
179 surface->pix->destroy = wayland_pixmap_destroy;
180 surface->pix->driver_private =
181 resource_surface_get_single_resource(surface->rsurf, front_natt);
182 }
183
184 static void
185 wayland_release_pending_resource(void *data,
186 struct wl_callback *callback,
187 uint32_t time)
188 {
189 struct wayland_surface *surface = data;
190
191 wl_callback_destroy(callback);
192
193 /* FIXME: print internal error */
194 if (!surface->pending_resource)
195 return;
196
197 pipe_resource_reference(&surface->pending_resource, NULL);
198 }
199
200 static const struct wl_callback_listener release_buffer_listener = {
201 wayland_release_pending_resource
202 };
203
204 static void
205 wayland_window_surface_handle_resize(struct wayland_surface *surface)
206 {
207 struct wayland_display *display = surface->display;
208 struct pipe_resource *front_resource;
209 const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
210 int i;
211
212 front_resource = resource_surface_get_single_resource(surface->rsurf,
213 front_natt);
214 if (resource_surface_set_size(surface->rsurf,
215 surface->win->width, surface->win->height)) {
216
217 if (surface->pending_resource)
218 wayland_roundtrip(display);
219
220 if (front_resource) {
221 struct wl_callback *callback;
222
223 surface->pending_resource = front_resource;
224 front_resource = NULL;
225
226 callback = wl_display_sync(display->dpy);
227 wl_callback_add_listener(callback, &release_buffer_listener, surface);
228 wl_proxy_set_queue((struct wl_proxy *) callback, display->queue);
229 }
230
231 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
232 if (surface->buffer[i])
233 wl_buffer_destroy(surface->buffer[i]);
234 surface->buffer[i] = NULL;
235 }
236
237 surface->dx = surface->win->dx;
238 surface->dy = surface->win->dy;
239 }
240 pipe_resource_reference(&front_resource, NULL);
241 }
242
243 static boolean
244 wayland_surface_validate(struct native_surface *nsurf, uint attachment_mask,
245 unsigned int *seq_num, struct pipe_resource **textures,
246 int *width, int *height)
247 {
248 struct wayland_surface *surface = wayland_surface(nsurf);
249
250 if (surface->type == WL_WINDOW_SURFACE)
251 wayland_window_surface_handle_resize(surface);
252
253 if (!resource_surface_add_resources(surface->rsurf, attachment_mask |
254 surface->attachment_mask))
255 return FALSE;
256
257 if (textures)
258 resource_surface_get_resources(surface->rsurf, textures, attachment_mask);
259
260 if (seq_num)
261 *seq_num = surface->sequence_number;
262
263 resource_surface_get_size(surface->rsurf, (uint *) width, (uint *) height);
264
265 if (surface->type == WL_PIXMAP_SURFACE)
266 wayland_pixmap_surface_initialize(surface);
267
268 return TRUE;
269 }
270
271 static void
272 wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time)
273 {
274 struct wayland_surface *surface = data;
275
276 surface->frame_callback = NULL;
277
278 wl_callback_destroy(callback);
279 }
280
281 static const struct wl_callback_listener frame_listener = {
282 wayland_frame_callback
283 };
284
285 static INLINE void
286 wayland_buffers_swap(struct wl_buffer **buffer,
287 enum wayland_buffer_type buf1,
288 enum wayland_buffer_type buf2)
289 {
290 struct wl_buffer *tmp = buffer[buf1];
291 buffer[buf1] = buffer[buf2];
292 buffer[buf2] = tmp;
293 }
294
295 static boolean
296 wayland_surface_swap_buffers(struct native_surface *nsurf)
297 {
298 struct wayland_surface *surface = wayland_surface(nsurf);
299 struct wayland_display *display = surface->display;
300 int ret = 0;
301
302 while (surface->frame_callback && ret != -1)
303 ret = wl_display_dispatch_queue(display->dpy, display->queue);
304 if (ret == -1)
305 return EGL_FALSE;
306
307 surface->frame_callback = wl_surface_frame(surface->win->surface);
308 wl_callback_add_listener(surface->frame_callback, &frame_listener, surface);
309 wl_proxy_set_queue((struct wl_proxy *) surface->frame_callback,
310 display->queue);
311
312 if (surface->type == WL_WINDOW_SURFACE) {
313 resource_surface_swap_buffers(surface->rsurf,
314 NATIVE_ATTACHMENT_FRONT_LEFT,
315 NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
316
317 wayland_buffers_swap(surface->buffer, WL_BUFFER_FRONT, WL_BUFFER_BACK);
318
319 if (surface->buffer[WL_BUFFER_FRONT] == NULL)
320 surface->buffer[WL_BUFFER_FRONT] =
321 display->create_buffer(display, surface,
322 NATIVE_ATTACHMENT_FRONT_LEFT);
323
324 wl_surface_attach(surface->win->surface, surface->buffer[WL_BUFFER_FRONT],
325 surface->dx, surface->dy);
326
327 resource_surface_get_size(surface->rsurf,
328 (uint *) &surface->win->attached_width,
329 (uint *) &surface->win->attached_height);
330 surface->dx = 0;
331 surface->dy = 0;
332 }
333
334 surface->sequence_number++;
335 wayland_event_handler->invalid_surface(&display->base,
336 &surface->base,
337 surface->sequence_number);
338
339 return TRUE;
340 }
341
342 static boolean
343 wayland_surface_present(struct native_surface *nsurf,
344 const struct native_present_control *ctrl)
345 {
346 struct wayland_surface *surface = wayland_surface(nsurf);
347 uint width, height;
348 boolean ret;
349
350 if (ctrl->preserve || ctrl->swap_interval)
351 return FALSE;
352
353 /* force buffers to be re-created if they will be presented differently */
354 if (surface->premultiplied_alpha != ctrl->premultiplied_alpha) {
355 enum wayland_buffer_type buffer;
356
357 for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) {
358 if (surface->buffer[buffer]) {
359 wl_buffer_destroy(surface->buffer[buffer]);
360 surface->buffer[buffer] = NULL;
361 }
362 }
363
364 surface->premultiplied_alpha = ctrl->premultiplied_alpha;
365 }
366
367 switch (ctrl->natt) {
368 case NATIVE_ATTACHMENT_FRONT_LEFT:
369 ret = TRUE;
370 break;
371 case NATIVE_ATTACHMENT_BACK_LEFT:
372 ret = wayland_surface_swap_buffers(nsurf);
373 break;
374 default:
375 ret = FALSE;
376 break;
377 }
378
379 if (surface->type == WL_WINDOW_SURFACE) {
380 resource_surface_get_size(surface->rsurf, &width, &height);
381 wl_surface_damage(surface->win->surface, 0, 0, width, height);
382 wl_surface_commit(surface->win->surface);
383 }
384
385 return ret;
386 }
387
388 static void
389 wayland_surface_wait(struct native_surface *nsurf)
390 {
391 /* no-op */
392 }
393
394 static void
395 wayland_surface_destroy(struct native_surface *nsurf)
396 {
397 struct wayland_surface *surface = wayland_surface(nsurf);
398 enum wayland_buffer_type buffer;
399
400 for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) {
401 if (surface->buffer[buffer])
402 wl_buffer_destroy(surface->buffer[buffer]);
403 }
404
405 resource_surface_destroy(surface->rsurf);
406 FREE(surface);
407 }
408
409
410
411 static struct native_surface *
412 wayland_create_pixmap_surface(struct native_display *ndpy,
413 EGLNativePixmapType pix,
414 const struct native_config *nconf)
415 {
416 struct wayland_display *display = wayland_display(ndpy);
417 struct wayland_surface *surface;
418 struct wl_egl_pixmap *egl_pixmap = (struct wl_egl_pixmap *) pix;
419 enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT;
420 uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
421 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT;
422
423 surface = CALLOC_STRUCT(wayland_surface);
424 if (!surface)
425 return NULL;
426
427 surface->display = display;
428
429 surface->pending_resource = NULL;
430 surface->type = WL_PIXMAP_SURFACE;
431 surface->pix = egl_pixmap;
432
433 if (nconf)
434 surface->color_format = nconf->color_format;
435 else /* FIXME: derive format from wl_visual */
436 surface->color_format = PIPE_FORMAT_B8G8R8A8_UNORM;
437
438 surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
439
440 surface->rsurf = resource_surface_create(display->base.screen,
441 surface->color_format, bind);
442
443 if (!surface->rsurf) {
444 FREE(surface);
445 return NULL;
446 }
447
448 resource_surface_set_size(surface->rsurf,
449 egl_pixmap->width, egl_pixmap->height);
450
451 /* the pixmap is already allocated, so import it */
452 if (surface->pix->buffer != NULL)
453 resource_surface_import_resource(surface->rsurf, natt,
454 surface->pix->driver_private);
455
456 surface->base.destroy = wayland_surface_destroy;
457 surface->base.present = wayland_surface_present;
458 surface->base.validate = wayland_surface_validate;
459 surface->base.wait = wayland_surface_wait;
460
461 return &surface->base;
462 }
463
464
465 static struct native_surface *
466 wayland_create_window_surface(struct native_display *ndpy,
467 EGLNativeWindowType win,
468 const struct native_config *nconf)
469 {
470 struct wayland_display *display = wayland_display(ndpy);
471 struct wayland_config *config = wayland_config(nconf);
472 struct wayland_surface *surface;
473 uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
474 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT;
475
476 surface = CALLOC_STRUCT(wayland_surface);
477 if (!surface)
478 return NULL;
479
480 surface->display = display;
481 surface->color_format = config->base.color_format;
482
483 surface->win = (struct wl_egl_window *) win;
484
485 surface->pending_resource = NULL;
486 surface->frame_callback = NULL;
487 surface->type = WL_WINDOW_SURFACE;
488
489 surface->buffer[WL_BUFFER_FRONT] = NULL;
490 surface->buffer[WL_BUFFER_BACK] = NULL;
491 surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
492 (1 << NATIVE_ATTACHMENT_BACK_LEFT);
493
494 surface->rsurf = resource_surface_create(display->base.screen,
495 surface->color_format, bind);
496
497 if (!surface->rsurf) {
498 FREE(surface);
499 return NULL;
500 }
501
502 surface->base.destroy = wayland_surface_destroy;
503 surface->base.present = wayland_surface_present;
504 surface->base.validate = wayland_surface_validate;
505 surface->base.wait = wayland_surface_wait;
506
507 return &surface->base;
508 }
509
510 static struct native_display *
511 native_create_display(void *dpy, boolean use_sw)
512 {
513 struct wayland_display *display = NULL;
514 boolean own_dpy = FALSE;
515
516 use_sw = use_sw || debug_get_bool_option("EGL_SOFTWARE", FALSE);
517
518 if (dpy == NULL) {
519 dpy = wl_display_connect(NULL);
520 if (dpy == NULL)
521 return NULL;
522 own_dpy = TRUE;
523 }
524
525 if (use_sw) {
526 _eglLog(_EGL_INFO, "use software fallback");
527 display = wayland_create_shm_display((struct wl_display *) dpy,
528 wayland_event_handler);
529 } else {
530 display = wayland_create_drm_display((struct wl_display *) dpy,
531 wayland_event_handler);
532 }
533
534 if (!display)
535 return NULL;
536
537 display->base.get_param = wayland_display_get_param;
538 display->base.get_configs = wayland_display_get_configs;
539 display->base.get_pixmap_format = wayland_display_get_pixmap_format;
540 display->base.copy_to_pixmap = native_display_copy_to_pixmap;
541 display->base.create_window_surface = wayland_create_window_surface;
542 display->base.create_pixmap_surface = wayland_create_pixmap_surface;
543
544 display->own_dpy = own_dpy;
545
546 return &display->base;
547 }
548
549 static const struct native_platform wayland_platform = {
550 "wayland", /* name */
551 native_create_display
552 };
553
554 const struct native_platform *
555 native_get_wayland_platform(const struct native_event_handler *event_handler)
556 {
557 wayland_event_handler = event_handler;
558 return &wayland_platform;
559 }
560
561 /* vim: set sw=3 ts=8 sts=3 expandtab: */