Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright © 2014 Broadcom
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21.  * IN THE SOFTWARE.
  22.  */
  23.  
  24. #include <errno.h>
  25. #include <err.h>
  26. #include <sys/mman.h>
  27. #include <fcntl.h>
  28. #include <xf86drm.h>
  29. #include <xf86drmMode.h>
  30.  
  31. #include "util/u_memory.h"
  32. #include "util/ralloc.h"
  33.  
  34. #include "vc4_context.h"
  35. #include "vc4_screen.h"
  36.  
  37. #define container_of(ptr, type, field) \
  38.    (type*)((char*)ptr - offsetof(type, field))
  39.  
  40. static struct vc4_bo *
  41. vc4_bo_from_cache(struct vc4_screen *screen, uint32_t size, const char *name)
  42. {
  43.         struct vc4_bo_cache *cache = &screen->bo_cache;
  44.         uint32_t page_index = size / 4096 - 1;
  45.  
  46.         if (cache->size_list_size <= page_index)
  47.                 return NULL;
  48.  
  49.         struct vc4_bo *bo = NULL;
  50.         pipe_mutex_lock(cache->lock);
  51.         if (!is_empty_list(&cache->size_list[page_index])) {
  52.                 struct simple_node *node = last_elem(&cache->size_list[page_index]);
  53.                 bo = container_of(node, struct vc4_bo, size_list);
  54.                 pipe_reference_init(&bo->reference, 1);
  55.                 remove_from_list(&bo->time_list);
  56.                 remove_from_list(&bo->size_list);
  57.  
  58.                 bo->name = name;
  59.         }
  60.         pipe_mutex_unlock(cache->lock);
  61.         return bo;
  62. }
  63.  
  64. struct vc4_bo *
  65. vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name)
  66. {
  67.         struct vc4_bo *bo;
  68.         int ret;
  69.  
  70.         size = align(size, 4096);
  71.  
  72.         bo = vc4_bo_from_cache(screen, size, name);
  73.         if (bo)
  74.                 return bo;
  75.  
  76.         bo = CALLOC_STRUCT(vc4_bo);
  77.         if (!bo)
  78.                 return NULL;
  79.  
  80.         pipe_reference_init(&bo->reference, 1);
  81.         bo->screen = screen;
  82.         bo->size = size;
  83.         bo->name = name;
  84.         bo->private = true;
  85.  
  86.         if (!using_vc4_simulator) {
  87.                 struct drm_vc4_create_bo create;
  88.                 memset(&create, 0, sizeof(create));
  89.  
  90.                 create.size = size;
  91.  
  92.                 ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_CREATE_BO, &create);
  93.                 bo->handle = create.handle;
  94.         } else {
  95.                 struct drm_mode_create_dumb create;
  96.                 memset(&create, 0, sizeof(create));
  97.  
  98.                 create.width = 128;
  99.                 create.bpp = 8;
  100.                 create.height = (size + 127) / 128;
  101.  
  102.                 ret = drmIoctl(screen->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
  103.                 bo->handle = create.handle;
  104.                 assert(create.size >= size);
  105.         }
  106.         if (ret != 0) {
  107.                 fprintf(stderr, "create ioctl failure\n");
  108.                 abort();
  109.         }
  110.  
  111.         return bo;
  112. }
  113.  
  114. void
  115. vc4_bo_last_unreference(struct vc4_bo *bo)
  116. {
  117.         struct vc4_screen *screen = bo->screen;
  118.  
  119.         struct timespec time;
  120.         clock_gettime(CLOCK_MONOTONIC, &time);
  121.         pipe_mutex_lock(screen->bo_cache.lock);
  122.         vc4_bo_last_unreference_locked_timed(bo, time.tv_sec);
  123.         pipe_mutex_unlock(screen->bo_cache.lock);
  124. }
  125.  
  126. static void
  127. vc4_bo_free(struct vc4_bo *bo)
  128. {
  129.         struct vc4_screen *screen = bo->screen;
  130.  
  131.         if (bo->map) {
  132. #ifdef USE_VC4_SIMULATOR
  133.                 if (bo->simulator_winsys_map) {
  134.                         free(bo->map);
  135.                         bo->map = bo->simulator_winsys_map;
  136.                 }
  137. #endif
  138.                 munmap(bo->map, bo->size);
  139.         }
  140.  
  141.         struct drm_gem_close c;
  142.         memset(&c, 0, sizeof(c));
  143.         c.handle = bo->handle;
  144.         int ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &c);
  145.         if (ret != 0)
  146.                 fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno));
  147.  
  148.         free(bo);
  149. }
  150.  
  151. static void
  152. free_stale_bos(struct vc4_screen *screen, time_t time)
  153. {
  154.         while (!is_empty_list(&screen->bo_cache.time_list)) {
  155.                 struct simple_node *node =
  156.                         first_elem(&screen->bo_cache.time_list);
  157.                 struct vc4_bo *bo = container_of(node, struct vc4_bo, time_list);
  158.  
  159.                 /* If it's more than a second old, free it. */
  160.                 if (time - bo->free_time > 2) {
  161.                         remove_from_list(&bo->time_list);
  162.                         remove_from_list(&bo->size_list);
  163.                         vc4_bo_free(bo);
  164.                 } else {
  165.                         break;
  166.                 }
  167.         }
  168. }
  169.  
  170. void
  171. vc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time)
  172. {
  173.         struct vc4_screen *screen = bo->screen;
  174.         struct vc4_bo_cache *cache = &screen->bo_cache;
  175.         uint32_t page_index = bo->size / 4096 - 1;
  176.  
  177.         if (!bo->private) {
  178.                 vc4_bo_free(bo);
  179.                 return;
  180.         }
  181.  
  182.         if (cache->size_list_size <= page_index) {
  183.                 struct simple_node *new_list =
  184.                         ralloc_array(screen, struct simple_node, page_index + 1);
  185.  
  186.                 /* Move old list contents over (since the array has moved, and
  187.                  * therefore the pointers to the list heads have to change.
  188.                  */
  189.                 for (int i = 0; i < cache->size_list_size; i++) {
  190.                         struct simple_node *old_head = &cache->size_list[i];
  191.                         if (is_empty_list(old_head))
  192.                                 make_empty_list(&new_list[i]);
  193.                         else {
  194.                                 new_list[i].next = old_head->next;
  195.                                 new_list[i].prev = old_head->prev;
  196.                                 new_list[i].next->prev = &new_list[i];
  197.                                 new_list[i].prev->next = &new_list[i];
  198.                         }
  199.                 }
  200.                 for (int i = cache->size_list_size; i < page_index + 1; i++)
  201.                         make_empty_list(&new_list[i]);
  202.  
  203.                 cache->size_list = new_list;
  204.                 cache->size_list_size = page_index + 1;
  205.         }
  206.  
  207.         bo->free_time = time;
  208.         insert_at_tail(&cache->size_list[page_index], &bo->size_list);
  209.         insert_at_tail(&cache->time_list, &bo->time_list);
  210.  
  211.         free_stale_bos(screen, time);
  212. }
  213.  
  214. static struct vc4_bo *
  215. vc4_bo_open_handle(struct vc4_screen *screen,
  216.                    uint32_t winsys_stride,
  217.                    uint32_t handle, uint32_t size)
  218. {
  219.         struct vc4_bo *bo = CALLOC_STRUCT(vc4_bo);
  220.  
  221.         assert(size);
  222.  
  223.         pipe_reference_init(&bo->reference, 1);
  224.         bo->screen = screen;
  225.         bo->handle = handle;
  226.         bo->size = size;
  227.         bo->name = "winsys";
  228.         bo->private = false;
  229.  
  230. #ifdef USE_VC4_SIMULATOR
  231.         vc4_bo_map(bo);
  232.         bo->simulator_winsys_map = bo->map;
  233.         bo->simulator_winsys_stride = winsys_stride;
  234.         bo->map = malloc(bo->size);
  235. #endif
  236.  
  237.         return bo;
  238. }
  239.  
  240. struct vc4_bo *
  241. vc4_bo_open_name(struct vc4_screen *screen, uint32_t name,
  242.                  uint32_t winsys_stride)
  243. {
  244.         struct drm_gem_open o = {
  245.                 .name = name
  246.         };
  247.         int ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_OPEN, &o);
  248.         if (ret) {
  249.                 fprintf(stderr, "Failed to open bo %d: %s\n",
  250.                         name, strerror(errno));
  251.                 return NULL;
  252.         }
  253.  
  254.         return vc4_bo_open_handle(screen, winsys_stride, o.handle, o.size);
  255. }
  256.  
  257. struct vc4_bo *
  258. vc4_bo_open_dmabuf(struct vc4_screen *screen, int fd, uint32_t winsys_stride)
  259. {
  260.         uint32_t handle;
  261.         int ret = drmPrimeFDToHandle(screen->fd, fd, &handle);
  262.         int size;
  263.         if (ret) {
  264.                 fprintf(stderr, "Failed to get vc4 handle for dmabuf %d\n", fd);
  265.                 return NULL;
  266.         }
  267.  
  268.         /* Determine the size of the bo we were handed. */
  269.         size = lseek(fd, 0, SEEK_END);
  270.         if (size == -1) {
  271.                 fprintf(stderr, "Couldn't get size of dmabuf fd %d.\n", fd);
  272.                 return NULL;
  273.         }
  274.  
  275.         return vc4_bo_open_handle(screen, winsys_stride, handle, size);
  276. }
  277.  
  278. int
  279. vc4_bo_get_dmabuf(struct vc4_bo *bo)
  280. {
  281.         int fd;
  282.         int ret = drmPrimeHandleToFD(bo->screen->fd, bo->handle,
  283.                                      O_CLOEXEC, &fd);
  284.         if (ret != 0) {
  285.                 fprintf(stderr, "Failed to export gem bo %d to dmabuf\n",
  286.                         bo->handle);
  287.                 return -1;
  288.         }
  289.  
  290.         return fd;
  291. }
  292.  
  293. struct vc4_bo *
  294. vc4_bo_alloc_mem(struct vc4_screen *screen, const void *data, uint32_t size,
  295.                  const char *name)
  296. {
  297.         void *map;
  298.         struct vc4_bo *bo;
  299.  
  300.         bo = vc4_bo_alloc(screen, size, name);
  301.         map = vc4_bo_map(bo);
  302.         memcpy(map, data, size);
  303.         return bo;
  304. }
  305.  
  306. bool
  307. vc4_bo_flink(struct vc4_bo *bo, uint32_t *name)
  308. {
  309.         struct drm_gem_flink flink = {
  310.                 .handle = bo->handle,
  311.         };
  312.         int ret = drmIoctl(bo->screen->fd, DRM_IOCTL_GEM_FLINK, &flink);
  313.         if (ret) {
  314.                 fprintf(stderr, "Failed to flink bo %d: %s\n",
  315.                         bo->handle, strerror(errno));
  316.                 free(bo);
  317.                 return false;
  318.         }
  319.  
  320.         bo->private = false;
  321.         *name = flink.name;
  322.  
  323.         return true;
  324. }
  325.  
  326. bool
  327. vc4_wait_seqno(struct vc4_screen *screen, uint64_t seqno, uint64_t timeout_ns)
  328. {
  329.         if (screen->finished_seqno >= seqno)
  330.                 return true;
  331.  
  332.         struct drm_vc4_wait_seqno wait;
  333.         memset(&wait, 0, sizeof(wait));
  334.         wait.seqno = seqno;
  335.         wait.timeout_ns = timeout_ns;
  336.  
  337.         int ret;
  338.         if (!using_vc4_simulator)
  339.                 ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_WAIT_SEQNO, &wait);
  340.         else {
  341.                 wait.seqno = screen->finished_seqno;
  342.                 ret = 0;
  343.         }
  344.  
  345.         if (ret == -ETIME) {
  346.                 return false;
  347.         } else if (ret != 0) {
  348.                 fprintf(stderr, "wait failed\n");
  349.                 abort();
  350.         } else {
  351.                 screen->finished_seqno = wait.seqno;
  352.                 return true;
  353.         }
  354. }
  355.  
  356. bool
  357. vc4_bo_wait(struct vc4_bo *bo, uint64_t timeout_ns)
  358. {
  359.         struct vc4_screen *screen = bo->screen;
  360.  
  361.         struct drm_vc4_wait_bo wait;
  362.         memset(&wait, 0, sizeof(wait));
  363.         wait.handle = bo->handle;
  364.         wait.timeout_ns = timeout_ns;
  365.  
  366.         int ret;
  367.         if (!using_vc4_simulator)
  368.                 ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_WAIT_BO, &wait);
  369.         else
  370.                 ret = 0;
  371.  
  372.         if (ret == -ETIME) {
  373.                 return false;
  374.         } else if (ret != 0) {
  375.                 fprintf(stderr, "wait failed\n");
  376.                 abort();
  377.         } else {
  378.                 return true;
  379.         }
  380. }
  381.  
  382. void *
  383. vc4_bo_map_unsynchronized(struct vc4_bo *bo)
  384. {
  385.         uint64_t offset;
  386.         int ret;
  387.  
  388.         if (bo->map)
  389.                 return bo->map;
  390.  
  391.         if (!using_vc4_simulator) {
  392.                 struct drm_vc4_mmap_bo map;
  393.                 memset(&map, 0, sizeof(map));
  394.                 map.handle = bo->handle;
  395.                 ret = drmIoctl(bo->screen->fd, DRM_IOCTL_VC4_MMAP_BO, &map);
  396.                 offset = map.offset;
  397.         } else {
  398.                 struct drm_mode_map_dumb map;
  399.                 memset(&map, 0, sizeof(map));
  400.                 map.handle = bo->handle;
  401.                 ret = drmIoctl(bo->screen->fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
  402.                 offset = map.offset;
  403.         }
  404.         if (ret != 0) {
  405.                 fprintf(stderr, "map ioctl failure\n");
  406.                 abort();
  407.         }
  408.  
  409.         bo->map = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
  410.                        bo->screen->fd, offset);
  411.         if (bo->map == MAP_FAILED) {
  412.                 fprintf(stderr, "mmap of bo %d (offset 0x%016llx, size %d) failed\n",
  413.                         bo->handle, (long long)offset, bo->size);
  414.                 abort();
  415.         }
  416.  
  417.         return bo->map;
  418. }
  419.  
  420. void *
  421. vc4_bo_map(struct vc4_bo *bo)
  422. {
  423.         void *map = vc4_bo_map_unsynchronized(bo);
  424.  
  425.         bool ok = vc4_bo_wait(bo, PIPE_TIMEOUT_INFINITE);
  426.         if (!ok) {
  427.                 fprintf(stderr, "BO wait for map failed\n");
  428.                 abort();
  429.         }
  430.  
  431.         return map;
  432. }
  433.  
  434. void
  435. vc4_bufmgr_destroy(struct pipe_screen *pscreen)
  436. {
  437.         struct vc4_screen *screen = vc4_screen(pscreen);
  438.         struct vc4_bo_cache *cache = &screen->bo_cache;
  439.  
  440.         while (!is_empty_list(&cache->time_list)) {
  441.                 struct simple_node *node = first_elem(&cache->time_list);
  442.                 struct vc4_bo *bo = container_of(node, struct vc4_bo, time_list);
  443.  
  444.                 remove_from_list(&bo->time_list);
  445.                 remove_from_list(&bo->size_list);
  446.                 vc4_bo_free(bo);
  447.         }
  448. }
  449.