egl: Add EGL_WL_bind_wayland_display
[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
35 #include "egllog.h"
36
37 #include "native_wayland.h"
38
39 /* see get_drm_screen_name */
40 #include <radeon_drm.h>
41 #include "radeon/drm/radeon_drm_public.h"
42
43 #include <wayland-client.h>
44 #include "wayland-drm-client-protocol.h"
45 #include "wayland-egl-priv.h"
46
47 #include <xf86drm.h>
48
49 static struct native_event_handler *wayland_event_handler;
50
51 static void
52 sync_callback(void *data)
53 {
54 int *done = data;
55
56 *done = 1;
57 }
58
59 static void
60 force_roundtrip(struct wl_display *display)
61 {
62 int done = 0;
63
64 wl_display_sync_callback(display, sync_callback, &done);
65 wl_display_iterate(display, WL_DISPLAY_WRITABLE);
66 while (!done)
67 wl_display_iterate(display, WL_DISPLAY_READABLE);
68 }
69
70 static const struct native_config **
71 wayland_display_get_configs (struct native_display *ndpy, int *num_configs)
72 {
73 struct wayland_display *display = wayland_display(ndpy);
74 const struct native_config **configs;
75
76 if (!display->config) {
77 struct native_config *nconf;
78 enum pipe_format format;
79 display->config = CALLOC(1, sizeof(*display->config));
80 if (!display->config)
81 return NULL;
82 nconf = &display->config->base;
83
84 nconf->buffer_mask =
85 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
86 (1 << NATIVE_ATTACHMENT_BACK_LEFT);
87
88 format = PIPE_FORMAT_B8G8R8A8_UNORM;
89
90 nconf->color_format = format;
91 nconf->window_bit = TRUE;
92 nconf->pixmap_bit = TRUE;
93 }
94
95 configs = MALLOC(sizeof(*configs));
96 if (configs) {
97 configs[0] = &display->config->base;
98 if (num_configs)
99 *num_configs = 1;
100 }
101
102 return configs;
103 }
104
105 static int
106 wayland_display_get_param(struct native_display *ndpy,
107 enum native_param_type param)
108 {
109 int val;
110
111 switch (param) {
112 case NATIVE_PARAM_USE_NATIVE_BUFFER:
113 case NATIVE_PARAM_PRESERVE_BUFFER:
114 case NATIVE_PARAM_MAX_SWAP_INTERVAL:
115 default:
116 val = 0;
117 break;
118 }
119
120 return val;
121 }
122
123 static boolean
124 wayland_display_is_pixmap_supported(struct native_display *ndpy,
125 EGLNativePixmapType pix,
126 const struct native_config *nconf)
127 {
128 /* all wl_egl_pixmaps are supported */
129
130 return TRUE;
131 }
132
133 static void
134 wayland_display_destroy(struct native_display *ndpy)
135 {
136 struct wayland_display *display = wayland_display(ndpy);
137
138 if (display->config)
139 FREE(display->config);
140
141 ndpy_uninit(ndpy);
142
143 FREE(display);
144 }
145
146
147 static struct wl_buffer *
148 wayland_create_buffer(struct wayland_surface *surface,
149 enum native_attachment attachment)
150 {
151 struct wayland_display *display = surface->display;
152 struct pipe_resource *resource;
153 struct winsys_handle wsh;
154 uint width, height;
155
156 resource = resource_surface_get_single_resource(surface->rsurf, attachment);
157 resource_surface_get_size(surface->rsurf, &width, &height);
158
159 wsh.type = DRM_API_HANDLE_TYPE_SHARED;
160 display->base.screen->resource_get_handle(display->base.screen, resource, &wsh);
161
162 pipe_resource_reference(&resource, NULL);
163
164 return wl_drm_create_buffer(display->dpy->drm, wsh.handle,
165 width, height,
166 wsh.stride, surface->win->visual);
167 }
168
169 static void
170 wayland_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
171 {
172 struct pipe_resource *resource = egl_pixmap->driver_private;
173
174 assert(resource);
175
176 pipe_resource_reference(&resource, NULL);
177
178 egl_pixmap->driver_private = NULL;
179 egl_pixmap->destroy = NULL;
180 egl_pixmap->name = 0;
181 }
182
183 static void
184 wayland_pixmap_surface_intialize(struct wayland_surface *surface)
185 {
186 struct native_display *ndpy = &surface->display->base;
187 struct pipe_resource *resource;
188 struct winsys_handle wsh;
189 const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
190
191 if (surface->pix->name > 0)
192 return;
193
194 resource = resource_surface_get_single_resource(surface->rsurf, front_natt);
195
196 wsh.type = DRM_API_HANDLE_TYPE_SHARED;
197 ndpy->screen->resource_get_handle(ndpy->screen, resource, &wsh);
198
199 surface->pix->name = wsh.handle;
200 surface->pix->stride = wsh.stride;
201 surface->pix->destroy = wayland_pixmap_destroy;
202 surface->pix->driver_private = resource;
203 }
204
205 static void
206 wayland_release_pending_resource(void *data)
207 {
208 struct wayland_surface *surface = data;
209
210 /* FIXME: print internal error */
211 if (!surface->pending_resource)
212 return;
213
214 pipe_resource_reference(&surface->pending_resource, NULL);
215 }
216
217 static void
218 wayland_window_surface_handle_resize(struct wayland_surface *surface)
219 {
220 struct wayland_display *display = surface->display;
221 struct pipe_resource *front_resource;
222 const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
223 int i;
224
225 front_resource = resource_surface_get_single_resource(surface->rsurf,
226 front_natt);
227 if (resource_surface_set_size(surface->rsurf,
228 surface->win->width, surface->win->height)) {
229
230 if (surface->pending_resource)
231 force_roundtrip(display->dpy->display);
232
233 if (front_resource) {
234 surface->pending_resource = front_resource;
235 front_resource = NULL;
236 wl_display_sync_callback(display->dpy->display,
237 wayland_release_pending_resource, surface);
238 }
239
240 for (i = 0; i < WL_BUFFER_COUNT; ++i) {
241 if (surface->buffer[i])
242 wl_buffer_destroy(surface->buffer[i]);
243 surface->buffer[i] = NULL;
244 }
245 }
246 pipe_resource_reference(&front_resource, NULL);
247
248 surface->dx = surface->win->dx;
249 surface->dy = surface->win->dy;
250 surface->win->dx = 0;
251 surface->win->dy = 0;
252 }
253
254 static boolean
255 wayland_surface_validate(struct native_surface *nsurf, uint attachment_mask,
256 unsigned int *seq_num, struct pipe_resource **textures,
257 int *width, int *height)
258 {
259 struct wayland_surface *surface = wayland_surface(nsurf);
260
261 if (surface->type == WL_WINDOW_SURFACE)
262 wayland_window_surface_handle_resize(surface);
263
264 if (!resource_surface_add_resources(surface->rsurf, attachment_mask |
265 surface->attachment_mask))
266 return FALSE;
267
268 if (textures)
269 resource_surface_get_resources(surface->rsurf, textures, attachment_mask);
270
271 if (seq_num)
272 *seq_num = surface->sequence_number;
273
274 resource_surface_get_size(surface->rsurf, (uint *) width, (uint *) height);
275
276 if (surface->type == WL_PIXMAP_SURFACE)
277 wayland_pixmap_surface_intialize(surface);
278
279 return TRUE;
280 }
281
282 static void
283 wayland_frame_callback(void *data, uint32_t time)
284 {
285 struct wayland_surface *surface = data;
286
287 surface->block_swap_buffers = FALSE;
288 }
289
290 static INLINE void
291 wayland_buffers_swap(struct wl_buffer **buffer,
292 enum wayland_buffer_type buf1,
293 enum wayland_buffer_type buf2)
294 {
295 struct wl_buffer *tmp = buffer[buf1];
296 buffer[buf1] = buffer[buf2];
297 buffer[buf2] = tmp;
298 }
299
300 static boolean
301 wayland_surface_swap_buffers(struct native_surface *nsurf)
302 {
303 struct wayland_surface *surface = wayland_surface(nsurf);
304 struct wayland_display *display = surface->display;
305
306 while (surface->block_swap_buffers)
307 wl_display_iterate(display->dpy->display, WL_DISPLAY_READABLE);
308
309 surface->block_swap_buffers = TRUE;
310 wl_display_frame_callback(display->dpy->display, wayland_frame_callback,
311 surface);
312
313 if (surface->type == WL_WINDOW_SURFACE) {
314 resource_surface_swap_buffers(surface->rsurf,
315 NATIVE_ATTACHMENT_FRONT_LEFT, 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 wayland_create_buffer(surface, NATIVE_ATTACHMENT_FRONT_LEFT);
322
323 wl_surface_attach(surface->win->surface, surface->buffer[WL_BUFFER_FRONT],
324 surface->dx, surface->dy);
325
326 resource_surface_get_size(surface->rsurf,
327 (uint *) &surface->win->attached_width,
328 (uint *) &surface->win->attached_height);
329 surface->dx = 0;
330 surface->dy = 0;
331 }
332
333 surface->sequence_number++;
334 wayland_event_handler->invalid_surface(&display->base,
335 &surface->base, surface->sequence_number);
336
337 return TRUE;
338 }
339
340 static boolean
341 wayland_surface_present(struct native_surface *nsurf,
342 enum native_attachment natt,
343 boolean preserve,
344 uint swap_interval)
345 {
346 struct wayland_surface *surface = wayland_surface(nsurf);
347 uint width, height;
348 boolean ret;
349
350 if (preserve || swap_interval)
351 return FALSE;
352
353 switch (natt) {
354 case NATIVE_ATTACHMENT_FRONT_LEFT:
355 ret = TRUE;
356 break;
357 case NATIVE_ATTACHMENT_BACK_LEFT:
358 ret = wayland_surface_swap_buffers(nsurf);
359 break;
360 default:
361 ret = FALSE;
362 break;
363 }
364
365 if (surface->type == WL_WINDOW_SURFACE) {
366 resource_surface_get_size(surface->rsurf, &width, &height);
367 wl_surface_damage(surface->win->surface, 0, 0, width, height);
368 }
369
370 return ret;
371 }
372
373 static void
374 wayland_surface_wait(struct native_surface *nsurf)
375 {
376 /* no-op */
377 }
378
379 static void
380 wayland_surface_destroy(struct native_surface *nsurf)
381 {
382 struct wayland_surface *surface = wayland_surface(nsurf);
383 enum wayland_buffer_type buffer;
384
385 for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) {
386 if (surface->buffer[buffer])
387 wl_buffer_destroy(surface->buffer[buffer]);
388 }
389
390 resource_surface_destroy(surface->rsurf);
391 FREE(surface);
392 }
393
394 static struct native_surface *
395 wayland_create_pixmap_surface(struct native_display *ndpy,
396 EGLNativePixmapType pix,
397 const struct native_config *nconf)
398 {
399 struct wayland_display *display = wayland_display(ndpy);
400 struct wayland_config *config = wayland_config(nconf);
401 struct wayland_surface *surface;
402 struct wl_egl_pixmap *egl_pixmap = (struct wl_egl_pixmap *) pix;
403 enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT;
404
405 surface = CALLOC_STRUCT(wayland_surface);
406 if (!surface)
407 return NULL;
408
409 surface->display = display;
410
411 surface->pending_resource = NULL;
412 surface->type = WL_PIXMAP_SURFACE;
413 surface->pix = egl_pixmap;
414
415 if (surface->pix->visual == wl_display_get_rgb_visual(display->dpy->display))
416 surface->color_format = PIPE_FORMAT_B8G8R8X8_UNORM;
417 else
418 surface->color_format = PIPE_FORMAT_B8G8R8A8_UNORM;
419
420 surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
421
422 surface->rsurf = resource_surface_create(display->base.screen,
423 surface->color_format,
424 PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
425 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT);
426
427 if (!surface->rsurf) {
428 FREE(surface);
429 return NULL;
430 }
431
432 resource_surface_set_size(surface->rsurf,
433 egl_pixmap->width, egl_pixmap->height);
434
435 /* the pixmap is already allocated, so import it */
436 if (surface->pix->name > 0)
437 resource_surface_import_resource(surface->rsurf, natt,
438 surface->pix->driver_private);
439
440 surface->base.destroy = wayland_surface_destroy;
441 surface->base.present = wayland_surface_present;
442 surface->base.validate = wayland_surface_validate;
443 surface->base.wait = wayland_surface_wait;
444
445 return &surface->base;
446 }
447
448 static struct native_surface *
449 wayland_create_window_surface(struct native_display *ndpy,
450 EGLNativeWindowType win,
451 const struct native_config *nconf)
452 {
453 struct wayland_display *display = wayland_display(ndpy);
454 struct wayland_config *config = wayland_config(nconf);
455 struct wayland_surface *surface;
456
457 surface = CALLOC_STRUCT(wayland_surface);
458 if (!surface)
459 return NULL;
460
461 surface->display = display;
462 surface->color_format = config->base.color_format;
463
464 surface->win = (struct wl_egl_window *) win;
465
466 surface->pending_resource = NULL;
467 surface->block_swap_buffers = FALSE;
468 surface->type = WL_WINDOW_SURFACE;
469
470 surface->buffer[WL_BUFFER_FRONT] = NULL;
471 surface->buffer[WL_BUFFER_BACK] = NULL;
472 surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
473 (1 << NATIVE_ATTACHMENT_BACK_LEFT);
474
475 surface->rsurf = resource_surface_create(display->base.screen,
476 surface->color_format,
477 PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
478 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT);
479
480 if (!surface->rsurf) {
481 FREE(surface);
482 return NULL;
483 }
484
485 surface->base.destroy = wayland_surface_destroy;
486 surface->base.present = wayland_surface_present;
487 surface->base.validate = wayland_surface_validate;
488 surface->base.wait = wayland_surface_wait;
489
490 return &surface->base;
491 }
492
493 static const char *
494 get_drm_screen_name(int fd, drmVersionPtr version)
495 {
496 const char *name = version->name;
497
498 if (name && !strcmp(name, "radeon")) {
499 int chip_id;
500 struct drm_radeon_info info;
501
502 memset(&info, 0, sizeof(info));
503 info.request = RADEON_INFO_DEVICE_ID;
504 info.value = pointer_to_intptr(&chip_id);
505 if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0)
506 return NULL;
507
508 name = is_r3xx(chip_id) ? "r300" : "r600";
509 }
510
511 return name;
512 }
513
514 static boolean
515 wayland_display_init_screen(struct native_display *ndpy)
516 {
517 struct wayland_display *display = wayland_display(ndpy);
518 drmVersionPtr version;
519 const char *driver_name;
520
521 if (display->dpy->fd == -1)
522 force_roundtrip(display->dpy->display);
523 if (display->dpy->fd == -1)
524 return FALSE;
525
526 if (!display->dpy->authenticated)
527 force_roundtrip(display->dpy->display);
528 if (!display->dpy->authenticated)
529 return FALSE;
530
531 version = drmGetVersion(display->dpy->fd);
532 if (!version) {
533 _eglLog(_EGL_WARNING, "invalid fd %d", display->dpy->fd);
534 return FALSE;
535 }
536
537 /* FIXME: share this with native_drm or egl_dri2 */
538 driver_name = get_drm_screen_name(display->dpy->fd, version);
539
540 display->base.screen =
541 wayland_event_handler->new_drm_screen(&display->base,
542 driver_name, display->dpy->fd);
543 drmFreeVersion(version);
544
545 if (!display->base.screen) {
546 _eglLog(_EGL_WARNING, "failed to create DRM screen");
547 return FALSE;
548 }
549
550 return TRUE;
551 }
552
553
554 static void
555 wayland_set_event_handler(struct native_event_handler *event_handler)
556 {
557 wayland_event_handler = event_handler;
558 }
559
560 static struct pipe_resource *
561 wayland_display_import_buffer(struct native_display *ndpy,
562 const struct pipe_resource *templ,
563 void *buf)
564 {
565 return ndpy->screen->resource_from_handle(ndpy->screen,
566 templ, (struct winsys_handle *) buf);
567 }
568
569 static boolean
570 wayland_display_export_buffer(struct native_display *ndpy,
571 struct pipe_resource *res,
572 void *buf)
573 {
574 return ndpy->screen->resource_get_handle(ndpy->screen,
575 res, (struct winsys_handle *) buf);
576 }
577
578 static struct native_display_buffer wayland_display_buffer = {
579 wayland_display_import_buffer,
580 wayland_display_export_buffer
581 };
582
583 static struct native_display *
584 wayland_display_create(void *dpy, boolean use_sw, void *user_data)
585 {
586 struct wayland_display *display;
587
588 display = CALLOC_STRUCT(wayland_display);
589 if (!display)
590 return NULL;
591
592 display->base.user_data = user_data;
593
594 display->dpy = dpy;
595 if (!display->dpy->display) {
596 wayland_display_destroy(&display->base);
597 return NULL;
598 }
599
600 if (!wayland_display_init_screen(&display->base)) {
601 wayland_display_destroy(&display->base);
602 return NULL;
603 }
604
605 display->base.destroy = wayland_display_destroy;
606 display->base.get_param = wayland_display_get_param;
607 display->base.get_configs = wayland_display_get_configs;
608 display->base.is_pixmap_supported = wayland_display_is_pixmap_supported;
609 display->base.create_window_surface = wayland_create_window_surface;
610 display->base.create_pixmap_surface = wayland_create_pixmap_surface;
611 display->base.buffer = &wayland_display_buffer;
612
613 return &display->base;
614 }
615
616 static const struct native_platform wayland_platform = {
617 "wayland", /* name */
618 wayland_set_event_handler,
619 wayland_display_create
620 };
621
622 const struct native_platform *
623 native_get_wayland_platform(void)
624 {
625 return &wayland_platform;
626 }