Home | History | Annotate | Download | only in drm
      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