Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (C) 2012 Intel Corporation. All Rights Reserved.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the
  6.  * "Software"), to deal in the Software without restriction, including
  7.  * without limitation the rights to use, copy, modify, merge, publish,
  8.  * distribute, sub license, and/or sell copies of the Software, and to
  9.  * permit persons to whom the Software is furnished to do so, subject to
  10.  * the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice (including the
  13.  * next paragraph) shall be included in all copies or substantial portions
  14.  * of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  19.  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
  20.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  21.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  22.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24.  
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <assert.h>
  28. #include <va/va_backend.h>
  29. #include <va/va_backend_wayland.h>
  30. #include <wayland-client.h>
  31. #include <wayland-drm-client-protocol.h>
  32. #include "intel_driver.h"
  33. #include "i965_output_wayland.h"
  34. #include "i965_drv_video.h"
  35. #include "i965_defines.h"
  36. #include "dso_utils.h"
  37.  
  38. #define LIBEGL_NAME             "libEGL.so.1"
  39. #define LIBWAYLAND_CLIENT_NAME  "libwayland-client.so.0"
  40.  
  41. typedef uint32_t (*wl_display_get_global_func)(struct wl_display *display,
  42.     const char *interface, uint32_t version);
  43. typedef void (*wl_display_roundtrip_func)(struct wl_display *display);
  44.  
  45. typedef struct wl_proxy *(*wl_proxy_create_func)(struct wl_proxy *factory,
  46.     const struct wl_interface *interface);
  47. typedef void (*wl_proxy_destroy_func)(struct wl_proxy *proxy);
  48. typedef void (*wl_proxy_marshal_func)(struct wl_proxy *p, uint32_t opcode, ...);
  49. typedef int (*wl_proxy_add_listener_func) (struct wl_proxy *proxy,
  50.     void (**implementation)(void), void *data);
  51.  
  52. struct wl_vtable {
  53.     const struct wl_interface  *buffer_interface;
  54.     const struct wl_interface  *drm_interface;
  55.     const struct wl_interface  *registry_interface;
  56.     wl_display_roundtrip_func   display_roundtrip;
  57.     wl_proxy_create_func        proxy_create;
  58.     wl_proxy_destroy_func       proxy_destroy;
  59.     wl_proxy_marshal_func       proxy_marshal;
  60.     wl_proxy_add_listener_func  proxy_add_listener;
  61. };
  62.  
  63. struct va_wl_output {
  64.     struct dso_handle  *libegl_handle;
  65.     struct dso_handle  *libwl_client_handle;
  66.     struct wl_vtable    vtable;
  67.     struct wl_drm      *wl_drm;
  68.     struct wl_registry *wl_registry;
  69. };
  70.  
  71. /* These function are copied and adapted from the version inside
  72.  * wayland-client-protocol.h
  73.  */
  74. static void *
  75. registry_bind(
  76.     struct wl_vtable          *wl_vtable,
  77.     struct wl_registry        *wl_registry,
  78.     uint32_t                   name,
  79.     const struct wl_interface *interface,
  80.     uint32_t                   version
  81. )
  82. {
  83.     struct wl_proxy *id;
  84.  
  85.     id = wl_vtable->proxy_create((struct wl_proxy *) wl_registry,
  86.                                  interface);
  87.     if (!id)
  88.       return NULL;
  89.  
  90.     wl_vtable->proxy_marshal((struct wl_proxy *) wl_registry,
  91.                              WL_REGISTRY_BIND, name, interface->name,
  92.                              version, id);
  93.  
  94.     return (void *) id;
  95. }
  96.  
  97. static struct wl_registry *
  98. display_get_registry(
  99.     struct wl_vtable  *wl_vtable,
  100.     struct wl_display *wl_display
  101. )
  102. {
  103.     struct wl_proxy *callback;
  104.  
  105.     callback = wl_vtable->proxy_create((struct wl_proxy *) wl_display,
  106.                                        wl_vtable->registry_interface);
  107.     if (!callback)
  108.       return NULL;
  109.  
  110.     wl_vtable->proxy_marshal((struct wl_proxy *) wl_display,
  111.                              WL_DISPLAY_GET_REGISTRY, callback);
  112.  
  113.     return (struct wl_registry *) callback;
  114. }
  115.  
  116. static int
  117. registry_add_listener(
  118.     struct wl_vtable                  *wl_vtable,
  119.     struct wl_registry                *wl_registry,
  120.     const struct wl_registry_listener *listener,
  121.     void                              *data
  122. )
  123. {
  124.     return wl_vtable->proxy_add_listener((struct wl_proxy *) wl_registry,
  125.                                          (void (**)(void)) listener, data);
  126. }
  127.  
  128. static void
  129. registry_handle_global(
  130.     void               *data,
  131.     struct wl_registry *registry,
  132.     uint32_t            id,
  133.     const char         *interface,
  134.     uint32_t            version
  135. )
  136. {
  137.     VADriverContextP ctx = data;
  138.     struct i965_driver_data * const i965 = i965_driver_data(ctx);
  139.     struct va_wl_output * const wl_output = i965->wl_output;
  140.     struct wl_vtable * const wl_vtable = &wl_output->vtable;
  141.  
  142.     if (strcmp(interface, "wl_drm") == 0) {
  143.         wl_output->wl_drm = registry_bind(wl_vtable, wl_output->wl_registry,
  144.                                           id, wl_vtable->drm_interface, 1);
  145.     }
  146. }
  147.  
  148. static const struct wl_registry_listener registry_listener = {
  149.     registry_handle_global,
  150.     NULL
  151. };
  152.  
  153. /* Ensure wl_drm instance is created */
  154. static bool
  155. ensure_wl_output(VADriverContextP ctx)
  156. {
  157.     struct i965_driver_data * const i965 = i965_driver_data(ctx);
  158.     struct va_wl_output * const wl_output = i965->wl_output;
  159.     struct wl_vtable * const wl_vtable = &wl_output->vtable;
  160.  
  161.     if (wl_output->wl_drm)
  162.         return true;
  163.  
  164.     wl_output->wl_registry = display_get_registry(wl_vtable, ctx->native_dpy);
  165.     registry_add_listener(wl_vtable, wl_output->wl_registry,
  166.                           &registry_listener, ctx);
  167.     wl_vtable->display_roundtrip(ctx->native_dpy);
  168.     if (!wl_output->wl_drm)
  169.         return false;
  170.     return true;
  171. }
  172.  
  173. /* Create planar YUV buffer */
  174. static struct wl_buffer *
  175. create_planar_buffer(
  176.     struct va_wl_output *wl_output,
  177.     uint32_t             name,
  178.     int32_t              width,
  179.     int32_t              height,
  180.     uint32_t             format,
  181.     int32_t              offsets[3],
  182.     int32_t              pitches[3]
  183. )
  184. {
  185.     struct wl_vtable * const wl_vtable = &wl_output->vtable;
  186.     struct wl_proxy *id;
  187.  
  188.     id = wl_vtable->proxy_create(
  189.         (struct wl_proxy *)wl_output->wl_drm,
  190.         wl_vtable->buffer_interface
  191.     );
  192.     if (!id)
  193.         return NULL;
  194.  
  195.     wl_vtable->proxy_marshal(
  196.         (struct wl_proxy *)wl_output->wl_drm,
  197.         WL_DRM_CREATE_PLANAR_BUFFER,
  198.         id,
  199.         name,
  200.         width, height, format,
  201.         offsets[0], pitches[0],
  202.         offsets[1], pitches[1],
  203.         offsets[2], pitches[2]
  204.     );
  205.     return (struct wl_buffer *)id;
  206. }
  207.  
  208. /* Hook to return Wayland buffer associated with the VA surface */
  209. static VAStatus
  210. va_GetSurfaceBufferWl(
  211.     struct VADriverContext *ctx,
  212.     VASurfaceID             surface,
  213.     unsigned int            flags,
  214.     struct wl_buffer      **out_buffer
  215. )
  216. {
  217.     struct i965_driver_data * const i965 = i965_driver_data(ctx);
  218.     struct object_surface *obj_surface;
  219.     struct wl_buffer *buffer;
  220.     uint32_t name, drm_format;
  221.     int offsets[3], pitches[3];
  222.  
  223.     obj_surface = SURFACE(surface);
  224.     if (!obj_surface)
  225.         return VA_STATUS_ERROR_INVALID_SURFACE;
  226.  
  227.     if (flags != VA_FRAME_PICTURE)
  228.         return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED;
  229.  
  230.     if (!out_buffer)
  231.         return VA_STATUS_ERROR_INVALID_PARAMETER;
  232.  
  233.     if (!ensure_wl_output(ctx))
  234.         return VA_STATUS_ERROR_INVALID_DISPLAY;
  235.  
  236.     if (drm_intel_bo_flink(obj_surface->bo, &name) != 0)
  237.         return VA_STATUS_ERROR_INVALID_SURFACE;
  238.  
  239.     switch (obj_surface->fourcc) {
  240.     case VA_FOURCC_NV12:
  241.         drm_format = WL_DRM_FORMAT_NV12;
  242.         offsets[0] = 0;
  243.         pitches[0] = obj_surface->width;
  244.         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
  245.         pitches[1] = obj_surface->cb_cr_pitch;
  246.         offsets[2] = 0;
  247.         pitches[2] = 0;
  248.         break;
  249.     case VA_FOURCC_YV12:
  250.     case VA_FOURCC_I420:
  251.     case VA_FOURCC_IMC1:
  252.     case VA_FOURCC_IMC3:
  253.     case VA_FOURCC_422H:
  254.     case VA_FOURCC_422V:
  255.     case VA_FOURCC_411P:
  256.     case VA_FOURCC_444P:
  257.         switch (obj_surface->subsampling) {
  258.         case SUBSAMPLE_YUV411:
  259.             drm_format = WL_DRM_FORMAT_YUV411;
  260.             break;
  261.         case SUBSAMPLE_YUV420:
  262.             drm_format = WL_DRM_FORMAT_YUV420;
  263.             break;
  264.         case SUBSAMPLE_YUV422H:
  265.         case SUBSAMPLE_YUV422V:
  266.             drm_format = WL_DRM_FORMAT_YUV422;
  267.             break;
  268.         case SUBSAMPLE_YUV444:
  269.             drm_format = WL_DRM_FORMAT_YUV444;
  270.             break;
  271.         default:
  272.             assert(0 && "unsupported subsampling");
  273.             return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
  274.         }
  275.         offsets[0] = 0;
  276.         pitches[0] = obj_surface->width;
  277.         offsets[1] = obj_surface->width * obj_surface->y_cb_offset;
  278.         pitches[1] = obj_surface->cb_cr_pitch;
  279.         offsets[2] = obj_surface->width * obj_surface->y_cr_offset;
  280.         pitches[2] = obj_surface->cb_cr_pitch;
  281.         break;
  282.     default:
  283.         assert(0 && "unsupported format");
  284.         return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
  285.     }
  286.  
  287.     buffer = create_planar_buffer(
  288.         i965->wl_output,
  289.         name,
  290.         obj_surface->orig_width,
  291.         obj_surface->orig_height,
  292.         drm_format,
  293.         offsets,
  294.         pitches
  295.     );
  296.     if (!buffer)
  297.         return VA_STATUS_ERROR_ALLOCATION_FAILED;
  298.  
  299.     *out_buffer = buffer;
  300.     return VA_STATUS_SUCCESS;
  301. }
  302.  
  303. /* Hook to return Wayland buffer associated with the VA image */
  304. static VAStatus
  305. va_GetImageBufferWl(
  306.     struct VADriverContext *ctx,
  307.     VAImageID               image,
  308.     unsigned int            flags,
  309.     struct wl_buffer      **out_buffer
  310. )
  311. {
  312.     return VA_STATUS_ERROR_UNIMPLEMENTED;
  313. }
  314.  
  315. bool
  316. ensure_driver_vtable(VADriverContextP ctx)
  317. {
  318.     struct VADriverVTableWayland * const vtable = ctx->vtable_wayland;
  319.  
  320.     if (!vtable)
  321.         return false;
  322.  
  323.     vtable->vaGetSurfaceBufferWl = va_GetSurfaceBufferWl;
  324.     vtable->vaGetImageBufferWl   = va_GetImageBufferWl;
  325.     return true;
  326. }
  327.  
  328. bool
  329. i965_output_wayland_init(VADriverContextP ctx)
  330. {
  331.     struct i965_driver_data * const i965 = i965_driver_data(ctx);
  332.     struct dso_handle *dso_handle;
  333.     struct wl_vtable *wl_vtable;
  334.  
  335.     static const struct dso_symbol libegl_symbols[] = {
  336.         { "wl_drm_interface",
  337.           offsetof(struct wl_vtable, drm_interface) },
  338.         { NULL, }
  339.     };
  340.  
  341.     static const struct dso_symbol libwl_client_symbols[] = {
  342.         { "wl_buffer_interface",
  343.           offsetof(struct wl_vtable, buffer_interface) },
  344.         { "wl_registry_interface",
  345.           offsetof(struct wl_vtable, registry_interface) },
  346.         { "wl_display_roundtrip",
  347.           offsetof(struct wl_vtable, display_roundtrip) },
  348.         { "wl_proxy_create",
  349.           offsetof(struct wl_vtable, proxy_create) },
  350.         { "wl_proxy_destroy",
  351.           offsetof(struct wl_vtable, proxy_destroy) },
  352.         { "wl_proxy_marshal",
  353.           offsetof(struct wl_vtable, proxy_marshal) },
  354.         { "wl_proxy_add_listener",
  355.           offsetof(struct wl_vtable, proxy_add_listener) },
  356.         { NULL, }
  357.     };
  358.  
  359.     if (ctx->display_type != VA_DISPLAY_WAYLAND)
  360.         return false;
  361.  
  362.     i965->wl_output = calloc(1, sizeof(struct va_wl_output));
  363.     if (!i965->wl_output)
  364.         goto error;
  365.  
  366.     i965->wl_output->libegl_handle = dso_open(LIBEGL_NAME);
  367.     if (!i965->wl_output->libegl_handle)
  368.         goto error;
  369.  
  370.     dso_handle = i965->wl_output->libegl_handle;
  371.     wl_vtable  = &i965->wl_output->vtable;
  372.     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
  373.                          libegl_symbols))
  374.         goto error;
  375.  
  376.     i965->wl_output->libwl_client_handle = dso_open(LIBWAYLAND_CLIENT_NAME);
  377.     if (!i965->wl_output->libwl_client_handle)
  378.         goto error;
  379.  
  380.     dso_handle = i965->wl_output->libwl_client_handle;
  381.     wl_vtable  = &i965->wl_output->vtable;
  382.     if (!dso_get_symbols(dso_handle, wl_vtable, sizeof(*wl_vtable),
  383.                          libwl_client_symbols))
  384.         goto error;
  385.  
  386.     if (!ensure_driver_vtable(ctx))
  387.         goto error;
  388.     return true;
  389.  
  390. error:
  391.     i965_output_wayland_terminate(ctx);
  392.     return false;
  393. }
  394.  
  395. void
  396. i965_output_wayland_terminate(VADriverContextP ctx)
  397. {
  398.     struct i965_driver_data * const i965 = i965_driver_data(ctx);
  399.     struct va_wl_output *wl_output;
  400.  
  401.     if (ctx->display_type != VA_DISPLAY_WAYLAND)
  402.         return;
  403.  
  404.     wl_output = i965->wl_output;
  405.     if (!wl_output)
  406.         return;
  407.  
  408.     if (wl_output->wl_drm) {
  409.         wl_output->vtable.proxy_destroy((struct wl_proxy *)wl_output->wl_drm);
  410.         wl_output->wl_drm = NULL;
  411.     }
  412.  
  413.     if (wl_output->libegl_handle) {
  414.         dso_close(wl_output->libegl_handle);
  415.         wl_output->libegl_handle = NULL;
  416.     }
  417.  
  418.     if (wl_output->libwl_client_handle) {
  419.         dso_close(wl_output->libwl_client_handle);
  420.         wl_output->libwl_client_handle = NULL;
  421.     }
  422.     free(wl_output);
  423.     i965->wl_output = NULL;
  424. }
  425.