use wayland-gbm to create/destroy wl_buffer
[mesa-gbm:mesa.git] / src / gallium / state_trackers / egl / wayland / native_drm.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 #include <errno.h>
37
38 #include "native_wayland.h"
39
40 #include <wayland-client.h>
41 #include "wayland-drm-client-protocol.h"
42 #include "wayland-egl-priv.h"
43
44 #include "common/native_wayland_drm_bufmgr_helper.h"
45
46 #include <xf86drm.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50
51 struct wayland_drm_display {
52    struct wayland_display base;
53
54    const struct native_event_handler *event_handler;
55
56    struct wl_gbm *wl_gbm;
57    struct wl_gbm *wl_server_gbm; /* for EGL_WL_bind_wayland_display */
58    int fd;
59    char *device_name;
60    boolean authenticated;
61 };
62
63 static INLINE struct wayland_drm_display *
64 wayland_drm_display(const struct native_display *ndpy)
65 {
66    return (struct wayland_drm_display *) ndpy;
67 }
68
69 static void 
70 wayland_drm_display_destroy(struct native_display *ndpy)
71 {
72    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
73
74    if (drmdpy->fd)
75       close(drmdpy->fd);
76    if (drmdpy->wl_gbm)
77       wl_gbm_destroy(drmdpy->wl_gbm);
78    if (drmdpy->device_name)
79       FREE(drmdpy->device_name);
80    if (drmdpy->base.configs)
81       FREE(drmdpy->base.configs);
82    if (drmdpy->base.own_dpy)
83       wl_display_disconnect(drmdpy->base.dpy);
84
85    ndpy_uninit(ndpy);
86
87    FREE(drmdpy);
88 }
89
90 static struct wl_buffer *
91 wayland_create_drm_buffer(struct wayland_display *display,
92                           struct wayland_surface *surface,
93                           enum native_attachment attachment)
94 {
95    struct wayland_drm_display *drmdpy = (struct wayland_drm_display *) display;
96    struct pipe_screen *screen = drmdpy->base.base.screen;
97    struct pipe_resource *resource;
98    struct winsys_handle wsh;
99    uint width, height;
100    enum wl_gbm_format format;
101
102    resource = resource_surface_get_single_resource(surface->rsurf, attachment);
103    resource_surface_get_size(surface->rsurf, &width, &height);
104
105    wsh.type = DRM_API_HANDLE_TYPE_SHARED;
106    screen->resource_get_handle(screen, resource, &wsh);
107
108    pipe_resource_reference(&resource, NULL);
109
110    switch (surface->color_format) {
111    case PIPE_FORMAT_B8G8R8A8_UNORM:
112       format = WL_GBM_FORMAT_ARGB8888;
113       break;
114    case PIPE_FORMAT_B8G8R8X8_UNORM:
115       format = WL_GBM_FORMAT_XRGB8888;
116       break;
117    default:
118       return NULL;
119       break;
120    }
121
122    return wl_gbm_create_buffer(drmdpy->wl_gbm, wsh.handle,
123                                width, height, wsh.stride, format);
124 }
125
126 static void
127 drm_handle_device(void *data, struct wl_gbm *drm, const char *device)
128 {
129    struct wayland_drm_display *drmdpy = data;
130    drm_magic_t magic;
131
132    drmdpy->device_name = strdup(device);
133    if (!drmdpy->device_name)
134       return;
135
136 #ifdef O_CLOEXEC
137    drmdpy->fd = open(drmdpy->device_name, O_RDWR | O_CLOEXEC);
138    if (drmdpy->fd == -1 && errno == EINVAL)
139 #endif
140    {
141       drmdpy->fd = open(drmdpy->device_name, O_RDWR);
142       if (drmdpy->fd != -1)
143          fcntl(drmdpy->fd, F_SETFD, fcntl(drmdpy->fd, F_GETFD) | FD_CLOEXEC);
144    }
145    if (drmdpy->fd == -1) {
146       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
147               drmdpy->device_name, strerror(errno));
148       return;
149    }
150
151    drmGetMagic(drmdpy->fd, &magic);
152    wl_gbm_authenticate(drmdpy->wl_gbm, magic);
153 }
154
155 static void
156 drm_handle_format(void *data, struct wl_gbm *drm, uint32_t format)
157 {
158    struct wayland_drm_display *drmdpy = data;
159
160    switch (format) {
161    case WL_GBM_FORMAT_ARGB8888:
162       drmdpy->base.formats |= HAS_ARGB8888;
163       break;
164    case WL_GBM_FORMAT_XRGB8888:
165       drmdpy->base.formats |= HAS_XRGB8888;
166       break;
167    }
168 }
169
170 static void
171 drm_handle_authenticated(void *data, struct wl_gbm *drm)
172 {
173    struct wayland_drm_display *drmdpy = data;
174
175    drmdpy->authenticated = true;
176 }
177
178 static const struct wl_gbm_listener drm_listener = {
179    drm_handle_device,
180    drm_handle_format,
181    drm_handle_authenticated
182 };
183
184 static boolean
185 wayland_drm_display_init_screen(struct native_display *ndpy)
186 {
187    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
188    uint32_t id;
189
190    id = wl_display_get_global(drmdpy->base.dpy, "wl_gbm", 1);
191    if (id == 0)
192       wl_display_roundtrip(drmdpy->base.dpy);
193    id = wl_display_get_global(drmdpy->base.dpy, "wl_gbm", 1);
194    if (id == 0)
195       return FALSE;
196
197    drmdpy->wl_gbm = wl_display_bind(drmdpy->base.dpy, id, &wl_gbm_interface);
198    if (!drmdpy->wl_gbm)
199       return FALSE;
200
201    wl_gbm_add_listener(drmdpy->wl_gbm, &drm_listener, drmdpy);
202    wl_display_roundtrip(drmdpy->base.dpy);
203    if (drmdpy->fd == -1)
204       return FALSE;
205
206    wl_display_roundtrip(drmdpy->base.dpy);
207    if (!drmdpy->authenticated)
208       return FALSE;
209
210    if (drmdpy->base.formats == 0)
211       wl_display_roundtrip(drmdpy->base.dpy);
212    if (drmdpy->base.formats == 0)
213       return FALSE;
214
215    drmdpy->base.base.screen =
216       drmdpy->event_handler->new_drm_screen(&drmdpy->base.base,
217                                             NULL, drmdpy->fd);
218    if (!drmdpy->base.base.screen) {
219       _eglLog(_EGL_WARNING, "failed to create DRM screen");
220       return FALSE;
221    }
222
223    return TRUE;
224 }
225
226 static struct native_display_buffer wayland_drm_display_buffer = {
227    /* use the helpers */
228    drm_display_import_native_buffer,
229    drm_display_export_native_buffer
230 };
231
232 static int
233 wayland_drm_display_authenticate(void *user_data, uint32_t magic)
234 {
235    struct native_display *ndpy = user_data;
236    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
237    boolean current_authenticate, authenticated;
238
239    current_authenticate = drmdpy->authenticated;
240
241    wl_gbm_authenticate(drmdpy->wl_gbm, magic);
242    wl_display_roundtrip(drmdpy->base.dpy);
243    authenticated = drmdpy->authenticated;
244
245    drmdpy->authenticated = current_authenticate;
246
247    return authenticated ? 0 : -1;
248 }
249
250 static struct wl_gbm_callbacks wl_gbm_callbacks = {
251    wayland_drm_display_authenticate,
252    egl_g3d_wl_gbm_helper_reference_buffer,
253    egl_g3d_wl_gbm_helper_unreference_buffer
254 };
255
256 static boolean
257 wayland_drm_display_bind_wayland_display(struct native_display *ndpy,
258                                          struct wl_display *wl_dpy)
259 {
260    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
261
262    if (drmdpy->wl_server_gbm)
263       return FALSE;
264
265    drmdpy->wl_server_gbm =
266       wl_gbm_init(wl_dpy, drmdpy->device_name, drmdpy->fd, 
267                        &wl_gbm_callbacks, ndpy);
268
269    if (!drmdpy->wl_server_gbm)
270       return FALSE;
271    
272    return TRUE;
273 }
274
275 static boolean
276 wayland_drm_display_unbind_wayland_display(struct native_display *ndpy,
277                                            struct wl_display *wl_dpy)
278 {
279    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
280
281    if (!drmdpy->wl_server_gbm)
282       return FALSE;
283
284    wl_gbm_uninit(drmdpy->wl_server_gbm);
285    drmdpy->wl_server_gbm = NULL;
286
287    return TRUE;
288 }
289
290 static struct native_display_wayland_bufmgr wayland_drm_display_wayland_bufmgr = {
291    wayland_drm_display_bind_wayland_display,
292    wayland_drm_display_unbind_wayland_display,
293    egl_g3d_wl_gbm_common_wl_buffer_get_resource
294 };
295
296
297 struct wayland_display *
298 wayland_create_drm_display(struct wl_display *dpy,
299                            const struct native_event_handler *event_handler)
300 {
301    struct wayland_drm_display *drmdpy;
302
303    drmdpy = CALLOC_STRUCT(wayland_drm_display);
304    if (!drmdpy)
305       return NULL;
306
307    drmdpy->event_handler = event_handler;
308
309    drmdpy->base.dpy = dpy;
310    if (!drmdpy->base.dpy) {
311       wayland_drm_display_destroy(&drmdpy->base.base);
312       return NULL;
313    }
314
315    drmdpy->base.base.init_screen = wayland_drm_display_init_screen;
316    drmdpy->base.base.destroy = wayland_drm_display_destroy;
317    drmdpy->base.base.buffer = &wayland_drm_display_buffer;
318    drmdpy->base.base.wayland_bufmgr = &wayland_drm_display_wayland_bufmgr;
319
320    drmdpy->base.create_buffer = wayland_create_drm_buffer;
321
322    return &drmdpy->base;
323 }
324
325 /* vim: set sw=3 ts=8 sts=3 expandtab: */