Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Permission is hereby granted, free of charge, to any person obtaining a
  3.  * copy of this software and associated documentation files (the "Software"),
  4.  * to deal in the Software without restriction, including without limitation
  5.  * on the rights to use, copy, modify, merge, publish, distribute, sub
  6.  * license, and/or sell copies of the Software, and to permit persons to whom
  7.  * the Software is furnished to do so, subject to the following conditions:
  8.  *
  9.  * The above copyright notice and this permission notice (including the next
  10.  * paragraph) shall be included in all copies or substantial portions of the
  11.  * Software.
  12.  *
  13.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15.  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  16.  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
  17.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  18.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  19.  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  20.  *
  21.  * Authors:
  22.  *      Adam Rak <adam.rak@streamnovation.com>
  23.  */
  24.  
  25. #include "pipe/p_defines.h"
  26. #include "pipe/p_state.h"
  27. #include "pipe/p_context.h"
  28. #include "util/u_blitter.h"
  29. #include "util/list.h"
  30. #include "util/u_transfer.h"
  31. #include "util/u_surface.h"
  32. #include "util/u_pack_color.h"
  33. #include "util/u_math.h"
  34. #include "util/u_memory.h"
  35. #include "util/u_inlines.h"
  36. #include "util/u_framebuffer.h"
  37. #include "r600_shader.h"
  38. #include "r600_pipe.h"
  39. #include "r600_formats.h"
  40. #include "compute_memory_pool.h"
  41. #include "evergreen_compute.h"
  42. #include "evergreen_compute_internal.h"
  43. #include <inttypes.h>
  44.  
  45. #define ITEM_ALIGNMENT 1024
  46. /**
  47.  * Creates a new pool.
  48.  */
  49. struct compute_memory_pool* compute_memory_pool_new(
  50.         struct r600_screen * rscreen)
  51. {
  52.         struct compute_memory_pool* pool = (struct compute_memory_pool*)
  53.                                 CALLOC(sizeof(struct compute_memory_pool), 1);
  54.         if (pool == NULL)
  55.                 return NULL;
  56.  
  57.         COMPUTE_DBG(rscreen, "* compute_memory_pool_new()\n");
  58.  
  59.         pool->screen = rscreen;
  60.         pool->item_list = (struct list_head *)
  61.                                 CALLOC(sizeof(struct list_head), 1);
  62.         pool->unallocated_list = (struct list_head *)
  63.                                 CALLOC(sizeof(struct list_head), 1);
  64.         list_inithead(pool->item_list);
  65.         list_inithead(pool->unallocated_list);
  66.         return pool;
  67. }
  68.  
  69. /**
  70.  * Initializes the pool with a size of \a initial_size_in_dw.
  71.  * \param pool                  The pool to be initialized.
  72.  * \param initial_size_in_dw    The initial size.
  73.  * \see compute_memory_grow_defrag_pool
  74.  */
  75. static void compute_memory_pool_init(struct compute_memory_pool * pool,
  76.         unsigned initial_size_in_dw)
  77. {
  78.  
  79.         COMPUTE_DBG(pool->screen, "* compute_memory_pool_init() initial_size_in_dw = %u\n",
  80.                 initial_size_in_dw);
  81.  
  82.         pool->size_in_dw = initial_size_in_dw;
  83.         pool->bo = (struct r600_resource*)r600_compute_buffer_alloc_vram(pool->screen,
  84.                                                         pool->size_in_dw * 4);
  85. }
  86.  
  87. /**
  88.  * Frees all stuff in the pool and the pool struct itself too.
  89.  */
  90. void compute_memory_pool_delete(struct compute_memory_pool* pool)
  91. {
  92.         COMPUTE_DBG(pool->screen, "* compute_memory_pool_delete()\n");
  93.         free(pool->shadow);
  94.         if (pool->bo) {
  95.                 pool->screen->b.b.resource_destroy((struct pipe_screen *)
  96.                         pool->screen, (struct pipe_resource *)pool->bo);
  97.         }
  98.         /* In theory, all of the items were freed in compute_memory_free.
  99.          * Just delete the list heads
  100.          */
  101.         free(pool->item_list);
  102.         free(pool->unallocated_list);
  103.         /* And then the pool itself */
  104.         free(pool);
  105. }
  106.  
  107. /**
  108.  * Searches for an empty space in the pool, return with the pointer to the
  109.  * allocatable space in the pool.
  110.  * \param size_in_dw    The size of the space we are looking for.
  111.  * \return -1 on failure
  112.  */
  113. int64_t compute_memory_prealloc_chunk(
  114.         struct compute_memory_pool* pool,
  115.         int64_t size_in_dw)
  116. {
  117.         struct compute_memory_item *item;
  118.  
  119.         int last_end = 0;
  120.  
  121.         assert(size_in_dw <= pool->size_in_dw);
  122.  
  123.         COMPUTE_DBG(pool->screen, "* compute_memory_prealloc_chunk() size_in_dw = %ld\n",
  124.                 size_in_dw);
  125.  
  126.         LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
  127.                 if (last_end + size_in_dw <= item->start_in_dw) {
  128.                         return last_end;
  129.                 }
  130.  
  131.                 last_end = item->start_in_dw + align(item->size_in_dw, ITEM_ALIGNMENT);
  132.         }
  133.  
  134.         if (pool->size_in_dw - last_end < size_in_dw) {
  135.                 return -1;
  136.         }
  137.  
  138.         return last_end;
  139. }
  140.  
  141. /**
  142.  *  Search for the chunk where we can link our new chunk after it.
  143.  *  \param start_in_dw  The position of the item we want to add to the pool.
  144.  *  \return The item that is just before the passed position
  145.  */
  146. struct list_head *compute_memory_postalloc_chunk(
  147.         struct compute_memory_pool* pool,
  148.         int64_t start_in_dw)
  149. {
  150.         struct compute_memory_item *item;
  151.         struct compute_memory_item *next;
  152.         struct list_head *next_link;
  153.  
  154.         COMPUTE_DBG(pool->screen, "* compute_memory_postalloc_chunck() start_in_dw = %ld\n",
  155.                 start_in_dw);
  156.  
  157.         /* Check if we can insert it in the front of the list */
  158.         item = LIST_ENTRY(struct compute_memory_item, pool->item_list->next, link);
  159.         if (LIST_IS_EMPTY(pool->item_list) || item->start_in_dw > start_in_dw) {
  160.                 return pool->item_list;
  161.         }
  162.  
  163.         LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
  164.                 next_link = item->link.next;
  165.  
  166.                 if (next_link != pool->item_list) {
  167.                         next = container_of(next_link, item, link);
  168.                         if (item->start_in_dw < start_in_dw
  169.                                 && next->start_in_dw > start_in_dw) {
  170.                                 return &item->link;
  171.                         }
  172.                 }
  173.                 else {
  174.                         /* end of chain */
  175.                         assert(item->start_in_dw < start_in_dw);
  176.                         return &item->link;
  177.                 }
  178.         }
  179.  
  180.         assert(0 && "unreachable");
  181.         return NULL;
  182. }
  183.  
  184. /**
  185.  * Reallocates and defragments the pool, conserves data.
  186.  * \returns -1 if it fails, 0 otherwise
  187.  * \see compute_memory_finalize_pending
  188.  */
  189. int compute_memory_grow_defrag_pool(struct compute_memory_pool *pool,
  190.         struct pipe_context *pipe, int new_size_in_dw)
  191. {
  192.         new_size_in_dw = align(new_size_in_dw, ITEM_ALIGNMENT);
  193.  
  194.         COMPUTE_DBG(pool->screen, "* compute_memory_grow_defrag_pool() "
  195.                 "new_size_in_dw = %d (%d bytes)\n",
  196.                 new_size_in_dw, new_size_in_dw * 4);
  197.  
  198.         assert(new_size_in_dw >= pool->size_in_dw);
  199.  
  200.         if (!pool->bo) {
  201.                 compute_memory_pool_init(pool, MAX2(new_size_in_dw, 1024 * 16));
  202.         } else {
  203.                 struct r600_resource *temp = NULL;
  204.  
  205.                 temp = (struct r600_resource *)r600_compute_buffer_alloc_vram(
  206.                                                         pool->screen, new_size_in_dw * 4);
  207.  
  208.                 if (temp != NULL) {
  209.                         struct pipe_resource *src = (struct pipe_resource *)pool->bo;
  210.                         struct pipe_resource *dst = (struct pipe_resource *)temp;
  211.  
  212.                         COMPUTE_DBG(pool->screen, "  Growing and defragmenting the pool "
  213.                                         "using a temporary resource\n");
  214.  
  215.                         compute_memory_defrag(pool, src, dst, pipe);
  216.  
  217.                         pool->screen->b.b.resource_destroy(
  218.                                         (struct pipe_screen *)pool->screen,
  219.                                         src);
  220.  
  221.                         pool->bo = temp;
  222.                         pool->size_in_dw = new_size_in_dw;
  223.                 }
  224.                 else {
  225.                         COMPUTE_DBG(pool->screen, "  The creation of the temporary resource failed\n"
  226.                                 "  Falling back to using 'shadow'\n");
  227.  
  228.                         compute_memory_shadow(pool, pipe, 1);
  229.                         pool->shadow = realloc(pool->shadow, new_size_in_dw * 4);
  230.                         if (pool->shadow == NULL)
  231.                                 return -1;
  232.  
  233.                         pool->size_in_dw = new_size_in_dw;
  234.                         pool->screen->b.b.resource_destroy(
  235.                                         (struct pipe_screen *)pool->screen,
  236.                                         (struct pipe_resource *)pool->bo);
  237.                         pool->bo = (struct r600_resource*)r600_compute_buffer_alloc_vram(
  238.                                         pool->screen,
  239.                                         pool->size_in_dw * 4);
  240.                         compute_memory_shadow(pool, pipe, 0);
  241.  
  242.                         if (pool->status & POOL_FRAGMENTED) {
  243.                                 struct pipe_resource *src = (struct pipe_resource *)pool->bo;
  244.                                 compute_memory_defrag(pool, src, src, pipe);
  245.                         }
  246.                 }
  247.         }
  248.  
  249.         return 0;
  250. }
  251.  
  252. /**
  253.  * Copy pool from device to host, or host to device.
  254.  * \param device_to_host 1 for device->host, 0 for host->device
  255.  * \see compute_memory_grow_defrag_pool
  256.  */
  257. void compute_memory_shadow(struct compute_memory_pool* pool,
  258.         struct pipe_context * pipe, int device_to_host)
  259. {
  260.         struct compute_memory_item chunk;
  261.  
  262.         COMPUTE_DBG(pool->screen, "* compute_memory_shadow() device_to_host = %d\n",
  263.                 device_to_host);
  264.  
  265.         chunk.id = 0;
  266.         chunk.start_in_dw = 0;
  267.         chunk.size_in_dw = pool->size_in_dw;
  268.         compute_memory_transfer(pool, pipe, device_to_host, &chunk,
  269.                                 pool->shadow, 0, pool->size_in_dw*4);
  270. }
  271.  
  272. /**
  273.  * Moves all the items marked for promotion from the \a unallocated_list
  274.  * to the \a item_list.
  275.  * \return -1 if it fails, 0 otherwise
  276.  * \see evergreen_set_global_binding
  277.  */
  278. int compute_memory_finalize_pending(struct compute_memory_pool* pool,
  279.         struct pipe_context * pipe)
  280. {
  281.         struct compute_memory_item *item, *next;
  282.  
  283.         int64_t allocated = 0;
  284.         int64_t unallocated = 0;
  285.         int64_t last_pos;
  286.  
  287.         int err = 0;
  288.  
  289.         COMPUTE_DBG(pool->screen, "* compute_memory_finalize_pending()\n");
  290.  
  291.         LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
  292.                 COMPUTE_DBG(pool->screen, "  + list: offset = %"PRIi64" id = %"PRIi64" size = %"PRIi64" "
  293.                         "(%"PRIi64" bytes)\n", item->start_in_dw, item->id,
  294.                         item->size_in_dw, item->size_in_dw * 4);
  295.         }
  296.  
  297.         /* Calculate the total allocated size */
  298.         LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
  299.                 allocated += align(item->size_in_dw, ITEM_ALIGNMENT);
  300.         }
  301.  
  302.         /* Calculate the total unallocated size of the items that
  303.          * will be promoted to the pool */
  304.         LIST_FOR_EACH_ENTRY(item, pool->unallocated_list, link) {
  305.                 if (item->status & ITEM_FOR_PROMOTING)
  306.                         unallocated += align(item->size_in_dw, ITEM_ALIGNMENT);
  307.         }
  308.  
  309.         if (unallocated == 0) {
  310.                 return 0;
  311.         }
  312.  
  313.         if (pool->size_in_dw < allocated + unallocated) {
  314.                 err = compute_memory_grow_defrag_pool(pool, pipe, allocated + unallocated);
  315.                 if (err == -1)
  316.                         return -1;
  317.         }
  318.         else if (pool->status & POOL_FRAGMENTED) {
  319.                 struct pipe_resource *src = (struct pipe_resource *)pool->bo;
  320.                 compute_memory_defrag(pool, src, src, pipe);
  321.         }
  322.  
  323.         /* After defragmenting the pool, allocated is equal to the first available
  324.          * position for new items in the pool */
  325.         last_pos = allocated;
  326.  
  327.         /* Loop through all the unallocated items, check if they are marked
  328.          * for promoting, allocate space for them and add them to the item_list. */
  329.         LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->unallocated_list, link) {
  330.                 if (item->status & ITEM_FOR_PROMOTING) {
  331.                         err = compute_memory_promote_item(pool, item, pipe, last_pos);
  332.                         item->status &= ~ITEM_FOR_PROMOTING;
  333.  
  334.                         last_pos += align(item->size_in_dw, ITEM_ALIGNMENT);
  335.  
  336.                         if (err == -1)
  337.                                 return -1;
  338.                 }
  339.         }
  340.  
  341.         return 0;
  342. }
  343.  
  344. /**
  345.  * Defragments the pool, so that there's no gap between items.
  346.  * \param pool  The pool to be defragmented
  347.  * \param src   The origin resource
  348.  * \param dst   The destination resource
  349.  * \see compute_memory_grow_defrag_pool and compute_memory_finalize_pending
  350.  */
  351. void compute_memory_defrag(struct compute_memory_pool *pool,
  352.         struct pipe_resource *src, struct pipe_resource *dst,
  353.         struct pipe_context *pipe)
  354. {
  355.         struct compute_memory_item *item;
  356.         int64_t last_pos;
  357.  
  358.         COMPUTE_DBG(pool->screen, "* compute_memory_defrag()\n");
  359.  
  360.         last_pos = 0;
  361.         LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
  362.                 if (src != dst || item->start_in_dw != last_pos) {
  363.                         assert(last_pos <= item->start_in_dw);
  364.  
  365.                         compute_memory_move_item(pool, src, dst,
  366.                                         item, last_pos, pipe);
  367.                 }
  368.  
  369.                 last_pos += align(item->size_in_dw, ITEM_ALIGNMENT);
  370.         }
  371.  
  372.         pool->status &= ~POOL_FRAGMENTED;
  373. }
  374.  
  375. /**
  376.  * Moves an item from the \a unallocated_list to the \a item_list.
  377.  * \param item  The item that will be promoted.
  378.  * \return -1 if it fails, 0 otherwise
  379.  * \see compute_memory_finalize_pending
  380.  */
  381. int compute_memory_promote_item(struct compute_memory_pool *pool,
  382.                 struct compute_memory_item *item, struct pipe_context *pipe,
  383.                 int64_t start_in_dw)
  384. {
  385.         struct pipe_screen *screen = (struct pipe_screen *)pool->screen;
  386.         struct r600_context *rctx = (struct r600_context *)pipe;
  387.         struct pipe_resource *src = (struct pipe_resource *)item->real_buffer;
  388.         struct pipe_resource *dst = (struct pipe_resource *)pool->bo;
  389.         struct pipe_box box;
  390.  
  391.         COMPUTE_DBG(pool->screen, "* compute_memory_promote_item()\n"
  392.                         "  + Promoting Item: %"PRIi64" , starting at: %"PRIi64" (%"PRIi64" bytes) "
  393.                         "size: %"PRIi64" (%"PRIi64" bytes)\n\t\t\tnew start: %"PRIi64" (%"PRIi64" bytes)\n",
  394.                         item->id, item->start_in_dw, item->start_in_dw * 4,
  395.                         item->size_in_dw, item->size_in_dw * 4,
  396.                         start_in_dw, start_in_dw * 4);
  397.  
  398.         /* Remove the item from the unallocated list */
  399.         list_del(&item->link);
  400.  
  401.         /* Add it back to the item_list */
  402.         list_addtail(&item->link, pool->item_list);
  403.         item->start_in_dw = start_in_dw;
  404.  
  405.         if (src != NULL) {
  406.                 u_box_1d(0, item->size_in_dw * 4, &box);
  407.  
  408.                 rctx->b.b.resource_copy_region(pipe,
  409.                                 dst, 0, item->start_in_dw * 4, 0 ,0,
  410.                                 src, 0, &box);
  411.  
  412.                 /* We check if the item is mapped for reading.
  413.                  * In this case, we need to keep the temporary buffer 'alive'
  414.                  * because it is possible to keep a map active for reading
  415.                  * while a kernel (that reads from it) executes */
  416.                 if (!(item->status & ITEM_MAPPED_FOR_READING)) {
  417.                         pool->screen->b.b.resource_destroy(screen, src);
  418.                         item->real_buffer = NULL;
  419.                 }
  420.         }
  421.  
  422.         return 0;
  423. }
  424.  
  425. /**
  426.  * Moves an item from the \a item_list to the \a unallocated_list.
  427.  * \param item  The item that will be demoted
  428.  * \see r600_compute_global_transfer_map
  429.  */
  430. void compute_memory_demote_item(struct compute_memory_pool *pool,
  431.         struct compute_memory_item *item, struct pipe_context *pipe)
  432. {
  433.         struct r600_context *rctx = (struct r600_context *)pipe;
  434.         struct pipe_resource *src = (struct pipe_resource *)pool->bo;
  435.         struct pipe_resource *dst;
  436.         struct pipe_box box;
  437.  
  438.         COMPUTE_DBG(pool->screen, "* compute_memory_demote_item()\n"
  439.                         "  + Demoting Item: %"PRIi64", starting at: %"PRIi64" (%"PRIi64" bytes) "
  440.                         "size: %"PRIi64" (%"PRIi64" bytes)\n", item->id, item->start_in_dw,
  441.                         item->start_in_dw * 4, item->size_in_dw, item->size_in_dw * 4);
  442.  
  443.         /* First, we remove the item from the item_list */
  444.         list_del(&item->link);
  445.  
  446.         /* Now we add it to the unallocated list */
  447.         list_addtail(&item->link, pool->unallocated_list);
  448.  
  449.         /* We check if the intermediate buffer exists, and if it
  450.          * doesn't, we create it again */
  451.         if (item->real_buffer == NULL) {
  452.                 item->real_buffer = (struct r600_resource*)r600_compute_buffer_alloc_vram(
  453.                                 pool->screen, item->size_in_dw * 4);
  454.         }
  455.  
  456.         dst = (struct pipe_resource *)item->real_buffer;
  457.  
  458.         /* We transfer the memory from the item in the pool to the
  459.          * temporary buffer */
  460.         u_box_1d(item->start_in_dw * 4, item->size_in_dw * 4, &box);
  461.  
  462.         rctx->b.b.resource_copy_region(pipe,
  463.                 dst, 0, 0, 0, 0,
  464.                 src, 0, &box);
  465.  
  466.         /* Remember to mark the buffer as 'pending' by setting start_in_dw to -1 */
  467.         item->start_in_dw = -1;
  468.  
  469.         if (item->link.next != pool->item_list) {
  470.                 pool->status |= POOL_FRAGMENTED;
  471.         }
  472. }
  473.  
  474. /**
  475.  * Moves the item \a item forward from the resource \a src to the
  476.  * resource \a dst at \a new_start_in_dw
  477.  *
  478.  * This function assumes two things:
  479.  * 1) The item is \b only moved forward, unless src is different from dst
  480.  * 2) The item \b won't change it's position inside the \a item_list
  481.  *
  482.  * \param item                  The item that will be moved
  483.  * \param new_start_in_dw       The new position of the item in \a item_list
  484.  * \see compute_memory_defrag
  485.  */
  486. void compute_memory_move_item(struct compute_memory_pool *pool,
  487.         struct pipe_resource *src, struct pipe_resource *dst,
  488.         struct compute_memory_item *item, uint64_t new_start_in_dw,
  489.         struct pipe_context *pipe)
  490. {
  491.         struct pipe_screen *screen = (struct pipe_screen *)pool->screen;
  492.         struct r600_context *rctx = (struct r600_context *)pipe;
  493.         struct pipe_box box;
  494.  
  495.         struct compute_memory_item *prev;
  496.  
  497.         COMPUTE_DBG(pool->screen, "* compute_memory_move_item()\n"
  498.                         "  + Moving item %"PRIi64" from %"PRIi64" (%"PRIi64" bytes) to %"PRIu64" (%"PRIu64" bytes)\n",
  499.                         item->id, item->start_in_dw, item->start_in_dw * 4,
  500.                         new_start_in_dw, new_start_in_dw * 4);
  501.  
  502.         if (pool->item_list != item->link.prev) {
  503.                 prev = container_of(item->link.prev, item, link);
  504.                 assert(prev->start_in_dw + prev->size_in_dw <= new_start_in_dw);
  505.         }
  506.  
  507.         u_box_1d(item->start_in_dw * 4, item->size_in_dw * 4, &box);
  508.  
  509.         /* If the ranges don't overlap, or we are copying from one resource
  510.          * to another, we can just copy the item directly */
  511.         if (src != dst || new_start_in_dw + item->size_in_dw <= item->start_in_dw) {
  512.  
  513.                 rctx->b.b.resource_copy_region(pipe,
  514.                         dst, 0, new_start_in_dw * 4, 0, 0,
  515.                         src, 0, &box);
  516.         } else {
  517.                 /* The ranges overlap, we will try first to use an intermediate
  518.                  * resource to move the item */
  519.                 struct pipe_resource *tmp = (struct pipe_resource *)
  520.                         r600_compute_buffer_alloc_vram(pool->screen, item->size_in_dw * 4);
  521.  
  522.                 if (tmp != NULL) {
  523.                         rctx->b.b.resource_copy_region(pipe,
  524.                                 tmp, 0, 0, 0, 0,
  525.                                 src, 0, &box);
  526.  
  527.                         box.x = 0;
  528.  
  529.                         rctx->b.b.resource_copy_region(pipe,
  530.                                 dst, 0, new_start_in_dw * 4, 0, 0,
  531.                                 tmp, 0, &box);
  532.  
  533.                         pool->screen->b.b.resource_destroy(screen, tmp);
  534.  
  535.                 } else {
  536.                         /* The allocation of the temporary resource failed,
  537.                          * falling back to use mappings */
  538.                         uint32_t *map;
  539.                         int64_t offset;
  540.                         struct pipe_transfer *trans;
  541.  
  542.                         offset = item->start_in_dw - new_start_in_dw;
  543.  
  544.                         u_box_1d(new_start_in_dw * 4, (offset + item->size_in_dw) * 4, &box);
  545.  
  546.                         map = pipe->transfer_map(pipe, src, 0, PIPE_TRANSFER_READ_WRITE,
  547.                                 &box, &trans);
  548.  
  549.                         assert(map);
  550.                         assert(trans);
  551.  
  552.                         memmove(map, map + offset, item->size_in_dw * 4);
  553.  
  554.                         pipe->transfer_unmap(pipe, trans);
  555.                 }
  556.         }
  557.  
  558.         item->start_in_dw = new_start_in_dw;
  559. }
  560.  
  561. /**
  562.  * Frees the memory asociated to the item with id \a id from the pool.
  563.  * \param id    The id of the item to be freed.
  564.  */
  565. void compute_memory_free(struct compute_memory_pool* pool, int64_t id)
  566. {
  567.         struct compute_memory_item *item, *next;
  568.         struct pipe_screen *screen = (struct pipe_screen *)pool->screen;
  569.         struct pipe_resource *res;
  570.  
  571.         COMPUTE_DBG(pool->screen, "* compute_memory_free() id + %ld \n", id);
  572.  
  573.         LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->item_list, link) {
  574.  
  575.                 if (item->id == id) {
  576.  
  577.                         if (item->link.next != pool->item_list) {
  578.                                 pool->status |= POOL_FRAGMENTED;
  579.                         }
  580.  
  581.                         list_del(&item->link);
  582.  
  583.                         if (item->real_buffer) {
  584.                                 res = (struct pipe_resource *)item->real_buffer;
  585.                                 pool->screen->b.b.resource_destroy(
  586.                                                 screen, res);
  587.                         }
  588.  
  589.                         free(item);
  590.  
  591.                         return;
  592.                 }
  593.         }
  594.  
  595.         LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->unallocated_list, link) {
  596.  
  597.                 if (item->id == id) {
  598.                         list_del(&item->link);
  599.  
  600.                         if (item->real_buffer) {
  601.                                 res = (struct pipe_resource *)item->real_buffer;
  602.                                 pool->screen->b.b.resource_destroy(
  603.                                                 screen, res);
  604.                         }
  605.  
  606.                         free(item);
  607.  
  608.                         return;
  609.                 }
  610.         }
  611.  
  612.         fprintf(stderr, "Internal error, invalid id %"PRIi64" "
  613.                 "for compute_memory_free\n", id);
  614.  
  615.         assert(0 && "error");
  616. }
  617.  
  618. /**
  619.  * Creates pending allocations for new items, these items are
  620.  * placed in the unallocated_list.
  621.  * \param size_in_dw    The size, in double words, of the new item.
  622.  * \return The new item
  623.  * \see r600_compute_global_buffer_create
  624.  */
  625. struct compute_memory_item* compute_memory_alloc(
  626.         struct compute_memory_pool* pool,
  627.         int64_t size_in_dw)
  628. {
  629.         struct compute_memory_item *new_item = NULL;
  630.  
  631.         COMPUTE_DBG(pool->screen, "* compute_memory_alloc() size_in_dw = %ld (%ld bytes)\n",
  632.                         size_in_dw, 4 * size_in_dw);
  633.  
  634.         new_item = (struct compute_memory_item *)
  635.                                 CALLOC(sizeof(struct compute_memory_item), 1);
  636.         if (new_item == NULL)
  637.                 return NULL;
  638.  
  639.         new_item->size_in_dw = size_in_dw;
  640.         new_item->start_in_dw = -1; /* mark pending */
  641.         new_item->id = pool->next_id++;
  642.         new_item->pool = pool;
  643.         new_item->real_buffer = NULL;
  644.  
  645.         list_addtail(&new_item->link, pool->unallocated_list);
  646.  
  647.         COMPUTE_DBG(pool->screen, "  + Adding item %p id = %"PRIi64" size = %"PRIi64" (%"PRIi64" bytes)\n",
  648.                         new_item, new_item->id, new_item->size_in_dw,
  649.                         new_item->size_in_dw * 4);
  650.         return new_item;
  651. }
  652.  
  653. /**
  654.  * Transfer data host<->device, offset and size is in bytes.
  655.  * \param device_to_host 1 for device->host, 0 for host->device.
  656.  * \see compute_memory_shadow
  657.  */
  658. void compute_memory_transfer(
  659.         struct compute_memory_pool* pool,
  660.         struct pipe_context * pipe,
  661.         int device_to_host,
  662.         struct compute_memory_item* chunk,
  663.         void* data,
  664.         int offset_in_chunk,
  665.         int size)
  666. {
  667.         int64_t aligned_size = pool->size_in_dw;
  668.         struct pipe_resource* gart = (struct pipe_resource*)pool->bo;
  669.         int64_t internal_offset = chunk->start_in_dw*4 + offset_in_chunk;
  670.  
  671.         struct pipe_transfer *xfer;
  672.         uint32_t *map;
  673.  
  674.         assert(gart);
  675.  
  676.         COMPUTE_DBG(pool->screen, "* compute_memory_transfer() device_to_host = %d, "
  677.                 "offset_in_chunk = %d, size = %d\n", device_to_host,
  678.                 offset_in_chunk, size);
  679.  
  680.         if (device_to_host) {
  681.                 map = pipe->transfer_map(pipe, gart, 0, PIPE_TRANSFER_READ,
  682.                         &(struct pipe_box) { .width = aligned_size * 4,
  683.                         .height = 1, .depth = 1 }, &xfer);
  684.                 assert(xfer);
  685.                 assert(map);
  686.                 memcpy(data, map + internal_offset, size);
  687.                 pipe->transfer_unmap(pipe, xfer);
  688.         } else {
  689.                 map = pipe->transfer_map(pipe, gart, 0, PIPE_TRANSFER_WRITE,
  690.                         &(struct pipe_box) { .width = aligned_size * 4,
  691.                         .height = 1, .depth = 1 }, &xfer);
  692.                 assert(xfer);
  693.                 assert(map);
  694.                 memcpy(map + internal_offset, data, size);
  695.                 pipe->transfer_unmap(pipe, xfer);
  696.         }
  697. }
  698.  
  699. /**
  700.  * Transfer data between chunk<->data, it is for VRAM<->GART transfers
  701.  */
  702. void compute_memory_transfer_direct(
  703.         struct compute_memory_pool* pool,
  704.         int chunk_to_data,
  705.         struct compute_memory_item* chunk,
  706.         struct r600_resource* data,
  707.         int offset_in_chunk,
  708.         int offset_in_data,
  709.         int size)
  710. {
  711.         ///TODO: DMA
  712. }
  713.