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) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
  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 "util/u_memory.h"
  26. #include "util/u_inlines.h"
  27.  
  28. #include "pipe/p_compiler.h"
  29. #include "pipe/p_screen.h"
  30. #include "pipe/p_context.h"
  31. #include "pipe/p_state.h"
  32. #include "state_tracker/drm_driver.h"
  33.  
  34. #include "egllog.h"
  35. #include <errno.h>
  36.  
  37. #include "native_wayland.h"
  38.  
  39. #include <wayland-client.h>
  40. #include "wayland-drm-client-protocol.h"
  41. #include "wayland-egl-priv.h"
  42.  
  43. #include "common/native_wayland_drm_bufmgr_helper.h"
  44.  
  45. #include <xf86drm.h>
  46. #include <sys/types.h>
  47. #include <sys/stat.h>
  48. #include <fcntl.h>
  49.  
  50. struct wayland_drm_display {
  51.    struct wayland_display base;
  52.  
  53.    const struct native_event_handler *event_handler;
  54.  
  55.    struct wl_drm *wl_drm;
  56.    struct wl_drm *wl_server_drm; /* for EGL_WL_bind_wayland_display */
  57.    int fd;
  58.    char *device_name;
  59.    boolean authenticated;
  60. };
  61.  
  62. static INLINE struct wayland_drm_display *
  63. wayland_drm_display(const struct native_display *ndpy)
  64. {
  65.    return (struct wayland_drm_display *) ndpy;
  66. }
  67.  
  68. static void
  69. wayland_drm_display_destroy(struct native_display *ndpy)
  70. {
  71.    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
  72.  
  73.    if (drmdpy->wl_drm)
  74.       wl_drm_destroy(drmdpy->wl_drm);
  75.    FREE(drmdpy->device_name);
  76.    FREE(drmdpy->base.configs);
  77.    if (drmdpy->base.own_dpy)
  78.       wl_display_disconnect(drmdpy->base.dpy);
  79.  
  80.    ndpy_uninit(ndpy);
  81.  
  82.    if (drmdpy->fd)
  83.       close(drmdpy->fd);
  84.  
  85.    FREE(drmdpy);
  86. }
  87.  
  88. static struct wl_buffer *
  89. wayland_create_drm_buffer(struct wayland_display *display,
  90.                           struct wayland_surface *surface,
  91.                           enum native_attachment attachment)
  92. {
  93.    struct wayland_drm_display *drmdpy = (struct wayland_drm_display *) display;
  94.    struct pipe_screen *screen = drmdpy->base.base.screen;
  95.    struct pipe_resource *resource;
  96.    struct winsys_handle wsh;
  97.    uint width, height;
  98.    enum wl_drm_format format;
  99.  
  100.    resource = resource_surface_get_single_resource(surface->rsurf, attachment);
  101.    resource_surface_get_size(surface->rsurf, &width, &height);
  102.  
  103.    wsh.type = DRM_API_HANDLE_TYPE_SHARED;
  104.    screen->resource_get_handle(screen, resource, &wsh);
  105.  
  106.    pipe_resource_reference(&resource, NULL);
  107.  
  108.    switch (surface->color_format) {
  109.    case PIPE_FORMAT_B8G8R8A8_UNORM:
  110.       format = WL_DRM_FORMAT_ARGB8888;
  111.       break;
  112.    case PIPE_FORMAT_B8G8R8X8_UNORM:
  113.       format = WL_DRM_FORMAT_XRGB8888;
  114.       break;
  115.    default:
  116.       return NULL;
  117.       break;
  118.    }
  119.  
  120.    return wl_drm_create_buffer(drmdpy->wl_drm, wsh.handle,
  121.                                width, height, wsh.stride, format);
  122. }
  123.  
  124. static void
  125. drm_handle_device(void *data, struct wl_drm *drm, const char *device)
  126. {
  127.    struct wayland_drm_display *drmdpy = data;
  128.    drm_magic_t magic;
  129.  
  130.    drmdpy->device_name = strdup(device);
  131.    if (!drmdpy->device_name)
  132.       return;
  133.  
  134. #ifdef O_CLOEXEC
  135.    drmdpy->fd = open(drmdpy->device_name, O_RDWR | O_CLOEXEC);
  136.    if (drmdpy->fd == -1 && errno == EINVAL)
  137. #endif
  138.    {
  139.       drmdpy->fd = open(drmdpy->device_name, O_RDWR);
  140.       if (drmdpy->fd != -1)
  141.          fcntl(drmdpy->fd, F_SETFD, fcntl(drmdpy->fd, F_GETFD) | FD_CLOEXEC);
  142.    }
  143.    if (drmdpy->fd == -1) {
  144.       _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
  145.               drmdpy->device_name, strerror(errno));
  146.       return;
  147.    }
  148.  
  149.    drmGetMagic(drmdpy->fd, &magic);
  150.    wl_drm_authenticate(drmdpy->wl_drm, magic);
  151. }
  152.  
  153. static void
  154. drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
  155. {
  156.    struct wayland_drm_display *drmdpy = data;
  157.  
  158.    switch (format) {
  159.    case WL_DRM_FORMAT_ARGB8888:
  160.       drmdpy->base.formats |= HAS_ARGB8888;
  161.       break;
  162.    case WL_DRM_FORMAT_XRGB8888:
  163.       drmdpy->base.formats |= HAS_XRGB8888;
  164.       break;
  165.    }
  166. }
  167.  
  168. static void
  169. drm_handle_authenticated(void *data, struct wl_drm *drm)
  170. {
  171.    struct wayland_drm_display *drmdpy = data;
  172.  
  173.    drmdpy->authenticated = true;
  174. }
  175.  
  176. static const struct wl_drm_listener drm_listener = {
  177.    drm_handle_device,
  178.    drm_handle_format,
  179.    drm_handle_authenticated
  180. };
  181.  
  182. static void
  183. registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
  184.                        const char *interface, uint32_t version)
  185. {
  186.    struct wayland_drm_display *drmdpy = data;
  187.  
  188.    if (strcmp(interface, "wl_drm") == 0) {
  189.       drmdpy->wl_drm = wl_registry_bind(registry, name, &wl_drm_interface, 1);
  190.       wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy);
  191.    }
  192. }
  193.  
  194. static const struct wl_registry_listener registry_listener = {
  195.        registry_handle_global
  196. };
  197.  
  198. static boolean
  199. wayland_drm_display_init_screen(struct native_display *ndpy)
  200. {
  201.    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
  202.  
  203.    drmdpy->base.queue = wl_display_create_queue(drmdpy->base.dpy);
  204.    drmdpy->base.registry = wl_display_get_registry(drmdpy->base.dpy);
  205.    wl_proxy_set_queue((struct wl_proxy *) drmdpy->base.registry,
  206.                       drmdpy->base.queue);
  207.    wl_registry_add_listener(drmdpy->base.registry, &registry_listener, drmdpy);
  208.    if (wayland_roundtrip(&drmdpy->base) < 0 || drmdpy->wl_drm == NULL)
  209.       return FALSE;
  210.  
  211.    wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy);
  212.    if (wayland_roundtrip(&drmdpy->base) < 0 || drmdpy->fd == -1)
  213.       return FALSE;
  214.  
  215.    if (wayland_roundtrip(&drmdpy->base) < 0 || !drmdpy->authenticated)
  216.       return FALSE;
  217.  
  218.    if (drmdpy->base.formats == 0)
  219.       return FALSE;
  220.  
  221.    drmdpy->base.base.screen =
  222.       drmdpy->event_handler->new_drm_screen(&drmdpy->base.base,
  223.                                             NULL, drmdpy->fd);
  224.    if (!drmdpy->base.base.screen) {
  225.       _eglLog(_EGL_WARNING, "failed to create DRM screen");
  226.       return FALSE;
  227.    }
  228.  
  229.    return TRUE;
  230. }
  231.  
  232. static struct native_display_buffer wayland_drm_display_buffer = {
  233.    /* use the helpers */
  234.    drm_display_import_native_buffer,
  235.    drm_display_export_native_buffer
  236. };
  237.  
  238. static int
  239. wayland_drm_display_authenticate(void *user_data, uint32_t magic)
  240. {
  241.    struct native_display *ndpy = user_data;
  242.    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
  243.    boolean current_authenticate, authenticated;
  244.  
  245.    current_authenticate = drmdpy->authenticated;
  246.  
  247.    wl_drm_authenticate(drmdpy->wl_drm, magic);
  248.    wl_display_roundtrip(drmdpy->base.dpy);
  249.    authenticated = drmdpy->authenticated;
  250.  
  251.    drmdpy->authenticated = current_authenticate;
  252.  
  253.    return authenticated ? 0 : -1;
  254. }
  255.  
  256. static struct wayland_drm_callbacks wl_drm_callbacks = {
  257.    wayland_drm_display_authenticate,
  258.    egl_g3d_wl_drm_helper_reference_buffer,
  259.    egl_g3d_wl_drm_helper_unreference_buffer
  260. };
  261.  
  262. static boolean
  263. wayland_drm_display_bind_wayland_display(struct native_display *ndpy,
  264.                                          struct wl_display *wl_dpy)
  265. {
  266.    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
  267.  
  268.    if (drmdpy->wl_server_drm)
  269.       return FALSE;
  270.  
  271.    drmdpy->wl_server_drm =
  272.       wayland_drm_init(wl_dpy, drmdpy->device_name,
  273.                        &wl_drm_callbacks, ndpy, 0);
  274.  
  275.    if (!drmdpy->wl_server_drm)
  276.       return FALSE;
  277.    
  278.    return TRUE;
  279. }
  280.  
  281. static boolean
  282. wayland_drm_display_unbind_wayland_display(struct native_display *ndpy,
  283.                                            struct wl_display *wl_dpy)
  284. {
  285.    struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
  286.  
  287.    if (!drmdpy->wl_server_drm)
  288.       return FALSE;
  289.  
  290.    wayland_drm_uninit(drmdpy->wl_server_drm);
  291.    drmdpy->wl_server_drm = NULL;
  292.  
  293.    return TRUE;
  294. }
  295.  
  296. static struct native_display_wayland_bufmgr wayland_drm_display_wayland_bufmgr = {
  297.    wayland_drm_display_bind_wayland_display,
  298.    wayland_drm_display_unbind_wayland_display,
  299.    egl_g3d_wl_drm_common_wl_buffer_get_resource,
  300.    egl_g3d_wl_drm_common_query_buffer
  301. };
  302.  
  303.  
  304. struct wayland_display *
  305. wayland_create_drm_display(struct wl_display *dpy,
  306.                            const struct native_event_handler *event_handler)
  307. {
  308.    struct wayland_drm_display *drmdpy;
  309.  
  310.    drmdpy = CALLOC_STRUCT(wayland_drm_display);
  311.    if (!drmdpy)
  312.       return NULL;
  313.  
  314.    drmdpy->event_handler = event_handler;
  315.  
  316.    drmdpy->base.dpy = dpy;
  317.    if (!drmdpy->base.dpy) {
  318.       wayland_drm_display_destroy(&drmdpy->base.base);
  319.       return NULL;
  320.    }
  321.  
  322.    drmdpy->base.base.init_screen = wayland_drm_display_init_screen;
  323.    drmdpy->base.base.destroy = wayland_drm_display_destroy;
  324.    drmdpy->base.base.buffer = &wayland_drm_display_buffer;
  325.    drmdpy->base.base.wayland_bufmgr = &wayland_drm_display_wayland_bufmgr;
  326.  
  327.    drmdpy->base.create_buffer = wayland_create_drm_buffer;
  328.  
  329.    return &drmdpy->base;
  330. }
  331.  
  332. /* vim: set sw=3 ts=8 sts=3 expandtab: */
  333.