Subversion Repositories Kolibri OS

Rev

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