1 /* 2 * va_wayland_drm.c - Wayland/DRM helpers 3 * 4 * Copyright (c) 2012 Intel Corporation. All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 #include "sysdeps.h" 28 #include <unistd.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <dlfcn.h> 32 #include <sys/stat.h> 33 #include <xf86drm.h> 34 #include "va_drmcommon.h" 35 #include "drm/va_drm_utils.h" 36 #include "va_wayland_drm.h" 37 #include "va_wayland_private.h" 38 #include "wayland-drm-client-protocol.h" 39 40 /* XXX: Wayland/DRM support currently lives in Mesa libEGL.so.* library */ 41 #define LIBWAYLAND_DRM_NAME "libEGL.so.1" 42 43 typedef struct va_wayland_drm_context { 44 struct va_wayland_context base; 45 void *handle; 46 struct wl_drm *drm; 47 struct wl_registry *registry; 48 void *drm_interface; 49 unsigned int is_authenticated : 1; 50 } VADisplayContextWaylandDRM; 51 52 static void 53 drm_handle_device(void *data, struct wl_drm *drm, const char *device) 54 { 55 VADisplayContextP const pDisplayContext = data; 56 VADriverContextP const ctx = pDisplayContext->pDriverContext; 57 VADisplayContextWaylandDRM * const wl_drm_ctx = pDisplayContext->opaque; 58 struct drm_state * const drm_state = ctx->drm_state; 59 drm_magic_t magic; 60 struct stat st; 61 62 if (stat(device, &st) < 0) { 63 va_wayland_error("failed to identify %s: %s (errno %d)", 64 device, strerror(errno), errno); 65 return; 66 } 67 68 if (!S_ISCHR(st.st_mode)) { 69 va_wayland_error("%s is not a device", device); 70 return; 71 } 72 73 drm_state->fd = open(device, O_RDWR); 74 if (drm_state->fd < 0) { 75 va_wayland_error("failed to open %s: %s (errno %d)", 76 device, strerror(errno), errno); 77 return; 78 } 79 80 drmGetMagic(drm_state->fd, &magic); 81 wl_drm_authenticate(wl_drm_ctx->drm, magic); 82 } 83 84 static void 85 drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 86 { 87 } 88 89 static void 90 drm_handle_authenticated(void *data, struct wl_drm *drm) 91 { 92 VADisplayContextP const pDisplayContext = data; 93 VADriverContextP const ctx = pDisplayContext->pDriverContext; 94 VADisplayContextWaylandDRM * const wl_drm_ctx = pDisplayContext->opaque; 95 struct drm_state * const drm_state = ctx->drm_state; 96 97 wl_drm_ctx->is_authenticated = 1; 98 drm_state->auth_type = VA_DRM_AUTH_CUSTOM; 99 } 100 101 static const struct wl_drm_listener drm_listener = { 102 drm_handle_device, 103 drm_handle_format, 104 drm_handle_authenticated 105 }; 106 107 static VAStatus 108 va_DisplayContextGetDriverName( 109 VADisplayContextP pDisplayContext, 110 char **driver_name_ptr 111 ) 112 { 113 VADriverContextP const ctx = pDisplayContext->pDriverContext; 114 115 return VA_DRM_GetDriverName(ctx, driver_name_ptr); 116 } 117 118 void 119 va_wayland_drm_destroy(VADisplayContextP pDisplayContext) 120 { 121 VADriverContextP const ctx = pDisplayContext->pDriverContext; 122 struct va_wayland_drm_context * const wl_drm_ctx = pDisplayContext->opaque; 123 struct drm_state * const drm_state = ctx->drm_state; 124 125 if (wl_drm_ctx->drm) { 126 wl_drm_destroy(wl_drm_ctx->drm); 127 wl_drm_ctx->drm = NULL; 128 } 129 wl_drm_ctx->is_authenticated = 0; 130 131 if (wl_drm_ctx->handle) { 132 dlclose(wl_drm_ctx->handle); 133 wl_drm_ctx->handle = NULL; 134 } 135 136 if (drm_state) { 137 if (drm_state->fd >= 0) { 138 close(drm_state->fd); 139 drm_state->fd = -1; 140 } 141 free(ctx->drm_state); 142 ctx->drm_state = NULL; 143 } 144 } 145 146 static void 147 registry_handle_global( 148 void *data, 149 struct wl_registry *registry, 150 uint32_t id, 151 const char *interface, 152 uint32_t version 153 ) 154 { 155 struct va_wayland_drm_context *wl_drm_ctx = data; 156 157 if (strcmp(interface, "wl_drm") == 0) { 158 wl_drm_ctx->drm = 159 wl_registry_bind(wl_drm_ctx->registry, id, wl_drm_ctx->drm_interface, 1); 160 } 161 } 162 163 static const struct wl_registry_listener registry_listener = { 164 registry_handle_global, 165 NULL, 166 }; 167 168 bool 169 va_wayland_drm_create(VADisplayContextP pDisplayContext) 170 { 171 VADriverContextP const ctx = pDisplayContext->pDriverContext; 172 struct va_wayland_drm_context *wl_drm_ctx; 173 struct drm_state *drm_state; 174 uint32_t id; 175 176 wl_drm_ctx = malloc(sizeof(*wl_drm_ctx)); 177 if (!wl_drm_ctx) 178 return false; 179 wl_drm_ctx->base.destroy = va_wayland_drm_destroy; 180 wl_drm_ctx->handle = NULL; 181 wl_drm_ctx->drm = NULL; 182 wl_drm_ctx->drm_interface = NULL; 183 wl_drm_ctx->is_authenticated = 0; 184 pDisplayContext->opaque = wl_drm_ctx; 185 pDisplayContext->vaGetDriverName = va_DisplayContextGetDriverName; 186 187 drm_state = calloc(1, sizeof(struct drm_state)); 188 if (!drm_state) 189 return false; 190 drm_state->fd = -1; 191 drm_state->auth_type = 0; 192 ctx->drm_state = drm_state; 193 194 wl_drm_ctx->handle = dlopen(LIBWAYLAND_DRM_NAME, RTLD_LAZY|RTLD_LOCAL); 195 if (!wl_drm_ctx->handle) 196 return false; 197 198 wl_drm_ctx->drm_interface = 199 dlsym(wl_drm_ctx->handle, "wl_drm_interface"); 200 if (!wl_drm_ctx->drm_interface) 201 return false; 202 203 wl_drm_ctx->registry = wl_display_get_registry(ctx->native_dpy); 204 wl_registry_add_listener(wl_drm_ctx->registry, ®istry_listener, wl_drm_ctx); 205 wl_display_roundtrip(ctx->native_dpy); 206 207 /* registry_handle_global should have been called by the 208 * wl_display_roundtrip above 209 */ 210 211 if (!wl_drm_ctx->drm) 212 return false; 213 214 wl_drm_add_listener(wl_drm_ctx->drm, &drm_listener, pDisplayContext); 215 wl_display_roundtrip(ctx->native_dpy); 216 if (drm_state->fd < 0) 217 return false; 218 219 wl_display_roundtrip(ctx->native_dpy); 220 if (!wl_drm_ctx->is_authenticated) 221 return false; 222 return true; 223 } 224