Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2009, VMware, Inc.
  4.  * All Rights Reserved.
  5.  * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
  6.  *           2013 Red Hat, Inc.
  7.  *
  8.  * Permission is hereby granted, free of charge, to any person obtaining a
  9.  * copy of this software and associated documentation files (the
  10.  * "Software"), to deal in the Software without restriction, including
  11.  * without limitation the rights to use, copy, modify, merge, publish,
  12.  * distribute, sub license, and/or sell copies of the Software, and to
  13.  * permit persons to whom the Software is furnished to do so, subject to
  14.  * the following conditions:
  15.  *
  16.  * The above copyright notice and this permission notice (including the
  17.  * next paragraph) shall be included in all copies or substantial portions
  18.  * of the Software.
  19.  *
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  21.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  23.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  24.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  25.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  26.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27.  *
  28.  **************************************************************************/
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <stddef.h>
  33. #include <stdint.h>
  34. #include <string.h>
  35. #include <limits.h>
  36.  
  37. #include <sys/types.h>
  38. #include <sys/mman.h>
  39. #include <unistd.h>
  40. #include <dlfcn.h>
  41. #include <fcntl.h>
  42. #include <xf86drm.h>
  43.  
  44. #include "pipe/p_compiler.h"
  45. #include "pipe/p_format.h"
  46. #include "util/u_inlines.h"
  47. #include "util/u_format.h"
  48. #include "util/u_math.h"
  49. #include "util/u_memory.h"
  50. #include "util/list.h"
  51.  
  52. #include "state_tracker/sw_winsys.h"
  53. #include "state_tracker/drm_driver.h"
  54. #include "kms_dri_sw_winsys.h"
  55.  
  56. #ifdef DEBUG
  57. #define DEBUG_PRINT(msg, ...) fprintf(stderr, msg, __VA_ARGS__)
  58. #else
  59. #define DEBUG_PRINT(msg, ...)
  60. #endif
  61.  
  62.  
  63. struct kms_sw_displaytarget
  64. {
  65.    enum pipe_format format;
  66.    unsigned width;
  67.    unsigned height;
  68.    unsigned stride;
  69.    unsigned size;
  70.  
  71.    uint32_t handle;
  72.    void *mapped;
  73.  
  74.    int ref_count;
  75.    struct list_head link;
  76. };
  77.  
  78. struct kms_sw_winsys
  79. {
  80.    struct sw_winsys base;
  81.  
  82.    int fd;
  83.    struct list_head bo_list;
  84. };
  85.  
  86. static INLINE struct kms_sw_displaytarget *
  87. kms_sw_displaytarget( struct sw_displaytarget *dt )
  88. {
  89.    return (struct kms_sw_displaytarget *)dt;
  90. }
  91.  
  92. static INLINE struct kms_sw_winsys *
  93. kms_sw_winsys( struct sw_winsys *ws )
  94. {
  95.    return (struct kms_sw_winsys *)ws;
  96. }
  97.  
  98.  
  99. static boolean
  100. kms_sw_is_displaytarget_format_supported( struct sw_winsys *ws,
  101.                                           unsigned tex_usage,
  102.                                           enum pipe_format format )
  103. {
  104.    /* TODO: check visuals or other sensible thing here */
  105.    return TRUE;
  106. }
  107.  
  108. static struct sw_displaytarget *
  109. kms_sw_displaytarget_create(struct sw_winsys *ws,
  110.                             unsigned tex_usage,
  111.                             enum pipe_format format,
  112.                             unsigned width, unsigned height,
  113.                             unsigned alignment,
  114.                             unsigned *stride)
  115. {
  116.    struct kms_sw_winsys *kms_sw = kms_sw_winsys(ws);
  117.    struct kms_sw_displaytarget *kms_sw_dt;
  118.    struct drm_mode_create_dumb create_req;
  119.    struct drm_mode_destroy_dumb destroy_req;
  120.    int ret;
  121.  
  122.    kms_sw_dt = CALLOC_STRUCT(kms_sw_displaytarget);
  123.    if (!kms_sw_dt)
  124.       goto no_dt;
  125.  
  126.    kms_sw_dt->ref_count = 1;
  127.  
  128.    kms_sw_dt->format = format;
  129.    kms_sw_dt->width = width;
  130.    kms_sw_dt->height = height;
  131.  
  132.    memset(&create_req, 0, sizeof(create_req));
  133.    create_req.bpp = 32;
  134.    create_req.width = width;
  135.    create_req.height = height;
  136.    ret = drmIoctl(kms_sw->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req);
  137.    if (ret)
  138.       goto free_bo;
  139.  
  140.    kms_sw_dt->stride = create_req.pitch;
  141.    kms_sw_dt->size = create_req.size;
  142.    kms_sw_dt->handle = create_req.handle;
  143.  
  144.    list_add(&kms_sw_dt->link, &kms_sw->bo_list);
  145.  
  146.    DEBUG_PRINT("KMS-DEBUG: created buffer %u (size %u)\n", kms_sw_dt->handle, kms_sw_dt->size);
  147.  
  148.    *stride = kms_sw_dt->stride;
  149.    return (struct sw_displaytarget *)kms_sw_dt;
  150.  
  151.  free_bo:
  152.    memset(&destroy_req, 0, sizeof destroy_req);
  153.    destroy_req.handle = create_req.handle;
  154.    drmIoctl(kms_sw->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
  155.    FREE(kms_sw_dt);
  156.  no_dt:
  157.    return NULL;
  158. }
  159.  
  160. static void
  161. kms_sw_displaytarget_destroy(struct sw_winsys *ws,
  162.                              struct sw_displaytarget *dt)
  163. {
  164.    struct kms_sw_winsys *kms_sw = kms_sw_winsys(ws);
  165.    struct kms_sw_displaytarget *kms_sw_dt = kms_sw_displaytarget(dt);
  166.    struct drm_mode_destroy_dumb destroy_req;
  167.  
  168.    kms_sw_dt->ref_count --;
  169.    if (kms_sw_dt->ref_count > 0)
  170.       return;
  171.  
  172.    memset(&destroy_req, 0, sizeof destroy_req);
  173.    destroy_req.handle = kms_sw_dt->handle;
  174.    drmIoctl(kms_sw->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
  175.  
  176.    list_del(&kms_sw_dt->link);
  177.  
  178.    DEBUG_PRINT("KMS-DEBUG: destroyed buffer %u\n", kms_sw_dt->handle);
  179.  
  180.    FREE(kms_sw_dt);
  181. }
  182.  
  183. static void *
  184. kms_sw_displaytarget_map(struct sw_winsys *ws,
  185.                          struct sw_displaytarget *dt,
  186.                          unsigned flags)
  187. {
  188.    struct kms_sw_winsys *kms_sw = kms_sw_winsys(ws);
  189.    struct kms_sw_displaytarget *kms_sw_dt = kms_sw_displaytarget(dt);
  190.    struct drm_mode_map_dumb map_req;
  191.    int prot, ret;
  192.  
  193.    memset(&map_req, 0, sizeof map_req);
  194.    map_req.handle = kms_sw_dt->handle;
  195.    ret = drmIoctl(kms_sw->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req);
  196.    if (ret)
  197.       return NULL;
  198.  
  199.    prot = (flags == PIPE_TRANSFER_READ) ? PROT_READ : (PROT_READ | PROT_WRITE);
  200.    kms_sw_dt->mapped = mmap(0, kms_sw_dt->size, prot, MAP_SHARED,
  201.                             kms_sw->fd, map_req.offset);
  202.  
  203.    if (kms_sw_dt->mapped == MAP_FAILED)
  204.       return NULL;
  205.  
  206.    DEBUG_PRINT("KMS-DEBUG: mapped buffer %u (size %u) at %p\n",
  207.          kms_sw_dt->handle, kms_sw_dt->size, kms_sw_dt->mapped);
  208.  
  209.    return kms_sw_dt->mapped;
  210. }
  211.  
  212. static struct kms_sw_displaytarget *
  213. kms_sw_displaytarget_add_from_prime(struct kms_sw_winsys *kms_sw, int fd)
  214. {
  215.    uint32_t handle = -1;
  216.    struct kms_sw_displaytarget * kms_sw_dt;
  217.    int ret;
  218.  
  219.    ret = drmPrimeFDToHandle(kms_sw->fd, fd, &handle);
  220.  
  221.    if (ret)
  222.       return NULL;
  223.  
  224.    kms_sw_dt = CALLOC_STRUCT(kms_sw_displaytarget);
  225.    if (!kms_sw_dt)
  226.       return NULL;
  227.  
  228.    kms_sw_dt->ref_count = 1;
  229.    kms_sw_dt->handle = handle;
  230.    kms_sw_dt->size = lseek(fd, 0, SEEK_END);
  231.  
  232.    if (kms_sw_dt->size == (off_t)-1) {
  233.       FREE(kms_sw_dt);
  234.       return NULL;
  235.    }
  236.  
  237.    lseek(fd, 0, SEEK_SET);
  238.  
  239.    list_add(&kms_sw_dt->link, &kms_sw->bo_list);
  240.  
  241.    return kms_sw_dt;
  242. }
  243.  
  244. static void
  245. kms_sw_displaytarget_unmap(struct sw_winsys *ws,
  246.                            struct sw_displaytarget *dt)
  247. {
  248.    struct kms_sw_displaytarget *kms_sw_dt = kms_sw_displaytarget(dt);
  249.  
  250.    DEBUG_PRINT("KMS-DEBUG: unmapped buffer %u (was %p)\n", kms_sw_dt->handle, kms_sw_dt->mapped);
  251.  
  252.    munmap(kms_sw_dt->mapped, kms_sw_dt->size);
  253.    kms_sw_dt->mapped = NULL;
  254. }
  255.  
  256. static struct sw_displaytarget *
  257. kms_sw_displaytarget_from_handle(struct sw_winsys *ws,
  258.                                  const struct pipe_resource *templ,
  259.                                  struct winsys_handle *whandle,
  260.                                  unsigned *stride)
  261. {
  262.    struct kms_sw_winsys *kms_sw = kms_sw_winsys(ws);
  263.    struct kms_sw_displaytarget *kms_sw_dt;
  264.  
  265.    assert(whandle->type == DRM_API_HANDLE_TYPE_KMS ||
  266.           whandle->type == DRM_API_HANDLE_TYPE_FD);
  267.  
  268.    switch(whandle->type) {
  269.    case DRM_API_HANDLE_TYPE_FD:
  270.       kms_sw_dt = kms_sw_displaytarget_add_from_prime(kms_sw, whandle->handle);
  271.       if (kms_sw_dt) {
  272.          kms_sw_dt->ref_count++;
  273.          kms_sw_dt->width = templ->width0;
  274.          kms_sw_dt->height = templ->height0;
  275.          kms_sw_dt->stride = whandle->stride;
  276.          *stride = kms_sw_dt->stride;
  277.       }
  278.       return (struct sw_displaytarget *)kms_sw_dt;
  279.    case DRM_API_HANDLE_TYPE_KMS:
  280.       LIST_FOR_EACH_ENTRY(kms_sw_dt, &kms_sw->bo_list, link) {
  281.          if (kms_sw_dt->handle == whandle->handle) {
  282.             kms_sw_dt->ref_count++;
  283.  
  284.             DEBUG_PRINT("KMS-DEBUG: imported buffer %u (size %u)\n", kms_sw_dt->handle, kms_sw_dt->size);
  285.  
  286.             *stride = kms_sw_dt->stride;
  287.             return (struct sw_displaytarget *)kms_sw_dt;
  288.          }
  289.       }
  290.       /* fallthrough */
  291.    default:
  292.       break;
  293.    }
  294.  
  295.    assert(0);
  296.    return NULL;
  297. }
  298.  
  299. static boolean
  300. kms_sw_displaytarget_get_handle(struct sw_winsys *winsys,
  301.                                 struct sw_displaytarget *dt,
  302.                                 struct winsys_handle *whandle)
  303. {
  304.    struct kms_sw_winsys *kms_sw = kms_sw_winsys(winsys);
  305.    struct kms_sw_displaytarget *kms_sw_dt = kms_sw_displaytarget(dt);
  306.  
  307.    switch(whandle->type) {
  308.    case DRM_API_HANDLE_TYPE_KMS:
  309.       whandle->handle = kms_sw_dt->handle;
  310.       whandle->stride = kms_sw_dt->stride;
  311.       return TRUE;
  312.    case DRM_API_HANDLE_TYPE_FD:
  313.       if (!drmPrimeHandleToFD(kms_sw->fd, kms_sw_dt->handle,
  314.                              DRM_CLOEXEC, (int*)&whandle->handle)) {
  315.          whandle->stride = kms_sw_dt->stride;
  316.          return TRUE;
  317.       }
  318.       /* fallthrough */
  319.    default:
  320.       whandle->handle = 0;
  321.       whandle->stride = 0;
  322.       return FALSE;
  323.    }
  324. }
  325.  
  326. static void
  327. kms_sw_displaytarget_display(struct sw_winsys *ws,
  328.                              struct sw_displaytarget *dt,
  329.                              void *context_private,
  330.                              struct pipe_box *box)
  331. {
  332.    /* This function should not be called, instead the dri2 loader should
  333.       handle swap buffers internally.
  334.    */
  335.    assert(0);
  336. }
  337.  
  338.  
  339. static void
  340. kms_destroy_sw_winsys(struct sw_winsys *winsys)
  341. {
  342.    FREE(winsys);
  343. }
  344.  
  345. struct sw_winsys *
  346. kms_dri_create_winsys(int fd)
  347. {
  348.    struct kms_sw_winsys *ws;
  349.  
  350.    ws = CALLOC_STRUCT(kms_sw_winsys);
  351.    if (!ws)
  352.       return NULL;
  353.  
  354.    ws->fd = fd;
  355.    list_inithead(&ws->bo_list);
  356.  
  357.    ws->base.destroy = kms_destroy_sw_winsys;
  358.  
  359.    ws->base.is_displaytarget_format_supported = kms_sw_is_displaytarget_format_supported;
  360.  
  361.    /* screen texture functions */
  362.    ws->base.displaytarget_create = kms_sw_displaytarget_create;
  363.    ws->base.displaytarget_destroy = kms_sw_displaytarget_destroy;
  364.    ws->base.displaytarget_from_handle = kms_sw_displaytarget_from_handle;
  365.    ws->base.displaytarget_get_handle = kms_sw_displaytarget_get_handle;
  366.  
  367.    /* texture functions */
  368.    ws->base.displaytarget_map = kms_sw_displaytarget_map;
  369.    ws->base.displaytarget_unmap = kms_sw_displaytarget_unmap;
  370.  
  371.    ws->base.displaytarget_display = kms_sw_displaytarget_display;
  372.  
  373.    return &ws->base;
  374. }
  375.  
  376. /* vim: set sw=3 ts=8 sts=3 expandtab: */
  377.