2 * Mesa 3-D graphics library
5 * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 #include "util/u_memory.h"
27 #include "util/u_inlines.h"
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"
36 #include "native_wayland.h"
39 sync_callback(void *data
, struct wl_callback
*callback
, uint32_t serial
)
44 wl_callback_destroy(callback
);
47 static const struct wl_callback_listener sync_listener
= {
52 wayland_roundtrip(struct wayland_display
*display
)
54 struct wl_callback
*callback
;
55 int done
= 0, ret
= 0;
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
);
66 static const struct native_event_handler
*wayland_event_handler
;
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
},
76 static const struct native_config
**
77 wayland_display_get_configs(struct native_display
*ndpy
, int *num_configs
)
79 struct wayland_display
*display
= wayland_display(ndpy
);
80 const struct native_config
**configs
;
83 if (!display
->configs
) {
84 struct native_config
*nconf
;
86 display
->num_configs
= 0;
87 display
->configs
= CALLOC(Elements(wayland_formats
),
88 sizeof(*display
->configs
));
89 if (!display
->configs
)
92 for (i
= 0; i
< Elements(wayland_formats
); ++i
) {
93 if (!(display
->formats
& wayland_formats
[i
].flag
))
96 nconf
= &display
->configs
[display
->num_configs
].base
;
98 (1 << NATIVE_ATTACHMENT_FRONT_LEFT
) |
99 (1 << NATIVE_ATTACHMENT_BACK_LEFT
);
101 nconf
->window_bit
= TRUE
;
102 nconf
->pixmap_bit
= TRUE
;
104 nconf
->color_format
= wayland_formats
[i
].format
;
105 display
->num_configs
++;
109 configs
= MALLOC(display
->num_configs
* sizeof(*configs
));
111 for (i
= 0; i
< display
->num_configs
; ++i
)
112 configs
[i
] = &display
->configs
[i
].base
;
114 *num_configs
= display
->num_configs
;
121 wayland_display_get_param(struct native_display
*ndpy
,
122 enum native_param_type param
)
127 case NATIVE_PARAM_PREMULTIPLIED_ALPHA
:
130 case NATIVE_PARAM_USE_NATIVE_BUFFER
:
131 case NATIVE_PARAM_PRESERVE_BUFFER
:
132 case NATIVE_PARAM_MAX_SWAP_INTERVAL
:
142 wayland_display_get_pixmap_format(struct native_display
*ndpy
,
143 EGLNativePixmapType pix
,
144 enum pipe_format
*format
)
146 /* all wl_egl_pixmaps are supported */
147 *format
= PIPE_FORMAT_NONE
;
153 wayland_pixmap_destroy(struct wl_egl_pixmap
*egl_pixmap
)
155 struct pipe_resource
*resource
= egl_pixmap
->driver_private
;
159 pipe_resource_reference(&resource
, NULL
);
160 if (egl_pixmap
->buffer
) {
161 wl_buffer_destroy(egl_pixmap
->buffer
);
162 egl_pixmap
->buffer
= NULL
;
165 egl_pixmap
->driver_private
= NULL
;
166 egl_pixmap
->destroy
= NULL
;
170 wayland_pixmap_surface_initialize(struct wayland_surface
*surface
)
172 struct wayland_display
*display
= wayland_display(&surface
->display
->base
);
173 const enum native_attachment front_natt
= NATIVE_ATTACHMENT_FRONT_LEFT
;
175 if (surface
->pix
->buffer
!= NULL
)
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
);
185 wayland_release_pending_resource(void *data
,
186 struct wl_callback
*callback
,
189 struct wayland_surface
*surface
= data
;
191 wl_callback_destroy(callback
);
193 /* FIXME: print internal error */
194 if (!surface
->pending_resource
)
197 pipe_resource_reference(&surface
->pending_resource
, NULL
);
200 static const struct wl_callback_listener release_buffer_listener
= {
201 wayland_release_pending_resource
205 wayland_window_surface_handle_resize(struct wayland_surface
*surface
)
207 struct wayland_display
*display
= surface
->display
;
208 struct pipe_resource
*front_resource
;
209 const enum native_attachment front_natt
= NATIVE_ATTACHMENT_FRONT_LEFT
;
212 front_resource
= resource_surface_get_single_resource(surface
->rsurf
,
214 if (resource_surface_set_size(surface
->rsurf
,
215 surface
->win
->width
, surface
->win
->height
)) {
217 if (surface
->pending_resource
)
218 wayland_roundtrip(display
);
220 if (front_resource
) {
221 struct wl_callback
*callback
;
223 surface
->pending_resource
= front_resource
;
224 front_resource
= NULL
;
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
);
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
;
237 surface
->dx
= surface
->win
->dx
;
238 surface
->dy
= surface
->win
->dy
;
240 pipe_resource_reference(&front_resource
, NULL
);
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
)
248 struct wayland_surface
*surface
= wayland_surface(nsurf
);
250 if (surface
->type
== WL_WINDOW_SURFACE
)
251 wayland_window_surface_handle_resize(surface
);
253 if (!resource_surface_add_resources(surface
->rsurf
, attachment_mask
|
254 surface
->attachment_mask
))
258 resource_surface_get_resources(surface
->rsurf
, textures
, attachment_mask
);
261 *seq_num
= surface
->sequence_number
;
263 resource_surface_get_size(surface
->rsurf
, (uint
*) width
, (uint
*) height
);
265 if (surface
->type
== WL_PIXMAP_SURFACE
)
266 wayland_pixmap_surface_initialize(surface
);
272 wayland_frame_callback(void *data
, struct wl_callback
*callback
, uint32_t time
)
274 struct wayland_surface
*surface
= data
;
276 surface
->frame_callback
= NULL
;
278 wl_callback_destroy(callback
);
281 static const struct wl_callback_listener frame_listener
= {
282 wayland_frame_callback
286 wayland_buffers_swap(struct wl_buffer
**buffer
,
287 enum wayland_buffer_type buf1
,
288 enum wayland_buffer_type buf2
)
290 struct wl_buffer
*tmp
= buffer
[buf1
];
291 buffer
[buf1
] = buffer
[buf2
];
296 wayland_surface_swap_buffers(struct native_surface
*nsurf
)
298 struct wayland_surface
*surface
= wayland_surface(nsurf
);
299 struct wayland_display
*display
= surface
->display
;
302 while (surface
->frame_callback
&& ret
!= -1)
303 ret
= wl_display_dispatch_queue(display
->dpy
, display
->queue
);
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
,
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
);
317 wayland_buffers_swap(surface
->buffer
, WL_BUFFER_FRONT
, WL_BUFFER_BACK
);
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
);
324 wl_surface_attach(surface
->win
->surface
, surface
->buffer
[WL_BUFFER_FRONT
],
325 surface
->dx
, surface
->dy
);
327 resource_surface_get_size(surface
->rsurf
,
328 (uint
*) &surface
->win
->attached_width
,
329 (uint
*) &surface
->win
->attached_height
);
334 surface
->sequence_number
++;
335 wayland_event_handler
->invalid_surface(&display
->base
,
337 surface
->sequence_number
);
343 wayland_surface_present(struct native_surface
*nsurf
,
344 const struct native_present_control
*ctrl
)
346 struct wayland_surface
*surface
= wayland_surface(nsurf
);
350 if (ctrl
->preserve
|| ctrl
->swap_interval
)
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
;
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
;
364 surface
->premultiplied_alpha
= ctrl
->premultiplied_alpha
;
367 switch (ctrl
->natt
) {
368 case NATIVE_ATTACHMENT_FRONT_LEFT
:
371 case NATIVE_ATTACHMENT_BACK_LEFT
:
372 ret
= wayland_surface_swap_buffers(nsurf
);
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
);
389 wayland_surface_wait(struct native_surface
*nsurf
)
395 wayland_surface_destroy(struct native_surface
*nsurf
)
397 struct wayland_surface
*surface
= wayland_surface(nsurf
);
398 enum wayland_buffer_type buffer
;
400 for (buffer
= 0; buffer
< WL_BUFFER_COUNT
; ++buffer
) {
401 if (surface
->buffer
[buffer
])
402 wl_buffer_destroy(surface
->buffer
[buffer
]);
405 resource_surface_destroy(surface
->rsurf
);
411 static struct native_surface
*
412 wayland_create_pixmap_surface(struct native_display
*ndpy
,
413 EGLNativePixmapType pix
,
414 const struct native_config
*nconf
)
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
;
423 surface
= CALLOC_STRUCT(wayland_surface
);
427 surface
->display
= display
;
429 surface
->pending_resource
= NULL
;
430 surface
->type
= WL_PIXMAP_SURFACE
;
431 surface
->pix
= egl_pixmap
;
434 surface
->color_format
= nconf
->color_format
;
435 else /* FIXME: derive format from wl_visual */
436 surface
->color_format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
438 surface
->attachment_mask
= (1 << NATIVE_ATTACHMENT_FRONT_LEFT
);
440 surface
->rsurf
= resource_surface_create(display
->base
.screen
,
441 surface
->color_format
, bind
);
443 if (!surface
->rsurf
) {
448 resource_surface_set_size(surface
->rsurf
,
449 egl_pixmap
->width
, egl_pixmap
->height
);
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
);
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
;
461 return &surface
->base
;
465 static struct native_surface
*
466 wayland_create_window_surface(struct native_display
*ndpy
,
467 EGLNativeWindowType win
,
468 const struct native_config
*nconf
)
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
;
476 surface
= CALLOC_STRUCT(wayland_surface
);
480 surface
->display
= display
;
481 surface
->color_format
= config
->base
.color_format
;
483 surface
->win
= (struct wl_egl_window
*) win
;
485 surface
->pending_resource
= NULL
;
486 surface
->frame_callback
= NULL
;
487 surface
->type
= WL_WINDOW_SURFACE
;
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
);
494 surface
->rsurf
= resource_surface_create(display
->base
.screen
,
495 surface
->color_format
, bind
);
497 if (!surface
->rsurf
) {
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
;
507 return &surface
->base
;
510 static struct native_display
*
511 native_create_display(void *dpy
, boolean use_sw
)
513 struct wayland_display
*display
= NULL
;
514 boolean own_dpy
= FALSE
;
516 use_sw
= use_sw
|| debug_get_bool_option("EGL_SOFTWARE", FALSE
);
519 dpy
= wl_display_connect(NULL
);
526 _eglLog(_EGL_INFO
, "use software fallback");
527 display
= wayland_create_shm_display((struct wl_display
*) dpy
,
528 wayland_event_handler
);
530 display
= wayland_create_drm_display((struct wl_display
*) dpy
,
531 wayland_event_handler
);
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
;
544 display
->own_dpy
= own_dpy
;
546 return &display
->base
;
549 static const struct native_platform wayland_platform
= {
550 "wayland", /* name */
551 native_create_display
554 const struct native_platform
*
555 native_get_wayland_platform(const struct native_event_handler
*event_handler
)
557 wayland_event_handler
= event_handler
;
558 return &wayland_platform
;
561 /* vim: set sw=3 ts=8 sts=3 expandtab: */