1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.11 4 * 5 * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke (at) 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 * 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->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 * 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 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 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 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 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 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 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 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 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 * 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