native_drm.c revision 901a1183274670766df7f3f5c3b0d60b22fee722
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2010 Chia-I Wu <olv@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 43static boolean 44drm_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 53static const struct native_config ** 54drm_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 103static int 104drm_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 121static void 122drm_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 147static 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 153static char * 154drm_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 181out: 182 udev_device_unref(device); 183 udev_unref(udev); 184 185#endif 186 return device_name; 187} 188 189#ifdef HAVE_WAYLAND_BACKEND 190 191static int 192drm_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 200static 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 206static boolean 207drm_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 225static boolean 226drm_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 240static 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}; 245 246#endif /* HAVE_WAYLAND_BACKEND */ 247 248static struct native_surface * 249drm_create_pixmap_surface(struct native_display *ndpy, 250 EGLNativePixmapType pix, 251 const struct native_config *nconf) 252{ 253 struct gbm_gallium_drm_bo *bo = (void *) pix; 254 255 return drm_display_create_surface_from_resource(ndpy, bo->resource); 256} 257 258static boolean 259drm_display_init_screen(struct native_display *ndpy) 260{ 261 return TRUE; 262} 263 264static struct native_display * 265drm_create_display(struct gbm_gallium_drm_device *gbmdrm, int own_gbm, 266 const struct native_event_handler *event_handler) 267{ 268 struct drm_display *drmdpy; 269 270 drmdpy = CALLOC_STRUCT(drm_display); 271 if (!drmdpy) 272 return NULL; 273 274 drmdpy->gbmdrm = gbmdrm; 275 drmdpy->own_gbm = own_gbm; 276 drmdpy->fd = gbmdrm->base.base.fd; 277 drmdpy->device_name = drm_get_device_name(drmdpy->fd); 278 279 gbmdrm->lookup_egl_image = (struct pipe_resource *(*)(void *, void *)) 280 event_handler->lookup_egl_image; 281 gbmdrm->lookup_egl_image_data = &drmdpy->base; 282 283 drmdpy->event_handler = event_handler; 284 285 drmdpy->base.screen = gbmdrm->screen; 286 287 drmdpy->base.init_screen = drm_display_init_screen; 288 drmdpy->base.destroy = drm_display_destroy; 289 drmdpy->base.get_param = drm_display_get_param; 290 drmdpy->base.get_configs = drm_display_get_configs; 291 292 drmdpy->base.create_pixmap_surface = drm_create_pixmap_surface; 293 294 drmdpy->base.buffer = &drm_display_buffer; 295#ifdef HAVE_WAYLAND_BACKEND 296 if (drmdpy->device_name) 297 drmdpy->base.wayland_bufmgr = &drm_display_wayland_bufmgr; 298#endif 299 drm_display_init_modeset(&drmdpy->base); 300 301 return &drmdpy->base; 302} 303 304static const struct native_event_handler *drm_event_handler; 305 306static struct native_display * 307native_create_display(void *dpy, boolean use_sw) 308{ 309 struct gbm_gallium_drm_device *gbm; 310 int fd; 311 int own_gbm = 0; 312 313 gbm = dpy; 314 315 if (gbm == NULL) { 316 const char *device_name="/dev/dri/card0"; 317#ifdef O_CLOEXEC 318 fd = open(device_name, O_RDWR | O_CLOEXEC); 319 if (fd == -1 && errno == EINVAL) 320#endif 321 { 322 fd = open(device_name, O_RDWR); 323 if (fd != -1) 324 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 325 } 326 /* FIXME: Use an internal constructor to create a gbm 327 * device with gallium backend directly, without setenv */ 328 setenv("GBM_BACKEND", "gbm_gallium_drm.so", 1); 329 gbm = gbm_gallium_drm_device(gbm_create_device(fd)); 330 own_gbm = 1; 331 } 332 333 if (gbm == NULL) 334 return NULL; 335 336 if (strcmp(gbm_device_get_backend_name(&gbm->base.base), "drm") != 0 || 337 gbm->base.type != GBM_DRM_DRIVER_TYPE_GALLIUM) { 338 if (own_gbm) 339 gbm_device_destroy(&gbm->base.base); 340 return NULL; 341 } 342 343 return drm_create_display(gbm, own_gbm, drm_event_handler); 344} 345 346static const struct native_platform drm_platform = { 347 "DRM", /* name */ 348 native_create_display 349}; 350 351const struct native_platform * 352native_get_drm_platform(const struct native_event_handler *event_handler) 353{ 354 drm_event_handler = event_handler; 355 return &drm_platform; 356} 357