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