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:
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
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.
22 * Adam Rak <adam.rak@streamnovation.com>
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"
37 #include "r600_resource.h"
38 #include "r600_shader.h"
39 #include "r600_pipe.h"
40 #include "r600_formats.h"
41 #include "compute_memory_pool.h"
42 #include "evergreen_compute_internal.h"
47 struct compute_memory_pool
* compute_memory_pool_new(
48 int64_t initial_size_in_dw
,
49 struct r600_screen
* rscreen
)
51 struct compute_memory_pool
* pool
= (struct compute_memory_pool
*)
52 CALLOC(sizeof(struct compute_memory_pool
), 1);
55 pool
->size_in_dw
= initial_size_in_dw
;
56 pool
->screen
= rscreen
;
57 pool
->bo
= (struct r600_resource
*)r600_compute_buffer_alloc_vram(
58 pool
->screen
, pool
->size_in_dw
*4);
59 pool
->shadow
= (uint32_t*)CALLOC(4, pool
->size_in_dw
);
65 * Frees all stuff in the pool and the pool struct itself too
67 void compute_memory_pool_delete(struct compute_memory_pool
* pool
)
70 pool
->screen
->screen
.resource_destroy((struct pipe_screen
*)
71 pool
->screen
, (struct pipe_resource
*)pool
->bo
);
76 * Searches for an empty space in the pool, return with the pointer to the
77 * allocatable space in the pool, returns -1 on failure.
79 int64_t compute_memory_prealloc_chunk(
80 struct compute_memory_pool
* pool
,
83 assert(size_in_dw
<= pool
->size_in_dw
);
85 struct compute_memory_item
*item
;
89 for (item
= pool
->item_list
; item
; item
= item
->next
) {
90 if (item
->start_in_dw
> -1) {
91 if (item
->start_in_dw
-last_end
> size_in_dw
) {
95 last_end
= item
->start_in_dw
+ item
->size_in_dw
;
96 last_end
+= (1024 - last_end
% 1024);
100 if (pool
->size_in_dw
- last_end
< size_in_dw
) {
108 * Search for the chunk where we can link our new chunk after it.
110 struct compute_memory_item
* compute_memory_postalloc_chunk(
111 struct compute_memory_pool
* pool
,
114 struct compute_memory_item
* item
;
116 for (item
= pool
->item_list
; item
; item
= item
->next
) {
118 if (item
->start_in_dw
< start_in_dw
119 && item
->next
->start_in_dw
> start_in_dw
) {
125 assert(item
->start_in_dw
< start_in_dw
);
130 assert(0 && "unreachable");
135 * Reallocates pool, conserves data
137 void compute_memory_grow_pool(struct compute_memory_pool
* pool
,
138 struct pipe_context
* pipe
, int new_size_in_dw
)
140 assert(new_size_in_dw
>= pool
->size_in_dw
);
142 new_size_in_dw
+= 1024 - (new_size_in_dw
% 1024);
144 compute_memory_shadow(pool
, pipe
, 1);
145 pool
->shadow
= (uint32_t*)realloc(pool
->shadow
, new_size_in_dw
*4);
146 pool
->size_in_dw
= new_size_in_dw
;
147 pool
->screen
->screen
.resource_destroy(
148 (struct pipe_screen
*)pool
->screen
,
149 (struct pipe_resource
*)pool
->bo
);
150 pool
->bo
= r600_compute_buffer_alloc_vram(pool
->screen
,
152 compute_memory_shadow(pool
, pipe
, 0);
156 * Copy pool from device to host, or host to device.
158 void compute_memory_shadow(struct compute_memory_pool
* pool
,
159 struct pipe_context
* pipe
, int device_to_host
)
161 struct compute_memory_item chunk
;
164 chunk
.start_in_dw
= 0;
165 chunk
.size_in_dw
= pool
->size_in_dw
;
166 chunk
.prev
= chunk
.next
= NULL
;
167 compute_memory_transfer(pool
, pipe
, device_to_host
, &chunk
,
168 pool
->shadow
, 0, pool
->size_in_dw
*4);
172 * Allocates pending allocations in the pool
174 void compute_memory_finalize_pending(struct compute_memory_pool
* pool
,
175 struct pipe_context
* pipe
)
177 struct compute_memory_item
*pending_list
= NULL
, *end_p
= NULL
;
178 struct compute_memory_item
*item
, *next
;
180 int64_t allocated
= 0;
181 int64_t unallocated
= 0;
183 for (item
= pool
->item_list
; item
; item
= item
->next
) {
184 COMPUTE_DBG("list: %i %p\n", item
->start_in_dw
, item
->next
);
187 for (item
= pool
->item_list
; item
; item
= next
) {
191 if (item
->start_in_dw
== -1) {
200 item
->prev
->next
= next
;
203 pool
->item_list
= next
;
207 next
->prev
= item
->prev
;
214 unallocated
+= item
->size_in_dw
+1024;
217 allocated
+= item
->size_in_dw
;
221 if (pool
->size_in_dw
< allocated
+unallocated
) {
222 compute_memory_grow_pool(pool
, pipe
, allocated
+unallocated
);
225 for (item
= pending_list
; item
; item
= next
) {
230 while ((start_in_dw
=compute_memory_prealloc_chunk(pool
,
231 item
->size_in_dw
)) == -1) {
232 int64_t need
= item
->size_in_dw
+2048 -
233 (pool
->size_in_dw
- allocated
);
235 need
+= 1024 - (need
% 1024);
238 compute_memory_grow_pool(pool
,
240 pool
->size_in_dw
+ need
);
243 need
= pool
->size_in_dw
/ 10;
244 need
+= 1024 - (need
% 1024);
245 compute_memory_grow_pool(pool
,
247 pool
->size_in_dw
+ need
);
251 item
->start_in_dw
= start_in_dw
;
255 if (pool
->item_list
) {
256 struct compute_memory_item
*pos
;
258 pos
= compute_memory_postalloc_chunk(pool
, start_in_dw
);
260 item
->next
= pos
->next
;
264 item
->next
->prev
= item
;
268 pool
->item_list
= item
;
271 allocated
+= item
->size_in_dw
;
276 void compute_memory_free(struct compute_memory_pool
* pool
, int64_t id
)
278 struct compute_memory_item
*item
, *next
;
280 for (item
= pool
->item_list
; item
; item
= next
) {
283 if (item
->id
== id
) {
285 item
->prev
->next
= item
->next
;
288 pool
->item_list
= item
->next
;
292 item
->next
->prev
= item
->prev
;
301 fprintf(stderr
, "Internal error, invalid id %ld "
302 "for compute_memory_free\n", id
);
304 assert(0 && "error");
308 * Creates pending allocations
310 struct compute_memory_item
* compute_memory_alloc(
311 struct compute_memory_pool
* pool
,
314 struct compute_memory_item
*new_item
;
316 COMPUTE_DBG("Alloc: %i\n", size_in_dw
);
318 new_item
= (struct compute_memory_item
*)
319 CALLOC(sizeof(struct compute_memory_item
), 1);
320 new_item
->size_in_dw
= size_in_dw
;
321 new_item
->start_in_dw
= -1; /* mark pending */
322 new_item
->id
= pool
->next_id
++;
323 new_item
->pool
= pool
;
325 struct compute_memory_item
*last_item
;
327 if (pool
->item_list
) {
328 for (last_item
= pool
->item_list
; last_item
->next
;
329 last_item
= last_item
->next
);
331 last_item
->next
= new_item
;
332 new_item
->prev
= last_item
;
335 pool
->item_list
= new_item
;
342 * Transfer data host<->device, offset and size is in bytes
344 void compute_memory_transfer(
345 struct compute_memory_pool
* pool
,
346 struct pipe_context
* pipe
,
348 struct compute_memory_item
* chunk
,
353 int64_t aligned_size
= pool
->size_in_dw
;
354 struct pipe_resource
* gart
= (struct pipe_resource
*)pool
->bo
;
355 int64_t internal_offset
= chunk
->start_in_dw
*4 + offset_in_chunk
;
357 struct pipe_transfer
*xfer
;
362 xfer
= pipe
->get_transfer(pipe
, gart
, 0, PIPE_TRANSFER_READ
,
363 &(struct pipe_box
) { .width
= aligned_size
,
364 .height
= 1, .depth
= 1 });
366 map
= pipe
->transfer_map(pipe
, xfer
);
368 memcpy(data
, map
+ internal_offset
, size
);
369 pipe
->transfer_unmap(pipe
, xfer
);
370 pipe
->transfer_destroy(pipe
, xfer
);
372 xfer
= pipe
->get_transfer(pipe
, gart
, 0, PIPE_TRANSFER_WRITE
,
373 &(struct pipe_box
) { .width
= aligned_size
,
374 .height
= 1, .depth
= 1 });
376 map
= pipe
->transfer_map(pipe
, xfer
);
378 memcpy(map
+ internal_offset
, data
, size
);
379 pipe
->transfer_unmap(pipe
, xfer
);
380 pipe
->transfer_destroy(pipe
, xfer
);
385 * Transfer data between chunk<->data, it is for VRAM<->GART transfers
387 void compute_memory_transfer_direct(
388 struct compute_memory_pool
* pool
,
390 struct compute_memory_item
* chunk
,
391 struct r600_resource
* data
,