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_drm *wl_drm;
57 struct wl_drm *wl_server_drm; /* 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 *
wayland_drm_display(const struct native_display * ndpy)64 wayland_drm_display(const struct native_display *ndpy)
65 {
66 return (struct wayland_drm_display *) ndpy;
67 }
68
69 static void
wayland_drm_display_destroy(struct native_display * ndpy)70 wayland_drm_display_destroy(struct native_display *ndpy)
71 {
72 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
73
74 if (drmdpy->wl_drm)
75 wl_drm_destroy(drmdpy->wl_drm);
76 if (drmdpy->device_name)
77 FREE(drmdpy->device_name);
78 if (drmdpy->base.configs)
79 FREE(drmdpy->base.configs);
80 if (drmdpy->base.own_dpy)
81 wl_display_disconnect(drmdpy->base.dpy);
82
83 ndpy_uninit(ndpy);
84
85 if (drmdpy->fd)
86 close(drmdpy->fd);
87
88 FREE(drmdpy);
89 }
90
91 static struct wl_buffer *
wayland_create_drm_buffer(struct wayland_display * display,struct wayland_surface * surface,enum native_attachment attachment)92 wayland_create_drm_buffer(struct wayland_display *display,
93 struct wayland_surface *surface,
94 enum native_attachment attachment)
95 {
96 struct wayland_drm_display *drmdpy = (struct wayland_drm_display *) display;
97 struct pipe_screen *screen = drmdpy->base.base.screen;
98 struct pipe_resource *resource;
99 struct winsys_handle wsh;
100 uint width, height;
101 enum wl_drm_format format;
102
103 resource = resource_surface_get_single_resource(surface->rsurf, attachment);
104 resource_surface_get_size(surface->rsurf, &width, &height);
105
106 wsh.type = DRM_API_HANDLE_TYPE_SHARED;
107 screen->resource_get_handle(screen, resource, &wsh);
108
109 pipe_resource_reference(&resource, NULL);
110
111 switch (surface->color_format) {
112 case PIPE_FORMAT_B8G8R8A8_UNORM:
113 format = WL_DRM_FORMAT_ARGB8888;
114 break;
115 case PIPE_FORMAT_B8G8R8X8_UNORM:
116 format = WL_DRM_FORMAT_XRGB8888;
117 break;
118 default:
119 return NULL;
120 break;
121 }
122
123 return wl_drm_create_buffer(drmdpy->wl_drm, wsh.handle,
124 width, height, wsh.stride, format);
125 }
126
127 static void
drm_handle_device(void * data,struct wl_drm * drm,const char * device)128 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
129 {
130 struct wayland_drm_display *drmdpy = data;
131 drm_magic_t magic;
132
133 drmdpy->device_name = strdup(device);
134 if (!drmdpy->device_name)
135 return;
136
137 #ifdef O_CLOEXEC
138 drmdpy->fd = open(drmdpy->device_name, O_RDWR | O_CLOEXEC);
139 if (drmdpy->fd == -1 && errno == EINVAL)
140 #endif
141 {
142 drmdpy->fd = open(drmdpy->device_name, O_RDWR);
143 if (drmdpy->fd != -1)
144 fcntl(drmdpy->fd, F_SETFD, fcntl(drmdpy->fd, F_GETFD) | FD_CLOEXEC);
145 }
146 if (drmdpy->fd == -1) {
147 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
148 drmdpy->device_name, strerror(errno));
149 return;
150 }
151
152 drmGetMagic(drmdpy->fd, &magic);
153 wl_drm_authenticate(drmdpy->wl_drm, magic);
154 }
155
156 static void
drm_handle_format(void * data,struct wl_drm * drm,uint32_t format)157 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
158 {
159 struct wayland_drm_display *drmdpy = data;
160
161 switch (format) {
162 case WL_DRM_FORMAT_ARGB8888:
163 drmdpy->base.formats |= HAS_ARGB8888;
164 break;
165 case WL_DRM_FORMAT_XRGB8888:
166 drmdpy->base.formats |= HAS_XRGB8888;
167 break;
168 }
169 }
170
171 static void
drm_handle_authenticated(void * data,struct wl_drm * drm)172 drm_handle_authenticated(void *data, struct wl_drm *drm)
173 {
174 struct wayland_drm_display *drmdpy = data;
175
176 drmdpy->authenticated = true;
177 }
178
179 static const struct wl_drm_listener drm_listener = {
180 drm_handle_device,
181 drm_handle_format,
182 drm_handle_authenticated
183 };
184
185 static void
registry_handle_global(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)186 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
187 const char *interface, uint32_t version)
188 {
189 struct wayland_drm_display *drmdpy = data;
190
191 if (strcmp(interface, "wl_drm") == 0) {
192 drmdpy->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface, 1);
193 wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy);
194 }
195 }
196
197 static const struct wl_registry_listener registry_listener = {
198 registry_handle_global
199 };
200
201 static boolean
wayland_drm_display_init_screen(struct native_display * ndpy)202 wayland_drm_display_init_screen(struct native_display *ndpy)
203 {
204 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
205
206 drmdpy->base.queue = wl_display_create_queue(drmdpy->base.dpy);
207 drmdpy->base.registry = wl_display_get_registry(drmdpy->base.dpy);
208 wl_proxy_set_queue((struct wl_proxy *) drmdpy->base.registry,
209 drmdpy->base.queue);
210 wl_registry_add_listener(drmdpy->base.registry, ®istry_listener, drmdpy);
211 if (wayland_roundtrip(&drmdpy->base) < 0 || drmdpy->wl_drm == NULL)
212 return FALSE;
213
214 wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy);
215 if (wayland_roundtrip(&drmdpy->base) < 0 || drmdpy->fd == -1)
216 return FALSE;
217
218 if (wayland_roundtrip(&drmdpy->base) < 0 || !drmdpy->authenticated)
219 return FALSE;
220
221 if (drmdpy->base.formats == 0)
222 return FALSE;
223
224 drmdpy->base.base.screen =
225 drmdpy->event_handler->new_drm_screen(&drmdpy->base.base,
226 NULL, drmdpy->fd);
227 if (!drmdpy->base.base.screen) {
228 _eglLog(_EGL_WARNING, "failed to create DRM screen");
229 return FALSE;
230 }
231
232 return TRUE;
233 }
234
235 static struct native_display_buffer wayland_drm_display_buffer = {
236 /* use the helpers */
237 drm_display_import_native_buffer,
238 drm_display_export_native_buffer
239 };
240
241 static int
wayland_drm_display_authenticate(void * user_data,uint32_t magic)242 wayland_drm_display_authenticate(void *user_data, uint32_t magic)
243 {
244 struct native_display *ndpy = user_data;
245 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
246 boolean current_authenticate, authenticated;
247
248 current_authenticate = drmdpy->authenticated;
249
250 wl_drm_authenticate(drmdpy->wl_drm, magic);
251 wl_display_roundtrip(drmdpy->base.dpy);
252 authenticated = drmdpy->authenticated;
253
254 drmdpy->authenticated = current_authenticate;
255
256 return authenticated ? 0 : -1;
257 }
258
259 static struct wayland_drm_callbacks wl_drm_callbacks = {
260 wayland_drm_display_authenticate,
261 egl_g3d_wl_drm_helper_reference_buffer,
262 egl_g3d_wl_drm_helper_unreference_buffer
263 };
264
265 static boolean
wayland_drm_display_bind_wayland_display(struct native_display * ndpy,struct wl_display * wl_dpy)266 wayland_drm_display_bind_wayland_display(struct native_display *ndpy,
267 struct wl_display *wl_dpy)
268 {
269 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
270
271 if (drmdpy->wl_server_drm)
272 return FALSE;
273
274 drmdpy->wl_server_drm =
275 wayland_drm_init(wl_dpy, drmdpy->device_name,
276 &wl_drm_callbacks, ndpy);
277
278 if (!drmdpy->wl_server_drm)
279 return FALSE;
280
281 return TRUE;
282 }
283
284 static boolean
wayland_drm_display_unbind_wayland_display(struct native_display * ndpy,struct wl_display * wl_dpy)285 wayland_drm_display_unbind_wayland_display(struct native_display *ndpy,
286 struct wl_display *wl_dpy)
287 {
288 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
289
290 if (!drmdpy->wl_server_drm)
291 return FALSE;
292
293 wayland_drm_uninit(drmdpy->wl_server_drm);
294 drmdpy->wl_server_drm = NULL;
295
296 return TRUE;
297 }
298
299 static struct native_display_wayland_bufmgr wayland_drm_display_wayland_bufmgr = {
300 wayland_drm_display_bind_wayland_display,
301 wayland_drm_display_unbind_wayland_display,
302 egl_g3d_wl_drm_common_wl_buffer_get_resource,
303 egl_g3d_wl_drm_common_query_buffer
304 };
305
306
307 struct wayland_display *
wayland_create_drm_display(struct wl_display * dpy,const struct native_event_handler * event_handler)308 wayland_create_drm_display(struct wl_display *dpy,
309 const struct native_event_handler *event_handler)
310 {
311 struct wayland_drm_display *drmdpy;
312
313 drmdpy = CALLOC_STRUCT(wayland_drm_display);
314 if (!drmdpy)
315 return NULL;
316
317 drmdpy->event_handler = event_handler;
318
319 drmdpy->base.dpy = dpy;
320 if (!drmdpy->base.dpy) {
321 wayland_drm_display_destroy(&drmdpy->base.base);
322 return NULL;
323 }
324
325 drmdpy->base.base.init_screen = wayland_drm_display_init_screen;
326 drmdpy->base.base.destroy = wayland_drm_display_destroy;
327 drmdpy->base.base.buffer = &wayland_drm_display_buffer;
328 drmdpy->base.base.wayland_bufmgr = &wayland_drm_display_wayland_bufmgr;
329
330 drmdpy->base.create_buffer = wayland_create_drm_buffer;
331
332 return &drmdpy->base;
333 }
334
335 /* vim: set sw=3 ts=8 sts=3 expandtab: */
336