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 /* A few forward declarations of static functions */
48 static void compute_memory_shadow(struct compute_memory_pool* pool,
49 struct pipe_context *pipe, int device_to_host);
50
51 static void compute_memory_defrag(struct compute_memory_pool *pool,
52 struct pipe_resource *src, struct pipe_resource *dst,
53 struct pipe_context *pipe);
54
55 static int compute_memory_promote_item(struct compute_memory_pool *pool,
56 struct compute_memory_item *item, struct pipe_context *pipe,
57 int64_t allocated);
58
59 static void compute_memory_move_item(struct compute_memory_pool *pool,
60 struct pipe_resource *src, struct pipe_resource *dst,
61 struct compute_memory_item *item, uint64_t new_start_in_dw,
62 struct pipe_context *pipe);
63
64 static void compute_memory_transfer(struct compute_memory_pool* pool,
65 struct pipe_context * pipe, int device_to_host,
66 struct compute_memory_item* chunk, void* data,
67 int offset_in_chunk, int size);
68
69 /**
70 * Creates a new pool.
71 */
compute_memory_pool_new(struct r600_screen * rscreen)72 struct compute_memory_pool* compute_memory_pool_new(
73 struct r600_screen * rscreen)
74 {
75 struct compute_memory_pool* pool = (struct compute_memory_pool*)
76 CALLOC(sizeof(struct compute_memory_pool), 1);
77 if (!pool)
78 return NULL;
79
80 COMPUTE_DBG(rscreen, "* compute_memory_pool_new()\n");
81
82 pool->screen = rscreen;
83 pool->item_list = (struct list_head *)
84 CALLOC(sizeof(struct list_head), 1);
85 pool->unallocated_list = (struct list_head *)
86 CALLOC(sizeof(struct list_head), 1);
87 list_inithead(pool->item_list);
88 list_inithead(pool->unallocated_list);
89 return pool;
90 }
91
92 /**
93 * Initializes the pool with a size of \a initial_size_in_dw.
94 * \param pool The pool to be initialized.
95 * \param initial_size_in_dw The initial size.
96 * \see compute_memory_grow_defrag_pool
97 */
compute_memory_pool_init(struct compute_memory_pool * pool,unsigned initial_size_in_dw)98 static void compute_memory_pool_init(struct compute_memory_pool * pool,
99 unsigned initial_size_in_dw)
100 {
101
102 COMPUTE_DBG(pool->screen, "* compute_memory_pool_init() initial_size_in_dw = %u\n",
103 initial_size_in_dw);
104
105 pool->size_in_dw = initial_size_in_dw;
106 pool->bo = r600_compute_buffer_alloc_vram(pool->screen,
107 pool->size_in_dw * 4);
108 }
109
110 /**
111 * Frees all stuff in the pool and the pool struct itself too.
112 */
compute_memory_pool_delete(struct compute_memory_pool * pool)113 void compute_memory_pool_delete(struct compute_memory_pool* pool)
114 {
115 COMPUTE_DBG(pool->screen, "* compute_memory_pool_delete()\n");
116 free(pool->shadow);
117 r600_resource_reference(&pool->bo, NULL);
118 /* In theory, all of the items were freed in compute_memory_free.
119 * Just delete the list heads
120 */
121 free(pool->item_list);
122 free(pool->unallocated_list);
123 /* And then the pool itself */
124 free(pool);
125 }
126
127 /**
128 * Reallocates and defragments the pool, conserves data.
129 * \returns -1 if it fails, 0 otherwise
130 * \see compute_memory_finalize_pending
131 */
compute_memory_grow_defrag_pool(struct compute_memory_pool * pool,struct pipe_context * pipe,int new_size_in_dw)132 static int compute_memory_grow_defrag_pool(struct compute_memory_pool *pool,
133 struct pipe_context *pipe, int new_size_in_dw)
134 {
135 new_size_in_dw = align(new_size_in_dw, ITEM_ALIGNMENT);
136
137 COMPUTE_DBG(pool->screen, "* compute_memory_grow_defrag_pool() "
138 "new_size_in_dw = %d (%d bytes)\n",
139 new_size_in_dw, new_size_in_dw * 4);
140
141 assert(new_size_in_dw >= pool->size_in_dw);
142
143 if (!pool->bo) {
144 compute_memory_pool_init(pool, MAX2(new_size_in_dw, 1024 * 16));
145 } else {
146 struct r600_resource *temp = NULL;
147
148 temp = r600_compute_buffer_alloc_vram(pool->screen, new_size_in_dw * 4);
149
150 if (temp != NULL) {
151 struct pipe_resource *src = (struct pipe_resource *)pool->bo;
152 struct pipe_resource *dst = (struct pipe_resource *)temp;
153
154 COMPUTE_DBG(pool->screen, " Growing and defragmenting the pool "
155 "using a temporary resource\n");
156
157 compute_memory_defrag(pool, src, dst, pipe);
158
159 /* Release the old buffer */
160 r600_resource_reference(&pool->bo, NULL);
161 pool->bo = temp;
162 pool->size_in_dw = new_size_in_dw;
163 }
164 else {
165 COMPUTE_DBG(pool->screen, " The creation of the temporary resource failed\n"
166 " Falling back to using 'shadow'\n");
167
168 compute_memory_shadow(pool, pipe, 1);
169 pool->shadow = realloc(pool->shadow, new_size_in_dw * 4);
170 if (pool->shadow == NULL)
171 return -1;
172
173 pool->size_in_dw = new_size_in_dw;
174 /* Release the old buffer */
175 r600_resource_reference(&pool->bo, NULL);
176 pool->bo = r600_compute_buffer_alloc_vram(pool->screen, pool->size_in_dw * 4);
177 compute_memory_shadow(pool, pipe, 0);
178
179 if (pool->status & POOL_FRAGMENTED) {
180 struct pipe_resource *src = (struct pipe_resource *)pool->bo;
181 compute_memory_defrag(pool, src, src, pipe);
182 }
183 }
184 }
185
186 return 0;
187 }
188
189 /**
190 * Copy pool from device to host, or host to device.
191 * \param device_to_host 1 for device->host, 0 for host->device
192 * \see compute_memory_grow_defrag_pool
193 */
compute_memory_shadow(struct compute_memory_pool * pool,struct pipe_context * pipe,int device_to_host)194 static void compute_memory_shadow(struct compute_memory_pool* pool,
195 struct pipe_context * pipe, int device_to_host)
196 {
197 struct compute_memory_item chunk;
198
199 COMPUTE_DBG(pool->screen, "* compute_memory_shadow() device_to_host = %d\n",
200 device_to_host);
201
202 chunk.id = 0;
203 chunk.start_in_dw = 0;
204 chunk.size_in_dw = pool->size_in_dw;
205 compute_memory_transfer(pool, pipe, device_to_host, &chunk,
206 pool->shadow, 0, pool->size_in_dw*4);
207 }
208
209 /**
210 * Moves all the items marked for promotion from the \a unallocated_list
211 * to the \a item_list.
212 * \return -1 if it fails, 0 otherwise
213 * \see evergreen_set_global_binding
214 */
compute_memory_finalize_pending(struct compute_memory_pool * pool,struct pipe_context * pipe)215 int compute_memory_finalize_pending(struct compute_memory_pool* pool,
216 struct pipe_context * pipe)
217 {
218 struct compute_memory_item *item, *next;
219
220 int64_t allocated = 0;
221 int64_t unallocated = 0;
222 int64_t last_pos;
223
224 int err = 0;
225
226 COMPUTE_DBG(pool->screen, "* compute_memory_finalize_pending()\n");
227
228 LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
229 COMPUTE_DBG(pool->screen, " + list: offset = %"PRIi64" id = %"PRIi64" size = %"PRIi64" "
230 "(%"PRIi64" bytes)\n", item->start_in_dw, item->id,
231 item->size_in_dw, item->size_in_dw * 4);
232 }
233
234 /* Calculate the total allocated size */
235 LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
236 allocated += align(item->size_in_dw, ITEM_ALIGNMENT);
237 }
238
239 /* Calculate the total unallocated size of the items that
240 * will be promoted to the pool */
241 LIST_FOR_EACH_ENTRY(item, pool->unallocated_list, link) {
242 if (item->status & ITEM_FOR_PROMOTING)
243 unallocated += align(item->size_in_dw, ITEM_ALIGNMENT);
244 }
245
246 if (unallocated == 0) {
247 return 0;
248 }
249
250 if (pool->size_in_dw < allocated + unallocated) {
251 err = compute_memory_grow_defrag_pool(pool, pipe, allocated + unallocated);
252 if (err == -1)
253 return -1;
254 }
255 else if (pool->status & POOL_FRAGMENTED) {
256 /* Loop through all unallocated items marked for promoting to
257 * insert them into an appropriate existing hole prior to defrag. */
258 LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->unallocated_list, link) {
259 if (!(item->status & ITEM_FOR_PROMOTING))
260 continue;
261
262 int64_t hole_start = 0, hole_size = 0;
263 int64_t item_size = align(item->size_in_dw, ITEM_ALIGNMENT);
264 struct compute_memory_item *alloc_item, *alloc_next;
265 LIST_FOR_EACH_ENTRY_SAFE(alloc_item, alloc_next, pool->item_list, link) {
266 if (alloc_item->start_in_dw == hole_start) {
267 hole_start += align(alloc_item->size_in_dw, ITEM_ALIGNMENT);
268 hole_size = 0;
269 } else if (alloc_item->start_in_dw > hole_start) {
270 hole_size = alloc_item->start_in_dw - hole_start;
271 }
272 }
273
274 /* Space after all items is also a hole. */
275 if (hole_size == 0 && hole_start < pool->size_in_dw)
276 hole_size = pool->size_in_dw - hole_start;
277
278 if (hole_size >= item_size) {
279 if (compute_memory_promote_item(pool, item, pipe, hole_start) != -1) {
280 item->status &= ~ITEM_FOR_PROMOTING;
281 unallocated -= item_size;
282 allocated += item_size;
283 }
284 }
285 }
286
287 if (allocated == pool->size_in_dw)
288 pool->status &= ~POOL_FRAGMENTED;
289
290 if (unallocated == 0)
291 return 0;
292
293 struct pipe_resource *src = (struct pipe_resource *)pool->bo;
294 compute_memory_defrag(pool, src, src, pipe);
295 }
296
297 /* After defragmenting the pool, allocated is equal to the first available
298 * position for new items in the pool */
299 last_pos = allocated;
300
301 /* Loop through all the unallocated items, check if they are marked
302 * for promoting, allocate space for them and add them to the item_list. */
303 LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->unallocated_list, link) {
304 if (item->status & ITEM_FOR_PROMOTING) {
305 err = compute_memory_promote_item(pool, item, pipe, last_pos);
306 item->status &= ~ITEM_FOR_PROMOTING;
307
308 last_pos += align(item->size_in_dw, ITEM_ALIGNMENT);
309
310 if (err == -1)
311 return -1;
312 }
313 }
314
315 return 0;
316 }
317
318 /**
319 * Defragments the pool, so that there's no gap between items.
320 * \param pool The pool to be defragmented
321 * \param src The origin resource
322 * \param dst The destination resource
323 * \see compute_memory_grow_defrag_pool and compute_memory_finalize_pending
324 */
compute_memory_defrag(struct compute_memory_pool * pool,struct pipe_resource * src,struct pipe_resource * dst,struct pipe_context * pipe)325 static void compute_memory_defrag(struct compute_memory_pool *pool,
326 struct pipe_resource *src, struct pipe_resource *dst,
327 struct pipe_context *pipe)
328 {
329 struct compute_memory_item *item;
330 int64_t last_pos;
331
332 COMPUTE_DBG(pool->screen, "* compute_memory_defrag()\n");
333
334 last_pos = 0;
335 LIST_FOR_EACH_ENTRY(item, pool->item_list, link) {
336 if (src != dst || item->start_in_dw != last_pos) {
337 assert(last_pos <= item->start_in_dw);
338
339 compute_memory_move_item(pool, src, dst,
340 item, last_pos, pipe);
341 }
342
343 last_pos += align(item->size_in_dw, ITEM_ALIGNMENT);
344 }
345
346 pool->status &= ~POOL_FRAGMENTED;
347 }
348
349 /**
350 * Moves an item from the \a unallocated_list to the \a item_list.
351 * \param item The item that will be promoted.
352 * \return -1 if it fails, 0 otherwise
353 * \see compute_memory_finalize_pending
354 */
compute_memory_promote_item(struct compute_memory_pool * pool,struct compute_memory_item * item,struct pipe_context * pipe,int64_t start_in_dw)355 static int compute_memory_promote_item(struct compute_memory_pool *pool,
356 struct compute_memory_item *item, struct pipe_context *pipe,
357 int64_t start_in_dw)
358 {
359 struct pipe_screen *screen = (struct pipe_screen *)pool->screen;
360 struct r600_context *rctx = (struct r600_context *)pipe;
361 struct pipe_resource *src = (struct pipe_resource *)item->real_buffer;
362 struct pipe_resource *dst = (struct pipe_resource *)pool->bo;
363 struct pipe_box box;
364
365 COMPUTE_DBG(pool->screen, "* compute_memory_promote_item()\n"
366 " + Promoting Item: %"PRIi64" , starting at: %"PRIi64" (%"PRIi64" bytes) "
367 "size: %"PRIi64" (%"PRIi64" bytes)\n\t\t\tnew start: %"PRIi64" (%"PRIi64" bytes)\n",
368 item->id, item->start_in_dw, item->start_in_dw * 4,
369 item->size_in_dw, item->size_in_dw * 4,
370 start_in_dw, start_in_dw * 4);
371
372 /* Remove the item from the unallocated list */
373 list_del(&item->link);
374
375 /* Add it back to the item_list */
376 list_addtail(&item->link, pool->item_list);
377 item->start_in_dw = start_in_dw;
378
379 if (src) {
380 u_box_1d(0, item->size_in_dw * 4, &box);
381
382 rctx->b.b.resource_copy_region(pipe,
383 dst, 0, item->start_in_dw * 4, 0 ,0,
384 src, 0, &box);
385
386 /* We check if the item is mapped for reading.
387 * In this case, we need to keep the temporary buffer 'alive'
388 * because it is possible to keep a map active for reading
389 * while a kernel (that reads from it) executes */
390 if (!(item->status & ITEM_MAPPED_FOR_READING) && !is_item_user_ptr(item)) {
391 pool->screen->b.b.resource_destroy(screen, src);
392 item->real_buffer = NULL;
393 }
394 }
395
396 return 0;
397 }
398
399 /**
400 * Moves an item from the \a item_list to the \a unallocated_list.
401 * \param item The item that will be demoted
402 * \see r600_compute_global_transfer_map
403 */
compute_memory_demote_item(struct compute_memory_pool * pool,struct compute_memory_item * item,struct pipe_context * pipe)404 void compute_memory_demote_item(struct compute_memory_pool *pool,
405 struct compute_memory_item *item, struct pipe_context *pipe)
406 {
407 struct r600_context *rctx = (struct r600_context *)pipe;
408 struct pipe_resource *src = (struct pipe_resource *)pool->bo;
409 struct pipe_resource *dst;
410 struct pipe_box box;
411
412 COMPUTE_DBG(pool->screen, "* compute_memory_demote_item()\n"
413 " + Demoting Item: %"PRIi64", starting at: %"PRIi64" (%"PRIi64" bytes) "
414 "size: %"PRIi64" (%"PRIi64" bytes)\n", item->id, item->start_in_dw,
415 item->start_in_dw * 4, item->size_in_dw, item->size_in_dw * 4);
416
417 /* First, we remove the item from the item_list */
418 list_del(&item->link);
419
420 /* Now we add it to the unallocated list */
421 list_addtail(&item->link, pool->unallocated_list);
422
423 /* We check if the intermediate buffer exists, and if it
424 * doesn't, we create it again */
425 if (item->real_buffer == NULL) {
426 item->real_buffer = r600_compute_buffer_alloc_vram(
427 pool->screen, item->size_in_dw * 4);
428 }
429
430 dst = (struct pipe_resource *)item->real_buffer;
431
432 /* We transfer the memory from the item in the pool to the
433 * temporary buffer. Download is skipped for items:
434 * - Not mapped for reading or writing (PIPE_MAP_DISCARD_RANGE).
435 * - Not writable by the device. */
436 if ((item->status & (ITEM_MAPPED_FOR_READING|ITEM_MAPPED_FOR_WRITING)) &&
437 !(r600_resource(dst)->flags & RADEON_FLAG_READ_ONLY)) {
438
439 u_box_1d(item->start_in_dw * 4, item->size_in_dw * 4, &box);
440
441 rctx->b.b.resource_copy_region(pipe,
442 dst, 0, 0, 0, 0,
443 src, 0, &box);
444 }
445
446 /* Remember to mark the buffer as 'pending' by setting start_in_dw to -1 */
447 item->start_in_dw = -1;
448
449 if (item->link.next != pool->item_list) {
450 pool->status |= POOL_FRAGMENTED;
451 }
452 }
453
454 /**
455 * Moves the item \a item forward from the resource \a src to the
456 * resource \a dst at \a new_start_in_dw
457 *
458 * This function assumes two things:
459 * 1) The item is \b only moved forward, unless src is different from dst
460 * 2) The item \b won't change it's position inside the \a item_list
461 *
462 * \param item The item that will be moved
463 * \param new_start_in_dw The new position of the item in \a item_list
464 * \see compute_memory_defrag
465 */
compute_memory_move_item(struct compute_memory_pool * pool,struct pipe_resource * src,struct pipe_resource * dst,struct compute_memory_item * item,uint64_t new_start_in_dw,struct pipe_context * pipe)466 static void compute_memory_move_item(struct compute_memory_pool *pool,
467 struct pipe_resource *src, struct pipe_resource *dst,
468 struct compute_memory_item *item, uint64_t new_start_in_dw,
469 struct pipe_context *pipe)
470 {
471 struct pipe_screen *screen = (struct pipe_screen *)pool->screen;
472 struct r600_context *rctx = (struct r600_context *)pipe;
473 struct pipe_box box;
474
475 COMPUTE_DBG(pool->screen, "* compute_memory_move_item()\n"
476 " + Moving item %"PRIi64" from %"PRIi64" (%"PRIi64" bytes) to %"PRIu64" (%"PRIu64" bytes)\n",
477 item->id, item->start_in_dw, item->start_in_dw * 4,
478 new_start_in_dw, new_start_in_dw * 4);
479
480 if (pool->item_list != item->link.prev) {
481 ASSERTED struct compute_memory_item *prev;
482 prev = container_of(item->link.prev, struct compute_memory_item, link);
483 assert(prev->start_in_dw + prev->size_in_dw <= new_start_in_dw);
484 }
485
486 u_box_1d(item->start_in_dw * 4, item->size_in_dw * 4, &box);
487
488 /* If the ranges don't overlap, or we are copying from one resource
489 * to another, we can just copy the item directly */
490 if (src != dst || new_start_in_dw + item->size_in_dw <= item->start_in_dw) {
491
492 rctx->b.b.resource_copy_region(pipe,
493 dst, 0, new_start_in_dw * 4, 0, 0,
494 src, 0, &box);
495 } else {
496 /* The ranges overlap, we will try first to use an intermediate
497 * resource to move the item */
498 struct pipe_resource *tmp = (struct pipe_resource *)
499 r600_compute_buffer_alloc_vram(pool->screen, item->size_in_dw * 4);
500
501 if (tmp != NULL) {
502 rctx->b.b.resource_copy_region(pipe,
503 tmp, 0, 0, 0, 0,
504 src, 0, &box);
505
506 box.x = 0;
507
508 rctx->b.b.resource_copy_region(pipe,
509 dst, 0, new_start_in_dw * 4, 0, 0,
510 tmp, 0, &box);
511
512 pool->screen->b.b.resource_destroy(screen, tmp);
513
514 } else {
515 /* The allocation of the temporary resource failed,
516 * falling back to use mappings */
517 uint32_t *map;
518 int64_t offset;
519 struct pipe_transfer *trans;
520
521 offset = item->start_in_dw - new_start_in_dw;
522
523 u_box_1d(new_start_in_dw * 4, (offset + item->size_in_dw) * 4, &box);
524
525 map = pipe->buffer_map(pipe, src, 0, PIPE_MAP_READ_WRITE,
526 &box, &trans);
527
528 assert(map);
529 assert(trans);
530
531 memmove(map, map + offset, item->size_in_dw * 4);
532
533 pipe->buffer_unmap(pipe, trans);
534 }
535 }
536
537 item->start_in_dw = new_start_in_dw;
538 }
539
540 /**
541 * Frees one item for compute_memory_free()
542 */
compute_memory_free_item(struct pipe_screen * screen,struct compute_memory_item * item)543 static void compute_memory_free_item(struct pipe_screen *screen,
544 struct compute_memory_item *item)
545 {
546 struct pipe_resource *res = (struct pipe_resource *)item->real_buffer;
547
548 list_del(&item->link);
549
550 if (res && !is_item_user_ptr(item))
551 screen->resource_destroy(screen, res);
552
553 free(item);
554 }
555
556 /**
557 * Frees the memory associated to the item with id \a id from the pool.
558 * \param id The id of the item to be freed.
559 */
compute_memory_free(struct compute_memory_pool * pool,int64_t id)560 void compute_memory_free(struct compute_memory_pool* pool, int64_t id)
561 {
562 struct compute_memory_item *item, *next;
563 struct pipe_screen *screen = (struct pipe_screen *)pool->screen;
564
565 COMPUTE_DBG(pool->screen, "* compute_memory_free() id + %"PRIi64" \n", id);
566
567 LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->item_list, link) {
568 if (item->id == id) {
569 if (item->link.next != pool->item_list) {
570 pool->status |= POOL_FRAGMENTED;
571 }
572
573 compute_memory_free_item(screen, item);
574 return;
575 }
576 }
577
578 LIST_FOR_EACH_ENTRY_SAFE(item, next, pool->unallocated_list, link) {
579 if (item->id == id) {
580 compute_memory_free_item(screen, item);
581 return;
582 }
583 }
584
585 fprintf(stderr, "Internal error, invalid id %"PRIi64" "
586 "for compute_memory_free\n", id);
587
588 assert(0 && "error");
589 }
590
591 /**
592 * Creates pending allocations for new items, these items are
593 * placed in the unallocated_list.
594 * \param size_in_dw The size, in double words, of the new item.
595 * \return The new item
596 * \see r600_compute_global_buffer_create
597 */
compute_memory_alloc(struct compute_memory_pool * pool,int64_t size_in_dw)598 struct compute_memory_item* compute_memory_alloc(
599 struct compute_memory_pool* pool,
600 int64_t size_in_dw)
601 {
602 struct compute_memory_item *new_item = NULL;
603
604 COMPUTE_DBG(pool->screen, "* compute_memory_alloc() size_in_dw = %"PRIi64" (%"PRIi64" bytes)\n",
605 size_in_dw, 4 * size_in_dw);
606
607 new_item = (struct compute_memory_item *)
608 CALLOC(sizeof(struct compute_memory_item), 1);
609 if (!new_item)
610 return NULL;
611
612 new_item->size_in_dw = size_in_dw;
613 new_item->start_in_dw = -1; /* mark pending */
614 new_item->id = pool->next_id++;
615 new_item->pool = pool;
616 new_item->real_buffer = NULL;
617
618 list_addtail(&new_item->link, pool->unallocated_list);
619
620 COMPUTE_DBG(pool->screen, " + Adding item %p id = %"PRIi64" size = %"PRIi64" (%"PRIi64" bytes)\n",
621 new_item, new_item->id, new_item->size_in_dw,
622 new_item->size_in_dw * 4);
623 return new_item;
624 }
625
626 /**
627 * Transfer data host<->device, offset and size is in bytes.
628 * \param device_to_host 1 for device->host, 0 for host->device.
629 * \see compute_memory_shadow
630 */
compute_memory_transfer(struct compute_memory_pool * pool,struct pipe_context * pipe,int device_to_host,struct compute_memory_item * chunk,void * data,int offset_in_chunk,int size)631 static void compute_memory_transfer(
632 struct compute_memory_pool* pool,
633 struct pipe_context * pipe,
634 int device_to_host,
635 struct compute_memory_item* chunk,
636 void* data,
637 int offset_in_chunk,
638 int size)
639 {
640 int64_t aligned_size = pool->size_in_dw;
641 struct pipe_resource* gart = (struct pipe_resource*)pool->bo;
642 int64_t internal_offset = chunk->start_in_dw*4 + offset_in_chunk;
643
644 struct pipe_transfer *xfer;
645 uint32_t *map;
646
647 assert(gart);
648
649 COMPUTE_DBG(pool->screen, "* compute_memory_transfer() device_to_host = %d, "
650 "offset_in_chunk = %d, size = %d\n", device_to_host,
651 offset_in_chunk, size);
652
653 if (device_to_host) {
654 map = pipe->buffer_map(pipe, gart, 0, PIPE_MAP_READ,
655 &(struct pipe_box) { .width = aligned_size * 4,
656 .height = 1, .depth = 1 }, &xfer);
657 assert(xfer);
658 assert(map);
659 memcpy(data, map + internal_offset, size);
660 pipe->buffer_unmap(pipe, xfer);
661 } else {
662 map = pipe->buffer_map(pipe, gart, 0, PIPE_MAP_WRITE,
663 &(struct pipe_box) { .width = aligned_size * 4,
664 .height = 1, .depth = 1 }, &xfer);
665 assert(xfer);
666 assert(map);
667 memcpy(map + internal_offset, data, size);
668 pipe->buffer_unmap(pipe, xfer);
669 }
670 }
671