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 51struct 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 63static INLINE struct wayland_drm_display * 64wayland_drm_display(const struct native_display *ndpy) 65{ 66 return (struct wayland_drm_display *) ndpy; 67} 68 69static void 70wayland_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 91static struct wl_buffer * 92wayland_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 127static void 128drm_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 156static void 157drm_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 171static void 172drm_handle_authenticated(void *data, struct wl_drm *drm) 173{ 174 struct wayland_drm_display *drmdpy = data; 175 176 drmdpy->authenticated = true; 177} 178 179static const struct wl_drm_listener drm_listener = { 180 drm_handle_device, 181 drm_handle_format, 182 drm_handle_authenticated 183}; 184 185static void 186registry_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 197static const struct wl_registry_listener registry_listener = { 198 registry_handle_global 199}; 200 201static boolean 202wayland_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 235static 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 241static int 242wayland_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 259static 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 265static boolean 266wayland_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 284static boolean 285wayland_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 299static 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 307struct wayland_display * 308wayland_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