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"
37 #include "native_wayland.h"
39 /* see get_drm_screen_name */
40 #include <radeon_drm.h>
41 #include "radeon/drm/radeon_drm_public.h"
43 #include <wayland-client.h>
44 #include "wayland-drm-client-protocol.h"
45 #include "wayland-egl-priv.h"
49 static struct native_event_handler
*wayland_event_handler
;
52 sync_callback(void *data
)
60 force_roundtrip(struct wl_display
*display
)
64 wl_display_sync_callback(display
, sync_callback
, &done
);
65 wl_display_iterate(display
, WL_DISPLAY_WRITABLE
);
67 wl_display_iterate(display
, WL_DISPLAY_READABLE
);
70 static const struct native_config
**
71 wayland_display_get_configs (struct native_display
*ndpy
, int *num_configs
)
73 struct wayland_display
*display
= wayland_display(ndpy
);
74 const struct native_config
**configs
;
76 if (!display
->config
) {
77 struct native_config
*nconf
;
78 enum pipe_format format
;
79 display
->config
= CALLOC(1, sizeof(*display
->config
));
82 nconf
= &display
->config
->base
;
85 (1 << NATIVE_ATTACHMENT_FRONT_LEFT
) |
86 (1 << NATIVE_ATTACHMENT_BACK_LEFT
);
88 format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
90 nconf
->color_format
= format
;
91 nconf
->window_bit
= TRUE
;
92 nconf
->pixmap_bit
= TRUE
;
95 configs
= MALLOC(sizeof(*configs
));
97 configs
[0] = &display
->config
->base
;
106 wayland_display_get_param(struct native_display
*ndpy
,
107 enum native_param_type param
)
112 case NATIVE_PARAM_USE_NATIVE_BUFFER
:
113 case NATIVE_PARAM_PRESERVE_BUFFER
:
114 case NATIVE_PARAM_MAX_SWAP_INTERVAL
:
124 wayland_display_is_pixmap_supported(struct native_display
*ndpy
,
125 EGLNativePixmapType pix
,
126 const struct native_config
*nconf
)
128 /* all wl_egl_pixmaps are supported */
134 wayland_display_destroy(struct native_display
*ndpy
)
136 struct wayland_display
*display
= wayland_display(ndpy
);
139 FREE(display
->config
);
147 static struct wl_buffer
*
148 wayland_create_buffer(struct wayland_surface
*surface
,
149 enum native_attachment attachment
)
151 struct wayland_display
*display
= surface
->display
;
152 struct pipe_resource
*resource
;
153 struct winsys_handle wsh
;
156 resource
= resource_surface_get_single_resource(surface
->rsurf
, attachment
);
157 resource_surface_get_size(surface
->rsurf
, &width
, &height
);
159 wsh
.type
= DRM_API_HANDLE_TYPE_SHARED
;
160 display
->base
.screen
->resource_get_handle(display
->base
.screen
, resource
, &wsh
);
162 pipe_resource_reference(&resource
, NULL
);
164 return wl_drm_create_buffer(display
->dpy
->drm
, wsh
.handle
,
166 wsh
.stride
, surface
->win
->visual
);
170 wayland_pixmap_destroy(struct wl_egl_pixmap
*egl_pixmap
)
172 struct pipe_resource
*resource
= egl_pixmap
->driver_private
;
176 pipe_resource_reference(&resource
, NULL
);
178 egl_pixmap
->driver_private
= NULL
;
179 egl_pixmap
->destroy
= NULL
;
180 egl_pixmap
->name
= 0;
184 wayland_pixmap_surface_intialize(struct wayland_surface
*surface
)
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
;
191 if (surface
->pix
->name
> 0)
194 resource
= resource_surface_get_single_resource(surface
->rsurf
, front_natt
);
196 wsh
.type
= DRM_API_HANDLE_TYPE_SHARED
;
197 ndpy
->screen
->resource_get_handle(ndpy
->screen
, resource
, &wsh
);
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
;
206 wayland_release_pending_resource(void *data
)
208 struct wayland_surface
*surface
= data
;
210 /* FIXME: print internal error */
211 if (!surface
->pending_resource
)
214 pipe_resource_reference(&surface
->pending_resource
, NULL
);
218 wayland_window_surface_handle_resize(struct wayland_surface
*surface
)
220 struct wayland_display
*display
= surface
->display
;
221 struct pipe_resource
*front_resource
;
222 const enum native_attachment front_natt
= NATIVE_ATTACHMENT_FRONT_LEFT
;
225 front_resource
= resource_surface_get_single_resource(surface
->rsurf
,
227 if (resource_surface_set_size(surface
->rsurf
,
228 surface
->win
->width
, surface
->win
->height
)) {
230 if (surface
->pending_resource
)
231 force_roundtrip(display
->dpy
->display
);
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
);
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
;
246 pipe_resource_reference(&front_resource
, NULL
);
248 surface
->dx
= surface
->win
->dx
;
249 surface
->dy
= surface
->win
->dy
;
250 surface
->win
->dx
= 0;
251 surface
->win
->dy
= 0;
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
)
259 struct wayland_surface
*surface
= wayland_surface(nsurf
);
261 if (surface
->type
== WL_WINDOW_SURFACE
)
262 wayland_window_surface_handle_resize(surface
);
264 if (!resource_surface_add_resources(surface
->rsurf
, attachment_mask
|
265 surface
->attachment_mask
))
269 resource_surface_get_resources(surface
->rsurf
, textures
, attachment_mask
);
272 *seq_num
= surface
->sequence_number
;
274 resource_surface_get_size(surface
->rsurf
, (uint
*) width
, (uint
*) height
);
276 if (surface
->type
== WL_PIXMAP_SURFACE
)
277 wayland_pixmap_surface_intialize(surface
);
283 wayland_frame_callback(void *data
, uint32_t time
)
285 struct wayland_surface
*surface
= data
;
287 surface
->block_swap_buffers
= FALSE
;
291 wayland_buffers_swap(struct wl_buffer
**buffer
,
292 enum wayland_buffer_type buf1
,
293 enum wayland_buffer_type buf2
)
295 struct wl_buffer
*tmp
= buffer
[buf1
];
296 buffer
[buf1
] = buffer
[buf2
];
301 wayland_surface_swap_buffers(struct native_surface
*nsurf
)
303 struct wayland_surface
*surface
= wayland_surface(nsurf
);
304 struct wayland_display
*display
= surface
->display
;
306 while (surface
->block_swap_buffers
)
307 wl_display_iterate(display
->dpy
->display
, WL_DISPLAY_READABLE
);
309 surface
->block_swap_buffers
= TRUE
;
310 wl_display_frame_callback(display
->dpy
->display
, wayland_frame_callback
,
313 if (surface
->type
== WL_WINDOW_SURFACE
) {
314 resource_surface_swap_buffers(surface
->rsurf
,
315 NATIVE_ATTACHMENT_FRONT_LEFT
, 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 wayland_create_buffer(surface
, NATIVE_ATTACHMENT_FRONT_LEFT
);
323 wl_surface_attach(surface
->win
->surface
, surface
->buffer
[WL_BUFFER_FRONT
],
324 surface
->dx
, surface
->dy
);
326 resource_surface_get_size(surface
->rsurf
,
327 (uint
*) &surface
->win
->attached_width
,
328 (uint
*) &surface
->win
->attached_height
);
333 surface
->sequence_number
++;
334 wayland_event_handler
->invalid_surface(&display
->base
,
335 &surface
->base
, surface
->sequence_number
);
341 wayland_surface_present(struct native_surface
*nsurf
,
342 enum native_attachment natt
,
346 struct wayland_surface
*surface
= wayland_surface(nsurf
);
350 if (preserve
|| swap_interval
)
354 case NATIVE_ATTACHMENT_FRONT_LEFT
:
357 case NATIVE_ATTACHMENT_BACK_LEFT
:
358 ret
= wayland_surface_swap_buffers(nsurf
);
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
);
374 wayland_surface_wait(struct native_surface
*nsurf
)
380 wayland_surface_destroy(struct native_surface
*nsurf
)
382 struct wayland_surface
*surface
= wayland_surface(nsurf
);
383 enum wayland_buffer_type buffer
;
385 for (buffer
= 0; buffer
< WL_BUFFER_COUNT
; ++buffer
) {
386 if (surface
->buffer
[buffer
])
387 wl_buffer_destroy(surface
->buffer
[buffer
]);
390 resource_surface_destroy(surface
->rsurf
);
394 static struct native_surface
*
395 wayland_create_pixmap_surface(struct native_display
*ndpy
,
396 EGLNativePixmapType pix
,
397 const struct native_config
*nconf
)
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
;
405 surface
= CALLOC_STRUCT(wayland_surface
);
409 surface
->display
= display
;
411 surface
->pending_resource
= NULL
;
412 surface
->type
= WL_PIXMAP_SURFACE
;
413 surface
->pix
= egl_pixmap
;
415 if (surface
->pix
->visual
== wl_display_get_rgb_visual(display
->dpy
->display
))
416 surface
->color_format
= PIPE_FORMAT_B8G8R8X8_UNORM
;
418 surface
->color_format
= PIPE_FORMAT_B8G8R8A8_UNORM
;
420 surface
->attachment_mask
= (1 << NATIVE_ATTACHMENT_FRONT_LEFT
);
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
);
427 if (!surface
->rsurf
) {
432 resource_surface_set_size(surface
->rsurf
,
433 egl_pixmap
->width
, egl_pixmap
->height
);
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
);
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
;
445 return &surface
->base
;
448 static struct native_surface
*
449 wayland_create_window_surface(struct native_display
*ndpy
,
450 EGLNativeWindowType win
,
451 const struct native_config
*nconf
)
453 struct wayland_display
*display
= wayland_display(ndpy
);
454 struct wayland_config
*config
= wayland_config(nconf
);
455 struct wayland_surface
*surface
;
457 surface
= CALLOC_STRUCT(wayland_surface
);
461 surface
->display
= display
;
462 surface
->color_format
= config
->base
.color_format
;
464 surface
->win
= (struct wl_egl_window
*) win
;
466 surface
->pending_resource
= NULL
;
467 surface
->block_swap_buffers
= FALSE
;
468 surface
->type
= WL_WINDOW_SURFACE
;
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
);
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
);
480 if (!surface
->rsurf
) {
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
;
490 return &surface
->base
;
494 get_drm_screen_name(int fd
, drmVersionPtr version
)
496 const char *name
= version
->name
;
498 if (name
&& !strcmp(name
, "radeon")) {
500 struct drm_radeon_info info
;
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)
508 name
= is_r3xx(chip_id
) ? "r300" : "r600";
515 wayland_display_init_screen(struct native_display
*ndpy
)
517 struct wayland_display
*display
= wayland_display(ndpy
);
518 drmVersionPtr version
;
519 const char *driver_name
;
521 if (display
->dpy
->fd
== -1)
522 force_roundtrip(display
->dpy
->display
);
523 if (display
->dpy
->fd
== -1)
526 if (!display
->dpy
->authenticated
)
527 force_roundtrip(display
->dpy
->display
);
528 if (!display
->dpy
->authenticated
)
531 version
= drmGetVersion(display
->dpy
->fd
);
533 _eglLog(_EGL_WARNING
, "invalid fd %d", display
->dpy
->fd
);
537 /* FIXME: share this with native_drm or egl_dri2 */
538 driver_name
= get_drm_screen_name(display
->dpy
->fd
, version
);
540 display
->base
.screen
=
541 wayland_event_handler
->new_drm_screen(&display
->base
,
542 driver_name
, display
->dpy
->fd
);
543 drmFreeVersion(version
);
545 if (!display
->base
.screen
) {
546 _eglLog(_EGL_WARNING
, "failed to create DRM screen");
555 wayland_set_event_handler(struct native_event_handler
*event_handler
)
557 wayland_event_handler
= event_handler
;
560 static struct pipe_resource
*
561 wayland_display_import_buffer(struct native_display
*ndpy
,
562 const struct pipe_resource
*templ
,
565 return ndpy
->screen
->resource_from_handle(ndpy
->screen
,
566 templ
, (struct winsys_handle
*) buf
);
570 wayland_display_export_buffer(struct native_display
*ndpy
,
571 struct pipe_resource
*res
,
574 return ndpy
->screen
->resource_get_handle(ndpy
->screen
,
575 res
, (struct winsys_handle
*) buf
);
578 static struct native_display_buffer wayland_display_buffer
= {
579 wayland_display_import_buffer
,
580 wayland_display_export_buffer
583 static struct native_display
*
584 wayland_display_create(void *dpy
, boolean use_sw
, void *user_data
)
586 struct wayland_display
*display
;
588 display
= CALLOC_STRUCT(wayland_display
);
592 display
->base
.user_data
= user_data
;
595 if (!display
->dpy
->display
) {
596 wayland_display_destroy(&display
->base
);
600 if (!wayland_display_init_screen(&display
->base
)) {
601 wayland_display_destroy(&display
->base
);
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
;
613 return &display
->base
;
616 static const struct native_platform wayland_platform
= {
617 "wayland", /* name */
618 wayland_set_event_handler
,
619 wayland_display_create
622 const struct native_platform
*
623 native_get_wayland_platform(void)
625 return &wayland_platform
;