1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2010 Chia-I Wu <olv (at) 0xlab.org> 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 <string.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <errno.h> 31 32 #include "util/u_memory.h" 33 #include "egllog.h" 34 35 #include "native_drm.h" 36 37 #include "gbm_gallium_drmint.h" 38 39 #ifdef HAVE_LIBUDEV 40 #include <libudev.h> 41 #endif 42 43 static boolean 44 drm_display_is_format_supported(struct native_display *ndpy, 45 enum pipe_format fmt, boolean is_color) 46 { 47 return ndpy->screen->is_format_supported(ndpy->screen, 48 fmt, PIPE_TEXTURE_2D, 0, 49 (is_color) ? PIPE_BIND_RENDER_TARGET : 50 PIPE_BIND_DEPTH_STENCIL); 51 } 52 53 static const struct native_config ** 54 drm_display_get_configs(struct native_display *ndpy, int *num_configs) 55 { 56 struct drm_display *drmdpy = drm_display(ndpy); 57 const struct native_config **configs; 58 59 /* first time */ 60 if (!drmdpy->config) { 61 struct native_config *nconf; 62 enum pipe_format format; 63 64 drmdpy->config = CALLOC(1, sizeof(*drmdpy->config)); 65 if (!drmdpy->config) 66 return NULL; 67 68 nconf = &drmdpy->config->base; 69 70 nconf->buffer_mask = 71 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 72 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 73 74 format = PIPE_FORMAT_B8G8R8A8_UNORM; 75 if (!drm_display_is_format_supported(&drmdpy->base, format, TRUE)) { 76 format = PIPE_FORMAT_A8R8G8B8_UNORM; 77 if (!drm_display_is_format_supported(&drmdpy->base, format, TRUE)) 78 format = PIPE_FORMAT_NONE; 79 } 80 if (format == PIPE_FORMAT_NONE) { 81 FREE(drmdpy->config); 82 drmdpy->config = NULL; 83 return NULL; 84 } 85 86 nconf->color_format = format; 87 88 /* support KMS */ 89 if (drmdpy->resources) 90 nconf->scanout_bit = TRUE; 91 } 92 93 configs = MALLOC(sizeof(*configs)); 94 if (configs) { 95 configs[0] = &drmdpy->config->base; 96 if (num_configs) 97 *num_configs = 1; 98 } 99 100 return configs; 101 } 102 103 static int 104 drm_display_get_param(struct native_display *ndpy, 105 enum native_param_type param) 106 { 107 int val; 108 109 switch (param) { 110 case NATIVE_PARAM_USE_NATIVE_BUFFER: 111 case NATIVE_PARAM_PRESERVE_BUFFER: 112 case NATIVE_PARAM_MAX_SWAP_INTERVAL: 113 default: 114 val = 0; 115 break; 116 } 117 118 return val; 119 } 120 121 static void 122 drm_display_destroy(struct native_display *ndpy) 123 { 124 struct drm_display *drmdpy = drm_display(ndpy); 125 126 if (drmdpy->config) 127 FREE(drmdpy->config); 128 129 drm_display_fini_modeset(&drmdpy->base); 130 131 /* gbm owns screen */ 132 ndpy->screen = NULL; 133 ndpy_uninit(ndpy); 134 135 if (drmdpy->device_name) 136 FREE(drmdpy->device_name); 137 138 if (drmdpy->own_gbm) { 139 gbm_device_destroy(&drmdpy->gbmdrm->base.base); 140 if (drmdpy->fd >= 0) 141 close(drmdpy->fd); 142 } 143 144 FREE(drmdpy); 145 } 146 147 static struct native_display_buffer drm_display_buffer = { 148 /* use the helpers */ 149 drm_display_import_native_buffer, 150 drm_display_export_native_buffer 151 }; 152 153 static char * 154 drm_get_device_name(int fd) 155 { 156 char *device_name = NULL; 157 #ifdef HAVE_LIBUDEV 158 struct udev *udev; 159 struct udev_device *device; 160 struct stat buf; 161 const char *tmp; 162 163 udev = udev_new(); 164 if (fstat(fd, &buf) < 0) { 165 _eglLog(_EGL_WARNING, "failed to stat fd %d", fd); 166 goto out; 167 } 168 169 device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev); 170 if (device == NULL) { 171 _eglLog(_EGL_WARNING, 172 "could not create udev device for fd %d", fd); 173 goto out; 174 } 175 176 tmp = udev_device_get_devnode(device); 177 if (!tmp) 178 goto out; 179 device_name = strdup(tmp); 180 181 out: 182 udev_device_unref(device); 183 udev_unref(udev); 184 185 #endif 186 return device_name; 187 } 188 189 #ifdef HAVE_WAYLAND_BACKEND 190 191 static int 192 drm_display_authenticate(void *user_data, uint32_t magic) 193 { 194 struct native_display *ndpy = user_data; 195 struct drm_display *drmdpy = drm_display(ndpy); 196 197 return drmAuthMagic(drmdpy->fd, magic); 198 } 199 200 static struct wayland_drm_callbacks wl_drm_callbacks = { 201 drm_display_authenticate, 202 egl_g3d_wl_drm_helper_reference_buffer, 203 egl_g3d_wl_drm_helper_unreference_buffer 204 }; 205 206 static boolean 207 drm_display_bind_wayland_display(struct native_display *ndpy, 208 struct wl_display *wl_dpy) 209 { 210 struct drm_display *drmdpy = drm_display(ndpy); 211 212 if (drmdpy->wl_server_drm) 213 return FALSE; 214 215 drmdpy->wl_server_drm = wayland_drm_init(wl_dpy, 216 drmdpy->device_name, 217 &wl_drm_callbacks, ndpy); 218 219 if (!drmdpy->wl_server_drm) 220 return FALSE; 221 222 return TRUE; 223 } 224 225 static boolean 226 drm_display_unbind_wayland_display(struct native_display *ndpy, 227 struct wl_display *wl_dpy) 228 { 229 struct drm_display *drmdpy = drm_display(ndpy); 230 231 if (!drmdpy->wl_server_drm) 232 return FALSE; 233 234 wayland_drm_uninit(drmdpy->wl_server_drm); 235 drmdpy->wl_server_drm = NULL; 236 237 return TRUE; 238 } 239 240 static struct native_display_wayland_bufmgr drm_display_wayland_bufmgr = { 241 drm_display_bind_wayland_display, 242 drm_display_unbind_wayland_display, 243 egl_g3d_wl_drm_common_wl_buffer_get_resource, 244 egl_g3d_wl_drm_common_query_buffer 245 }; 246 247 #endif /* HAVE_WAYLAND_BACKEND */ 248 249 static struct native_surface * 250 drm_create_pixmap_surface(struct native_display *ndpy, 251 EGLNativePixmapType pix, 252 const struct native_config *nconf) 253 { 254 struct gbm_gallium_drm_bo *bo = (void *) pix; 255 256 return drm_display_create_surface_from_resource(ndpy, bo->resource); 257 } 258 259 static boolean 260 drm_display_init_screen(struct native_display *ndpy) 261 { 262 return TRUE; 263 } 264 265 static struct native_display * 266 drm_create_display(struct gbm_gallium_drm_device *gbmdrm, int own_gbm, 267 const struct native_event_handler *event_handler) 268 { 269 struct drm_display *drmdpy; 270 271 drmdpy = CALLOC_STRUCT(drm_display); 272 if (!drmdpy) 273 return NULL; 274 275 drmdpy->gbmdrm = gbmdrm; 276 drmdpy->own_gbm = own_gbm; 277 drmdpy->fd = gbmdrm->base.base.fd; 278 drmdpy->device_name = drm_get_device_name(drmdpy->fd); 279 280 gbmdrm->lookup_egl_image = (struct pipe_resource *(*)(void *, void *)) 281 event_handler->lookup_egl_image; 282 gbmdrm->lookup_egl_image_data = &drmdpy->base; 283 284 drmdpy->event_handler = event_handler; 285 286 drmdpy->base.screen = gbmdrm->screen; 287 288 drmdpy->base.init_screen = drm_display_init_screen; 289 drmdpy->base.destroy = drm_display_destroy; 290 drmdpy->base.get_param = drm_display_get_param; 291 drmdpy->base.get_configs = drm_display_get_configs; 292 293 drmdpy->base.create_pixmap_surface = drm_create_pixmap_surface; 294 295 drmdpy->base.buffer = &drm_display_buffer; 296 #ifdef HAVE_WAYLAND_BACKEND 297 if (drmdpy->device_name) 298 drmdpy->base.wayland_bufmgr = &drm_display_wayland_bufmgr; 299 #endif 300 drm_display_init_modeset(&drmdpy->base); 301 302 return &drmdpy->base; 303 } 304 305 static const struct native_event_handler *drm_event_handler; 306 307 static struct native_display * 308 native_create_display(void *dpy, boolean use_sw) 309 { 310 struct gbm_gallium_drm_device *gbm; 311 int fd; 312 int own_gbm = 0; 313 314 gbm = dpy; 315 316 if (gbm == NULL) { 317 const char *device_name="/dev/dri/card0"; 318 #ifdef O_CLOEXEC 319 fd = open(device_name, O_RDWR | O_CLOEXEC); 320 if (fd == -1 && errno == EINVAL) 321 #endif 322 { 323 fd = open(device_name, O_RDWR); 324 if (fd != -1) 325 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 326 } 327 /* FIXME: Use an internal constructor to create a gbm 328 * device with gallium backend directly, without setenv */ 329 setenv("GBM_BACKEND", "gbm_gallium_drm.so", 1); 330 gbm = gbm_gallium_drm_device(gbm_create_device(fd)); 331 own_gbm = 1; 332 } 333 334 if (gbm == NULL) 335 return NULL; 336 337 if (strcmp(gbm_device_get_backend_name(&gbm->base.base), "drm") != 0 || 338 gbm->base.type != GBM_DRM_DRIVER_TYPE_GALLIUM) { 339 if (own_gbm) 340 gbm_device_destroy(&gbm->base.base); 341 return NULL; 342 } 343 344 return drm_create_display(gbm, own_gbm, drm_event_handler); 345 } 346 347 static const struct native_platform drm_platform = { 348 "DRM", /* name */ 349 native_create_display 350 }; 351 352 const struct native_platform * 353 native_get_drm_platform(const struct native_event_handler *event_handler) 354 { 355 drm_event_handler = event_handler; 356 return &drm_platform; 357 } 358