Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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/u_double_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_memory.h"
  34. #include "util/u_inlines.h"
  35. #include "util/u_framebuffer.h"
  36. #include "r600_resource.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. /**
  46.  * Creates a new pool
  47.  */
  48. struct compute_memory_pool* compute_memory_pool_new(
  49.         struct r600_screen * rscreen)
  50. {
  51.         struct compute_memory_pool* pool = (struct compute_memory_pool*)
  52.                                 CALLOC(sizeof(struct compute_memory_pool), 1);
  53.  
  54.         COMPUTE_DBG(rscreen, "* compute_memory_pool_new()\n");
  55.  
  56.         pool->screen = rscreen;
  57.         return pool;
  58. }
  59.  
  60. static void compute_memory_pool_init(struct compute_memory_pool * pool,
  61.         unsigned initial_size_in_dw)
  62. {
  63.  
  64.         COMPUTE_DBG(pool->screen, "* compute_memory_pool_init() initial_size_in_dw = %ld\n",
  65.                 initial_size_in_dw);
  66.  
  67.         pool->shadow = (uint32_t*)CALLOC(initial_size_in_dw, 4);
  68.         pool->next_id = 1;
  69.         pool->size_in_dw = initial_size_in_dw;
  70.         pool->bo = (struct r600_resource*)r600_compute_buffer_alloc_vram(pool->screen,
  71.                                                         pool->size_in_dw * 4);
  72. }
  73.  
  74. /**
  75.  * Frees all stuff in the pool and the pool struct itself too
  76.  */
  77. void compute_memory_pool_delete(struct compute_memory_pool* pool)
  78. {
  79.         COMPUTE_DBG(pool->screen, "* compute_memory_pool_delete()\n");
  80.         free(pool->shadow);
  81.         if (pool->bo) {
  82.                 pool->screen->screen.resource_destroy((struct pipe_screen *)
  83.                         pool->screen, (struct pipe_resource *)pool->bo);
  84.         }
  85.         free(pool);
  86. }
  87.  
  88. /**
  89.  * Searches for an empty space in the pool, return with the pointer to the
  90.  * allocatable space in the pool, returns -1 on failure.
  91.  */
  92. int64_t compute_memory_prealloc_chunk(
  93.         struct compute_memory_pool* pool,
  94.         int64_t size_in_dw)
  95. {
  96.         struct compute_memory_item *item;
  97.  
  98.         int last_end = 0;
  99.  
  100.         assert(size_in_dw <= pool->size_in_dw);
  101.  
  102.         COMPUTE_DBG(pool->screen, "* compute_memory_prealloc_chunk() size_in_dw = %ld\n",
  103.                 size_in_dw);
  104.  
  105.         for (item = pool->item_list; item; item = item->next) {
  106.                 if (item->start_in_dw > -1) {
  107.                         if (item->start_in_dw-last_end > size_in_dw) {
  108.                                 return last_end;
  109.                         }
  110.  
  111.                         last_end = item->start_in_dw + item->size_in_dw;
  112.                         last_end += (1024 - last_end % 1024);
  113.                 }
  114.         }
  115.  
  116.         if (pool->size_in_dw - last_end < size_in_dw) {
  117.                 return -1;
  118.         }
  119.  
  120.         return last_end;
  121. }
  122.  
  123. /**
  124.  *  Search for the chunk where we can link our new chunk after it.
  125.  */
  126. struct compute_memory_item* compute_memory_postalloc_chunk(
  127.         struct compute_memory_pool* pool,
  128.         int64_t start_in_dw)
  129. {
  130.         struct compute_memory_item* item;
  131.  
  132.         COMPUTE_DBG(pool->screen, "* compute_memory_postalloc_chunck() start_in_dw = %ld\n",
  133.                 start_in_dw);
  134.  
  135.         /* Check if we can insert it in the front of the list */
  136.         if (pool->item_list && pool->item_list->start_in_dw > start_in_dw) {
  137.                 return NULL;
  138.         }
  139.  
  140.         for (item = pool->item_list; item; item = item->next) {
  141.                 if (item->next) {
  142.                         if (item->start_in_dw < start_in_dw
  143.                                 && item->next->start_in_dw > start_in_dw) {
  144.                                 return item;
  145.                         }
  146.                 }
  147.                 else {
  148.                         /* end of chain */
  149.                         assert(item->start_in_dw < start_in_dw);
  150.                         return item;
  151.                 }
  152.         }
  153.  
  154.         assert(0 && "unreachable");
  155.         return NULL;
  156. }
  157.  
  158. /**
  159.  * Reallocates pool, conserves data
  160.  */
  161. void compute_memory_grow_pool(struct compute_memory_pool* pool,
  162.         struct pipe_context * pipe, int new_size_in_dw)
  163. {
  164.         COMPUTE_DBG(pool->screen, "* compute_memory_grow_pool() new_size_in_dw = %d\n",
  165.                 new_size_in_dw);
  166.  
  167.         assert(new_size_in_dw >= pool->size_in_dw);
  168.  
  169.         if (!pool->bo) {
  170.                 compute_memory_pool_init(pool, MAX2(new_size_in_dw, 1024 * 16));
  171.         } else {
  172.                 new_size_in_dw += 1024 - (new_size_in_dw % 1024);
  173.  
  174.                 COMPUTE_DBG(pool->screen, "  Aligned size = %d\n", new_size_in_dw);
  175.  
  176.                 compute_memory_shadow(pool, pipe, 1);
  177.                 pool->shadow = realloc(pool->shadow, new_size_in_dw*4);
  178.                 pool->size_in_dw = new_size_in_dw;
  179.                 pool->screen->screen.resource_destroy(
  180.                         (struct pipe_screen *)pool->screen,
  181.                         (struct pipe_resource *)pool->bo);
  182.                 pool->bo = (struct r600_resource*)r600_compute_buffer_alloc_vram(
  183.                                                         pool->screen,
  184.                                                         pool->size_in_dw * 4);
  185.                 compute_memory_shadow(pool, pipe, 0);
  186.         }
  187. }
  188.  
  189. /**
  190.  * Copy pool from device to host, or host to device.
  191.  */
  192. void compute_memory_shadow(struct compute_memory_pool* pool,
  193.         struct pipe_context * pipe, int device_to_host)
  194. {
  195.         struct compute_memory_item chunk;
  196.  
  197.         COMPUTE_DBG(pool->screen, "* compute_memory_shadow() device_to_host = %d\n",
  198.                 device_to_host);
  199.  
  200.         chunk.id = 0;
  201.         chunk.start_in_dw = 0;
  202.         chunk.size_in_dw = pool->size_in_dw;
  203.         chunk.prev = chunk.next = NULL;
  204.         compute_memory_transfer(pool, pipe, device_to_host, &chunk,
  205.                                 pool->shadow, 0, pool->size_in_dw*4);
  206. }
  207.  
  208. /**
  209.  * Allocates pending allocations in the pool
  210.  */
  211. void compute_memory_finalize_pending(struct compute_memory_pool* pool,
  212.         struct pipe_context * pipe)
  213. {
  214.         struct compute_memory_item *pending_list = NULL, *end_p = NULL;
  215.         struct compute_memory_item *item, *next;
  216.  
  217.         int64_t allocated = 0;
  218.         int64_t unallocated = 0;
  219.  
  220.         int64_t start_in_dw = 0;
  221.  
  222.         COMPUTE_DBG(pool->screen, "* compute_memory_finalize_pending()\n");
  223.  
  224.         for (item = pool->item_list; item; item = item->next) {
  225.                 COMPUTE_DBG(pool->screen, "  + list: offset = %i id = %i size = %i "
  226.                         "(%i bytes)\n",item->start_in_dw, item->id,
  227.                         item->size_in_dw, item->size_in_dw * 4);
  228.         }
  229.  
  230.         /* Search through the list of memory items in the pool */
  231.         for (item = pool->item_list; item; item = next) {
  232.                 next = item->next;
  233.  
  234.                 /* Check if the item is pending. */
  235.                 if (item->start_in_dw == -1) {
  236.                         /* It is pending, so add it to the pending_list... */
  237.                         if (end_p) {
  238.                                 end_p->next = item;
  239.                         }
  240.                         else {
  241.                                 pending_list = item;
  242.                         }
  243.  
  244.                         /* ... and then remove it from the item list. */
  245.                         if (item->prev) {
  246.                                 item->prev->next = next;
  247.                         }
  248.                         else {
  249.                                 pool->item_list = next;
  250.                         }
  251.  
  252.                         if (next) {
  253.                                 next->prev = item->prev;
  254.                         }
  255.  
  256.                         /* This sequence makes the item be at the end of the list */
  257.                         item->prev = end_p;
  258.                         item->next = NULL;
  259.                         end_p = item;
  260.  
  261.                         /* Update the amount of space we will need to allocate. */
  262.                         unallocated += item->size_in_dw+1024;
  263.                 }
  264.                 else {
  265.                         /* The item is not pendng, so update the amount of space
  266.                          * that has already been allocated. */
  267.                         allocated += item->size_in_dw;
  268.                 }
  269.         }
  270.  
  271.         /* If we require more space than the size of the pool, then grow the
  272.          * pool.
  273.          *
  274.          * XXX: I'm pretty sure this won't work.  Imagine this scenario:
  275.          *
  276.          * Offset Item Size
  277.          *   0    A    50
  278.          * 200    B    50
  279.          * 400    C    50
  280.          *
  281.          * Total size = 450
  282.          * Allocated size = 150
  283.          * Pending Item D Size = 200
  284.          *
  285.          * In this case, there are 300 units of free space in the pool, but
  286.          * they aren't contiguous, so it will be impossible to allocate Item D.
  287.          */
  288.         if (pool->size_in_dw < allocated+unallocated) {
  289.                 compute_memory_grow_pool(pool, pipe, allocated+unallocated);
  290.         }
  291.  
  292.         /* Loop through all the pending items, allocate space for them and
  293.          * add them back to the item_list. */
  294.         for (item = pending_list; item; item = next) {
  295.                 next = item->next;
  296.  
  297.                 /* Search for free space in the pool for this item. */
  298.                 while ((start_in_dw=compute_memory_prealloc_chunk(pool,
  299.                                                 item->size_in_dw)) == -1) {
  300.                         int64_t need = item->size_in_dw+2048 -
  301.                                                 (pool->size_in_dw - allocated);
  302.  
  303.                         need += 1024 - (need % 1024);
  304.  
  305.                         if (need > 0) {
  306.                                 compute_memory_grow_pool(pool,
  307.                                                 pipe,
  308.                                                 pool->size_in_dw + need);
  309.                         }
  310.                         else {
  311.                                 need = pool->size_in_dw / 10;
  312.                                 need += 1024 - (need % 1024);
  313.                                 compute_memory_grow_pool(pool,
  314.                                                 pipe,
  315.                                                 pool->size_in_dw + need);
  316.                         }
  317.                 }
  318.                 COMPUTE_DBG(pool->screen, "  + Found space for Item %p id = %u "
  319.                         "start_in_dw = %u (%u bytes) size_in_dw = %u (%u bytes)\n",
  320.                         item, item->id, start_in_dw, start_in_dw * 4,
  321.                         item->size_in_dw, item->size_in_dw * 4);
  322.  
  323.                 item->start_in_dw = start_in_dw;
  324.                 item->next = NULL;
  325.                 item->prev = NULL;
  326.  
  327.                 if (pool->item_list) {
  328.                         struct compute_memory_item *pos;
  329.  
  330.                         pos = compute_memory_postalloc_chunk(pool, start_in_dw);
  331.                         if (pos) {
  332.                                 item->prev = pos;
  333.                                 item->next = pos->next;
  334.                                 pos->next = item;
  335.                                 if (item->next) {
  336.                                         item->next->prev = item;
  337.                                 }
  338.                         } else {
  339.                                 /* Add item to the front of the list */
  340.                                 item->next = pool->item_list->next;
  341.                                 if (pool->item_list->next) {
  342.                                         pool->item_list->next->prev = item;
  343.                                 }
  344.                                 item->prev = pool->item_list->prev;
  345.                                 if (pool->item_list->prev) {
  346.                                         pool->item_list->prev->next = item;
  347.                                 }
  348.                                 pool->item_list = item;
  349.                         }
  350.                 }
  351.                 else {
  352.                         pool->item_list = item;
  353.                 }
  354.  
  355.                 allocated += item->size_in_dw;
  356.         }
  357. }
  358.  
  359.  
  360. void compute_memory_free(struct compute_memory_pool* pool, int64_t id)
  361. {
  362.         struct compute_memory_item *item, *next;
  363.  
  364.         COMPUTE_DBG(pool->screen, "* compute_memory_free() id + %ld \n", id);
  365.  
  366.         for (item = pool->item_list; item; item = next) {
  367.                 next = item->next;
  368.  
  369.                 if (item->id == id) {
  370.                         if (item->prev) {
  371.                                 item->prev->next = item->next;
  372.                         }
  373.                         else {
  374.                                 pool->item_list = item->next;
  375.                         }
  376.  
  377.                         if (item->next) {
  378.                                 item->next->prev = item->prev;
  379.                         }
  380.  
  381.                         free(item);
  382.  
  383.                         return;
  384.                 }
  385.         }
  386.  
  387.         fprintf(stderr, "Internal error, invalid id %"PRIi64" "
  388.                 "for compute_memory_free\n", id);
  389.  
  390.         assert(0 && "error");
  391. }
  392.  
  393. /**
  394.  * Creates pending allocations
  395.  */
  396. struct compute_memory_item* compute_memory_alloc(
  397.         struct compute_memory_pool* pool,
  398.         int64_t size_in_dw)
  399. {
  400.         struct compute_memory_item *new_item = NULL, *last_item = NULL;
  401.  
  402.         COMPUTE_DBG(pool->screen, "* compute_memory_alloc() size_in_dw = %ld (%ld bytes)\n",
  403.                         size_in_dw, 4 * size_in_dw);
  404.  
  405.         new_item = (struct compute_memory_item *)
  406.                                 CALLOC(sizeof(struct compute_memory_item), 1);
  407.         new_item->size_in_dw = size_in_dw;
  408.         new_item->start_in_dw = -1; /* mark pending */
  409.         new_item->id = pool->next_id++;
  410.         new_item->pool = pool;
  411.  
  412.         if (pool->item_list) {
  413.                 for (last_item = pool->item_list; last_item->next;
  414.                                                 last_item = last_item->next);
  415.  
  416.                 last_item->next = new_item;
  417.                 new_item->prev = last_item;
  418.         }
  419.         else {
  420.                 pool->item_list = new_item;
  421.         }
  422.  
  423.         COMPUTE_DBG(pool->screen, "  + Adding item %p id = %u size = %u (%u bytes)\n",
  424.                         new_item, new_item->id, new_item->size_in_dw,
  425.                         new_item->size_in_dw * 4);
  426.         return new_item;
  427. }
  428.  
  429. /**
  430.  * Transfer data host<->device, offset and size is in bytes
  431.  */
  432. void compute_memory_transfer(
  433.         struct compute_memory_pool* pool,
  434.         struct pipe_context * pipe,
  435.         int device_to_host,
  436.         struct compute_memory_item* chunk,
  437.         void* data,
  438.         int offset_in_chunk,
  439.         int size)
  440. {
  441.         int64_t aligned_size = pool->size_in_dw;
  442.         struct pipe_resource* gart = (struct pipe_resource*)pool->bo;
  443.         int64_t internal_offset = chunk->start_in_dw*4 + offset_in_chunk;
  444.  
  445.         struct pipe_transfer *xfer;
  446.         uint32_t *map;
  447.  
  448.         assert(gart);
  449.  
  450.         COMPUTE_DBG(pool->screen, "* compute_memory_transfer() device_to_host = %d, "
  451.                 "offset_in_chunk = %d, size = %d\n", device_to_host,
  452.                 offset_in_chunk, size);
  453.  
  454.         if (device_to_host) {
  455.                 map = pipe->transfer_map(pipe, gart, 0, PIPE_TRANSFER_READ,
  456.                         &(struct pipe_box) { .width = aligned_size,
  457.                         .height = 1, .depth = 1 }, &xfer);
  458.                 assert(xfer);
  459.                 assert(map);
  460.                 memcpy(data, map + internal_offset, size);
  461.                 pipe->transfer_unmap(pipe, xfer);
  462.         } else {
  463.                 map = pipe->transfer_map(pipe, gart, 0, PIPE_TRANSFER_WRITE,
  464.                         &(struct pipe_box) { .width = aligned_size,
  465.                         .height = 1, .depth = 1 }, &xfer);
  466.                 assert(xfer);
  467.                 assert(map);
  468.                 memcpy(map + internal_offset, data, size);
  469.                 pipe->transfer_unmap(pipe, xfer);
  470.         }
  471. }
  472.  
  473. /**
  474.  * Transfer data between chunk<->data, it is for VRAM<->GART transfers
  475.  */
  476. void compute_memory_transfer_direct(
  477.         struct compute_memory_pool* pool,
  478.         int chunk_to_data,
  479.         struct compute_memory_item* chunk,
  480.         struct r600_resource* data,
  481.         int offset_in_chunk,
  482.         int offset_in_data,
  483.         int size)
  484. {
  485.         ///TODO: DMA
  486. }
  487.