Subversion Repositories Kolibri OS

Rev

Rev 4358 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2010 Chia-I Wu <olv@0xlab.org>
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <errno.h>
  30.  
  31. #include "util/u_memory.h"
  32. #include "egllog.h"
  33.  
  34. #include "native_drm.h"
  35.  
  36. #include "gbm_gallium_drmint.h"
  37.  
  38. #ifdef HAVE_LIBUDEV
  39. #include <libudev.h>
  40. #endif
  41.  
  42. #ifdef HAVE_WAYLAND_BACKEND
  43. #include "common/native_wayland_drm_bufmgr_helper.h"
  44. #endif
  45.  
  46. static boolean
  47. drm_display_is_format_supported(struct native_display *ndpy,
  48.                                 enum pipe_format fmt, boolean is_color)
  49. {
  50.    return ndpy->screen->is_format_supported(ndpy->screen,
  51.          fmt, PIPE_TEXTURE_2D, 0,
  52.          (is_color) ? PIPE_BIND_RENDER_TARGET :
  53.          PIPE_BIND_DEPTH_STENCIL);
  54. }
  55.  
  56. static const struct native_config **
  57. drm_display_get_configs(struct native_display *ndpy, int *num_configs)
  58. {
  59.    struct drm_display *drmdpy = drm_display(ndpy);
  60.    const struct native_config **configs;
  61.  
  62.    /* first time */
  63.    if (!drmdpy->config) {
  64.       struct native_config *nconf;
  65.       enum pipe_format format;
  66.  
  67.       drmdpy->config = CALLOC(1, sizeof(*drmdpy->config));
  68.       if (!drmdpy->config)
  69.          return NULL;
  70.  
  71.       nconf = &drmdpy->config->base;
  72.  
  73.       nconf->buffer_mask =
  74.          (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
  75.          (1 << NATIVE_ATTACHMENT_BACK_LEFT);
  76.  
  77.       format = PIPE_FORMAT_B8G8R8A8_UNORM;
  78.       if (!drm_display_is_format_supported(&drmdpy->base, format, TRUE)) {
  79.          format = PIPE_FORMAT_A8R8G8B8_UNORM;
  80.          if (!drm_display_is_format_supported(&drmdpy->base, format, TRUE))
  81.             format = PIPE_FORMAT_NONE;
  82.       }
  83.       if (format == PIPE_FORMAT_NONE) {
  84.          FREE(drmdpy->config);
  85.          drmdpy->config = NULL;
  86.          return NULL;
  87.       }
  88.  
  89.       nconf->color_format = format;
  90.  
  91.       /* support KMS */
  92.       if (drmdpy->resources)
  93.          nconf->scanout_bit = TRUE;
  94.    }
  95.  
  96.    configs = MALLOC(sizeof(*configs));
  97.    if (configs) {
  98.       configs[0] = &drmdpy->config->base;
  99.       if (num_configs)
  100.          *num_configs = 1;
  101.    }
  102.  
  103.    return configs;
  104. }
  105.  
  106. static int
  107. drm_display_get_param(struct native_display *ndpy,
  108.                       enum native_param_type param)
  109. {
  110.    int val;
  111.  
  112.    switch (param) {
  113.    case NATIVE_PARAM_USE_NATIVE_BUFFER:
  114.    case NATIVE_PARAM_PRESERVE_BUFFER:
  115.    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
  116.    default:
  117.       val = 0;
  118.       break;
  119.    }
  120.  
  121.    return val;
  122. }
  123.  
  124. static void
  125. drm_display_destroy(struct native_display *ndpy)
  126. {
  127.    struct drm_display *drmdpy = drm_display(ndpy);
  128.  
  129.    FREE(drmdpy->config);
  130.  
  131.    drm_display_fini_modeset(&drmdpy->base);
  132.  
  133.    /* gbm owns screen */
  134.    ndpy->screen = NULL;
  135.    ndpy_uninit(ndpy);
  136.  
  137.    FREE(drmdpy->device_name);
  138.  
  139.    if (drmdpy->own_gbm) {
  140.       gbm_device_destroy(&drmdpy->gbmdrm->base.base);
  141.       if (drmdpy->fd >= 0)
  142.          close(drmdpy->fd);
  143.    }
  144.  
  145.    FREE(drmdpy);
  146. }
  147.  
  148. static struct native_display_buffer drm_display_buffer = {
  149.    /* use the helpers */
  150.    drm_display_import_native_buffer,
  151.    drm_display_export_native_buffer
  152. };
  153.  
  154. static char *
  155. drm_get_device_name(int fd)
  156. {
  157.    char *device_name = NULL;
  158. #ifdef HAVE_LIBUDEV
  159.    struct udev *udev;
  160.    struct udev_device *device;
  161.    struct stat buf;
  162.    const char *tmp;
  163.  
  164.    udev = udev_new();
  165.    if (fstat(fd, &buf) < 0) {
  166.       _eglLog(_EGL_WARNING, "failed to stat fd %d", fd);
  167.       goto outudev;
  168.    }
  169.  
  170.    device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
  171.    if (device == NULL) {
  172.       _eglLog(_EGL_WARNING,
  173.               "could not create udev device for fd %d", fd);
  174.       goto outdevice;
  175.    }
  176.  
  177.    tmp = udev_device_get_devnode(device);
  178.    if (!tmp)
  179.       goto outdevice;
  180.    device_name = strdup(tmp);
  181.  
  182. outdevice:
  183.    udev_device_unref(device);
  184. outudev:
  185.    udev_unref(udev);
  186.  
  187. #endif
  188.    return device_name;
  189. }
  190.  
  191. #ifdef HAVE_WAYLAND_BACKEND
  192.  
  193. static int
  194. drm_display_authenticate(void *user_data, uint32_t magic)
  195. {
  196.    struct native_display *ndpy = user_data;
  197.    struct drm_display *drmdpy = drm_display(ndpy);
  198.  
  199.    return drmAuthMagic(drmdpy->fd, magic);
  200. }
  201.  
  202. static struct wayland_drm_callbacks wl_drm_callbacks = {
  203.    drm_display_authenticate,
  204.    egl_g3d_wl_drm_helper_reference_buffer,
  205.    egl_g3d_wl_drm_helper_unreference_buffer
  206. };
  207.  
  208. static boolean
  209. drm_display_bind_wayland_display(struct native_display *ndpy,
  210.                                   struct wl_display *wl_dpy)
  211. {
  212.    struct drm_display *drmdpy = drm_display(ndpy);
  213.  
  214.    if (ndpy->wl_server_drm)
  215.       return FALSE;
  216.  
  217.    ndpy->wl_server_drm = wayland_drm_init(wl_dpy,
  218.          drmdpy->device_name,
  219.          &wl_drm_callbacks, ndpy, 0);
  220.  
  221.    if (!ndpy->wl_server_drm)
  222.       return FALSE;
  223.    
  224.    return TRUE;
  225. }
  226.  
  227. static boolean
  228. drm_display_unbind_wayland_display(struct native_display *ndpy,
  229.                                     struct wl_display *wl_dpy)
  230. {
  231.    if (!ndpy->wl_server_drm)
  232.       return FALSE;
  233.  
  234.    wayland_drm_uninit(ndpy->wl_server_drm);
  235.    ndpy->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.