1 /*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * based in part on tu driver which is:
5 * Copyright © 2022 Google LLC
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 #include <assert.h>
28 #include <limits.h>
29 #include <stddef.h>
30 #include <stdint.h>
31 #include <stdio.h>
32 #include <vulkan/vulkan.h>
33
34 #if defined(HAVE_VALGRIND)
35 # include <valgrind.h>
36 # include <memcheck.h>
37 #endif
38
39 #include "hwdef/rogue_hw_utils.h"
40 #include "pvr_bo.h"
41 #include "pvr_debug.h"
42 #include "pvr_dump.h"
43 #include "pvr_private.h"
44 #include "pvr_types.h"
45 #include "pvr_util.h"
46 #include "pvr_winsys.h"
47 #include "util/macros.h"
48 #include "util/rb_tree.h"
49 #include "util/simple_mtx.h"
50 #include "util/u_debug.h"
51 #include "vk_alloc.h"
52 #include "vk_log.h"
53
54 struct pvr_bo_store {
55 struct rb_tree tree;
56 simple_mtx_t mutex;
57 uint32_t size;
58 };
59
60 struct pvr_bo_store_entry {
61 struct rb_node node;
62 struct pvr_bo bo;
63 };
64
65 #define entry_from_node(node_) \
66 container_of(node_, struct pvr_bo_store_entry, node)
67 #define entry_from_bo(bo_) container_of(bo_, struct pvr_bo_store_entry, bo)
68
pvr_dev_addr_cmp(const pvr_dev_addr_t a,const pvr_dev_addr_t b)69 static inline int pvr_dev_addr_cmp(const pvr_dev_addr_t a,
70 const pvr_dev_addr_t b)
71 {
72 const uint64_t addr_a = a.addr;
73 const uint64_t addr_b = b.addr;
74
75 if (addr_a < addr_b)
76 return 1;
77 else if (addr_a > addr_b)
78 return -1;
79 else
80 return 0;
81 }
82
83 /* Borrowed from pandecode. Using this comparator allows us to lookup intervals
84 * in the RB-tree without storing extra information.
85 */
pvr_bo_store_entry_cmp_key(const struct rb_node * node,const void * const key)86 static inline int pvr_bo_store_entry_cmp_key(const struct rb_node *node,
87 const void *const key)
88 {
89 const struct pvr_winsys_vma *const vma = entry_from_node(node)->bo.vma;
90 const pvr_dev_addr_t addr = *(const pvr_dev_addr_t *)key;
91
92 if (addr.addr >= vma->dev_addr.addr &&
93 addr.addr < (vma->dev_addr.addr + vma->size)) {
94 return 0;
95 }
96
97 return pvr_dev_addr_cmp(vma->dev_addr, addr);
98 }
99
pvr_bo_store_entry_cmp(const struct rb_node * const a,const struct rb_node * const b)100 static inline int pvr_bo_store_entry_cmp(const struct rb_node *const a,
101 const struct rb_node *const b)
102 {
103 return pvr_dev_addr_cmp(entry_from_node(a)->bo.vma->dev_addr,
104 entry_from_node(b)->bo.vma->dev_addr);
105 }
106
pvr_bo_store_create(struct pvr_device * device)107 VkResult pvr_bo_store_create(struct pvr_device *device)
108 {
109 struct pvr_bo_store *store;
110
111 if (!PVR_IS_DEBUG_SET(TRACK_BOS)) {
112 device->bo_store = NULL;
113 return VK_SUCCESS;
114 }
115
116 store = vk_alloc(&device->vk.alloc,
117 sizeof(*store),
118 8,
119 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
120 if (!store)
121 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
122
123 rb_tree_init(&store->tree);
124 store->size = 0;
125 simple_mtx_init(&store->mutex, mtx_plain);
126
127 device->bo_store = store;
128
129 return VK_SUCCESS;
130 }
131
pvr_bo_store_destroy(struct pvr_device * device)132 void pvr_bo_store_destroy(struct pvr_device *device)
133 {
134 struct pvr_bo_store *store = device->bo_store;
135
136 if (likely(!store))
137 return;
138
139 if (unlikely(!rb_tree_is_empty(&store->tree))) {
140 debug_warning("Non-empty BO store destroyed; dump follows");
141 pvr_bo_store_dump(device);
142 }
143
144 simple_mtx_destroy(&store->mutex);
145
146 vk_free(&device->vk.alloc, store);
147
148 device->bo_store = NULL;
149 }
150
pvr_bo_store_insert(struct pvr_bo_store * const store,struct pvr_bo * const bo)151 static void pvr_bo_store_insert(struct pvr_bo_store *const store,
152 struct pvr_bo *const bo)
153 {
154 if (likely(!store))
155 return;
156
157 simple_mtx_lock(&store->mutex);
158 rb_tree_insert(&store->tree,
159 &entry_from_bo(bo)->node,
160 pvr_bo_store_entry_cmp);
161 store->size++;
162 simple_mtx_unlock(&store->mutex);
163 }
164
pvr_bo_store_remove(struct pvr_bo_store * const store,struct pvr_bo * const bo)165 static void pvr_bo_store_remove(struct pvr_bo_store *const store,
166 struct pvr_bo *const bo)
167 {
168 if (likely(!store))
169 return;
170
171 simple_mtx_lock(&store->mutex);
172 rb_tree_remove(&store->tree, &entry_from_bo(bo)->node);
173 store->size--;
174 simple_mtx_unlock(&store->mutex);
175 }
176
pvr_bo_store_lookup(struct pvr_device * const device,const pvr_dev_addr_t addr)177 struct pvr_bo *pvr_bo_store_lookup(struct pvr_device *const device,
178 const pvr_dev_addr_t addr)
179 {
180 struct pvr_bo_store *const store = device->bo_store;
181 struct rb_node *node;
182
183 if (unlikely(!store))
184 return NULL;
185
186 simple_mtx_lock(&store->mutex);
187 node = rb_tree_search(&store->tree, &addr, pvr_bo_store_entry_cmp_key);
188 simple_mtx_unlock(&store->mutex);
189
190 if (!node)
191 return NULL;
192
193 return &entry_from_node(node)->bo;
194 }
195
pvr_bo_dump_line(struct pvr_dump_ctx * const ctx,const struct pvr_bo * bo,const uint32_t index,const uint32_t nr_bos_log10)196 static void pvr_bo_dump_line(struct pvr_dump_ctx *const ctx,
197 const struct pvr_bo *bo,
198 const uint32_t index,
199 const uint32_t nr_bos_log10)
200 {
201 static const char *const pretty_sizes[64 + 1] = {
202 "", "1 B", "2 B", "4 B", "8 B", "16 B",
203 "32 B", "64 B", "128 B", "256 B", "512 B", "1 KiB",
204 "2 KiB", "4 KiB", "8 KiB", "16 KiB", "32 KiB", "64 KiB",
205 "128 KiB", "256 KiB", "512 KiB", "1 MiB", "2 MiB", "4 MiB",
206 "8 MiB", "16 MiB", "32 MiB", "64 MiB", "128 MiB", "256 MiB",
207 "512 MiB", "1 GiB", "2 GiB", "4 GiB", "8 GiB", "16 GiB",
208 "32 GiB", "64 GiB", "128 GiB", "256 GiB", "512 GiB", "1 TiB",
209 "2 TiB", "4 TiB", "8 TiB", "16 TiB", "32 TiB", "64 TiB",
210 "128 TiB", "256 TiB", "512 TiB", "1 PiB", "2 PiB", "4 PiB",
211 "8 PiB", "16 PiB", "32 PiB", "64 PiB", "128 PiB", "256 PiB",
212 "512 PiB", "1 EiB", "2 EiB", "4 EiB", "8 EiB",
213 };
214
215 const uint64_t size = bo->vma->size;
216 const uint32_t size_log2 =
217 util_is_power_of_two_or_zero64(size) ? util_last_bit(size) : 0;
218
219 pvr_dump_println(ctx,
220 "[%0*" PRIu32 "] " PVR_DEV_ADDR_FMT " -> %*p "
221 "(%s%s0x%" PRIx64 " bytes)",
222 nr_bos_log10,
223 index,
224 bo->vma->dev_addr.addr,
225 (int)sizeof(void *) * 2 + 2, /* nr hex digits + 0x prefix */
226 bo->bo->map,
227 pretty_sizes[size_log2],
228 size_log2 ? ", " : "",
229 size);
230 }
231
pvr_bo_store_dump(struct pvr_device * const device)232 bool pvr_bo_store_dump(struct pvr_device *const device)
233 {
234 struct pvr_bo_store *const store = device->bo_store;
235 const uint32_t nr_bos = store->size;
236 const uint32_t nr_bos_log10 = u32_dec_digits(nr_bos);
237 struct pvr_dump_ctx ctx;
238 uint32_t bo_idx = 0;
239
240 if (unlikely(!store)) {
241 debug_warning("Requested BO store dump, but no BO store is present.");
242 return false;
243 }
244
245 pvr_dump_begin(&ctx, stderr, "BO STORE", 1);
246
247 pvr_dump_println(&ctx, "Dumping %" PRIu32 " BO store entries...", nr_bos);
248
249 pvr_dump_indent(&ctx);
250 rb_tree_foreach_safe (struct pvr_bo_store_entry, entry, &store->tree, node) {
251 pvr_bo_dump_line(&ctx, &entry->bo, bo_idx++, nr_bos_log10);
252 }
253 pvr_dump_dedent(&ctx);
254
255 return pvr_dump_end(&ctx);
256 }
257
pvr_bo_list_dump(struct pvr_dump_ctx * const ctx,const struct list_head * const bo_list,const uint32_t nr_bos)258 void pvr_bo_list_dump(struct pvr_dump_ctx *const ctx,
259 const struct list_head *const bo_list,
260 const uint32_t nr_bos)
261 {
262 const uint32_t real_nr_bos = nr_bos ? nr_bos : list_length(bo_list);
263 const uint32_t nr_bos_log10 = u32_dec_digits(real_nr_bos);
264 uint32_t bo_idx = 0;
265
266 list_for_each_entry (struct pvr_bo, bo, bo_list, link) {
267 pvr_bo_dump_line(ctx, bo, bo_idx++, nr_bos_log10);
268 }
269 }
270
pvr_bo_alloc_to_winsys_flags(uint64_t flags)271 static uint32_t pvr_bo_alloc_to_winsys_flags(uint64_t flags)
272 {
273 uint32_t ws_flags = 0;
274
275 if (flags & (PVR_BO_ALLOC_FLAG_CPU_ACCESS | PVR_BO_ALLOC_FLAG_CPU_MAPPED))
276 ws_flags |= PVR_WINSYS_BO_FLAG_CPU_ACCESS;
277
278 if (flags & PVR_BO_ALLOC_FLAG_GPU_UNCACHED)
279 ws_flags |= PVR_WINSYS_BO_FLAG_GPU_UNCACHED;
280
281 if (flags & PVR_BO_ALLOC_FLAG_PM_FW_PROTECT)
282 ws_flags |= PVR_WINSYS_BO_FLAG_PM_FW_PROTECT;
283
284 return ws_flags;
285 }
286
287 static inline struct pvr_bo *
pvr_bo_alloc_bo(const struct pvr_device * const device)288 pvr_bo_alloc_bo(const struct pvr_device *const device)
289 {
290 size_t size;
291 void *ptr;
292
293 if (unlikely(device->bo_store))
294 size = sizeof(struct pvr_bo_store_entry);
295 else
296 size = sizeof(struct pvr_bo);
297
298 ptr =
299 vk_alloc(&device->vk.alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
300 if (unlikely(!ptr))
301 return NULL;
302
303 if (unlikely(device->bo_store))
304 return &((struct pvr_bo_store_entry *)ptr)->bo;
305 else
306 return (struct pvr_bo *)ptr;
307 }
308
pvr_bo_free_bo(const struct pvr_device * const device,struct pvr_bo * const bo)309 static inline void pvr_bo_free_bo(const struct pvr_device *const device,
310 struct pvr_bo *const bo)
311 {
312 void *ptr;
313
314 if (unlikely(device->bo_store))
315 ptr = entry_from_bo(bo);
316 else
317 ptr = bo;
318
319 vk_free(&device->vk.alloc, ptr);
320 }
321
322 /**
323 * \brief Helper interface to allocate a GPU buffer and map it to both host and
324 * device virtual memory. Host mapping is conditional and is controlled by
325 * flags.
326 *
327 * \param[in] device Logical device pointer.
328 * \param[in] heap Heap to allocate device virtual address from.
329 * \param[in] size Size of buffer to allocate.
330 * \param[in] alignment Required alignment of the allocation. Must be a power
331 * of two.
332 * \param[in] flags Controls allocation, CPU and GPU mapping behavior
333 * using PVR_BO_ALLOC_FLAG_*.
334 * \param[out] pvr_bo_out On success output buffer is returned in this pointer.
335 * \return VK_SUCCESS on success, or error code otherwise.
336 *
337 * \sa #pvr_bo_free()
338 */
pvr_bo_alloc(struct pvr_device * device,struct pvr_winsys_heap * heap,uint64_t size,uint64_t alignment,uint64_t flags,struct pvr_bo ** const pvr_bo_out)339 VkResult pvr_bo_alloc(struct pvr_device *device,
340 struct pvr_winsys_heap *heap,
341 uint64_t size,
342 uint64_t alignment,
343 uint64_t flags,
344 struct pvr_bo **const pvr_bo_out)
345 {
346 struct pvr_bo *pvr_bo;
347 VkResult result;
348
349 pvr_bo = pvr_bo_alloc_bo(device);
350 if (!pvr_bo) {
351 result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
352 goto err_out;
353 }
354
355 pvr_bo->ref_count = 1;
356
357 result = device->ws->ops->buffer_create(device->ws,
358 size,
359 alignment,
360 PVR_WINSYS_BO_TYPE_GPU,
361 pvr_bo_alloc_to_winsys_flags(flags),
362 &pvr_bo->bo);
363 if (result != VK_SUCCESS)
364 goto err_free_bo;
365
366 if (flags & PVR_BO_ALLOC_FLAG_CPU_MAPPED) {
367 result = device->ws->ops->buffer_map(pvr_bo->bo);
368 if (result != VK_SUCCESS)
369 goto err_buffer_destroy;
370
371 VG(VALGRIND_MAKE_MEM_DEFINED(pvr_bo->bo->map, pvr_bo->bo->size));
372 }
373
374 result = device->ws->ops->heap_alloc(heap, size, alignment, &pvr_bo->vma);
375 if (result != VK_SUCCESS)
376 goto err_buffer_unmap;
377
378 result = device->ws->ops->vma_map(pvr_bo->vma, pvr_bo->bo, 0, size, NULL);
379 if (result != VK_SUCCESS)
380 goto err_heap_free;
381
382 pvr_bo_store_insert(device->bo_store, pvr_bo);
383 *pvr_bo_out = pvr_bo;
384
385 return VK_SUCCESS;
386
387 err_heap_free:
388 device->ws->ops->heap_free(pvr_bo->vma);
389
390 err_buffer_unmap:
391 if (flags & PVR_BO_ALLOC_FLAG_CPU_MAPPED)
392 device->ws->ops->buffer_unmap(pvr_bo->bo);
393
394 err_buffer_destroy:
395 device->ws->ops->buffer_destroy(pvr_bo->bo);
396
397 err_free_bo:
398 pvr_bo_free_bo(device, pvr_bo);
399
400 err_out:
401 return result;
402 }
403
404 /**
405 * \brief Interface to map the buffer into host virtual address space.
406 *
407 * Buffer should have been created with the #PVR_BO_ALLOC_FLAG_CPU_ACCESS
408 * flag. It should also not already be mapped or it should have been unmapped
409 * using #pvr_bo_cpu_unmap() before mapping again.
410 *
411 * \param[in] device Logical device pointer.
412 * \param[in] pvr_bo Buffer to map.
413 * \return Valid host virtual address on success, or NULL otherwise.
414 *
415 * \sa #pvr_bo_alloc(), #PVR_BO_ALLOC_FLAG_CPU_MAPPED
416 */
pvr_bo_cpu_map(struct pvr_device * device,struct pvr_bo * pvr_bo)417 VkResult pvr_bo_cpu_map(struct pvr_device *device, struct pvr_bo *pvr_bo)
418 {
419 assert(!pvr_bo->bo->map);
420
421 return device->ws->ops->buffer_map(pvr_bo->bo);
422 }
423
424 /**
425 * \brief Interface to unmap the buffer from host virtual address space.
426 *
427 * Buffer should have a valid mapping, created either using #pvr_bo_cpu_map() or
428 * by passing #PVR_BO_ALLOC_FLAG_CPU_MAPPED flag to #pvr_bo_alloc() at
429 * allocation time.
430 *
431 * Buffer can be remapped using #pvr_bo_cpu_map().
432 *
433 * \param[in] device Logical device pointer.
434 * \param[in] pvr_bo Buffer to unmap.
435 */
pvr_bo_cpu_unmap(struct pvr_device * device,struct pvr_bo * pvr_bo)436 void pvr_bo_cpu_unmap(struct pvr_device *device, struct pvr_bo *pvr_bo)
437 {
438 struct pvr_winsys_bo *bo = pvr_bo->bo;
439
440 assert(bo->map);
441
442 #if defined(HAVE_VALGRIND)
443 if (!bo->vbits)
444 bo->vbits = vk_alloc(&device->vk.alloc,
445 bo->size,
446 8,
447 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
448 if (bo->vbits) {
449 unsigned ret = VALGRIND_GET_VBITS(bo->map, bo->vbits, bo->size);
450 if (ret != 0 && ret != 1)
451 mesa_loge("Failed to get vbits; expect bad valgrind results.");
452 } else {
453 mesa_loge("Failed to alloc vbits storage; expect bad valgrind results.");
454 }
455 #endif /* defined(HAVE_VALGRIND) */
456
457 device->ws->ops->buffer_unmap(bo);
458 }
459
460 /**
461 * \brief Interface to free the buffer object.
462 *
463 * \param[in] device Logical device pointer.
464 * \param[in] pvr_bo Buffer to free.
465 *
466 * \sa #pvr_bo_alloc()
467 */
pvr_bo_free(struct pvr_device * device,struct pvr_bo * pvr_bo)468 void pvr_bo_free(struct pvr_device *device, struct pvr_bo *pvr_bo)
469 {
470 if (!pvr_bo)
471 return;
472
473 if (!p_atomic_dec_zero(&pvr_bo->ref_count))
474 return;
475
476 #if defined(HAVE_VALGRIND)
477 vk_free(&device->vk.alloc, pvr_bo->bo->vbits);
478 #endif /* defined(HAVE_VALGRIND) */
479
480 pvr_bo_store_remove(device->bo_store, pvr_bo);
481
482 device->ws->ops->vma_unmap(pvr_bo->vma);
483 device->ws->ops->heap_free(pvr_bo->vma);
484
485 if (pvr_bo->bo->map)
486 device->ws->ops->buffer_unmap(pvr_bo->bo);
487
488 device->ws->ops->buffer_destroy(pvr_bo->bo);
489
490 pvr_bo_free_bo(device, pvr_bo);
491 }
492
493 /**
494 * \brief Interface to initialize a pvr_suballocator.
495 *
496 * \param[in] allocator Sub-allocator to initialize.
497 * \param[in] heap Heap to sub-allocate device virtual address from.
498 * \param[in] device Logical device pointer.
499 * \param[in] default_size Minimum size used for pvr bo(s).
500 *
501 * \sa #pvr_bo_suballocator_fini()
502 */
pvr_bo_suballocator_init(struct pvr_suballocator * allocator,struct pvr_winsys_heap * heap,struct pvr_device * device,uint32_t default_size)503 void pvr_bo_suballocator_init(struct pvr_suballocator *allocator,
504 struct pvr_winsys_heap *heap,
505 struct pvr_device *device,
506 uint32_t default_size)
507 {
508 *allocator = (struct pvr_suballocator){
509 .device = device,
510 .default_size = default_size,
511 .heap = heap,
512 };
513
514 simple_mtx_init(&allocator->mtx, mtx_plain);
515 }
516
517 /**
518 * \brief Interface to destroy a pvr_suballocator.
519 *
520 * \param[in] allocator Sub-allocator to clean-up.
521 *
522 * \sa #pvr_bo_suballocator_init()
523 */
pvr_bo_suballocator_fini(struct pvr_suballocator * allocator)524 void pvr_bo_suballocator_fini(struct pvr_suballocator *allocator)
525 {
526 pvr_bo_free(allocator->device, allocator->bo);
527 pvr_bo_free(allocator->device, allocator->bo_cached);
528
529 simple_mtx_destroy(&allocator->mtx);
530 }
531
pvr_bo_get_ref(struct pvr_bo * bo)532 static inline struct pvr_bo *pvr_bo_get_ref(struct pvr_bo *bo)
533 {
534 p_atomic_inc(&bo->ref_count);
535
536 return bo;
537 }
538
539 /**
540 * \brief Interface to sub-allocate buffer objects.
541 *
542 * \param[in] allocator Sub-allocator used to make a sub-allocation.
543 * \param[in] size Size of buffer to sub-alllocate.
544 * \param[in] align Required alignment of the allocation. Must be
545 * a power of two.
546 * \param[in] zero_on_alloc Require memory for the sub-allocation to be 0.
547 * \param[out] suballoc_bo_out On success points to the sub-allocated buffer
548 * object.
549 * \return VK_SUCCESS on success, or error code otherwise.
550 *
551 * \sa # pvr_bo_suballoc_free()
552 */
pvr_bo_suballoc(struct pvr_suballocator * allocator,uint32_t size,uint32_t align,bool zero_on_alloc,struct pvr_suballoc_bo ** const suballoc_bo_out)553 VkResult pvr_bo_suballoc(struct pvr_suballocator *allocator,
554 uint32_t size,
555 uint32_t align,
556 bool zero_on_alloc,
557 struct pvr_suballoc_bo **const suballoc_bo_out)
558 {
559 const struct pvr_device_info *dev_info =
560 &allocator->device->pdevice->dev_info;
561 const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
562 struct pvr_suballoc_bo *suballoc_bo;
563 uint32_t alloc_size, aligned_size;
564 VkResult result;
565
566 suballoc_bo = vk_alloc(&allocator->device->vk.alloc,
567 sizeof(*suballoc_bo),
568 8,
569 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
570 if (!suballoc_bo)
571 return vk_error(allocator->device, VK_ERROR_OUT_OF_HOST_MEMORY);
572
573 /* This cache line value is used for all type of allocations (i.e. USC, PDS,
574 * transfer and general), so always align them to at least the size of the
575 * cache line.
576 */
577 align = MAX2(align, cache_line_size);
578 assert(util_is_power_of_two_nonzero(align));
579 aligned_size = ALIGN_POT(size, align);
580
581 simple_mtx_lock(&allocator->mtx);
582
583 if (allocator->bo) {
584 uint32_t aligned_offset = ALIGN_POT(allocator->next_offset, align);
585
586 if (aligned_offset + aligned_size <= allocator->bo->bo->size) {
587 suballoc_bo->allocator = allocator;
588 suballoc_bo->bo = pvr_bo_get_ref(allocator->bo);
589 suballoc_bo->dev_addr =
590 PVR_DEV_ADDR_OFFSET(allocator->bo->vma->dev_addr, aligned_offset);
591 suballoc_bo->offset = aligned_offset;
592 suballoc_bo->size = aligned_size;
593
594 allocator->next_offset = aligned_offset + aligned_size;
595
596 if (zero_on_alloc)
597 memset(pvr_bo_suballoc_get_map_addr(suballoc_bo), 0, aligned_size);
598
599 *suballoc_bo_out = suballoc_bo;
600 simple_mtx_unlock(&allocator->mtx);
601
602 return VK_SUCCESS;
603 } else {
604 pvr_bo_free(allocator->device, allocator->bo);
605 allocator->bo = NULL;
606 }
607 }
608
609 alloc_size = MAX2(aligned_size, ALIGN_POT(allocator->default_size, align));
610
611 if (allocator->bo_cached) {
612 struct pvr_winsys_bo *bo_cached = allocator->bo_cached->bo;
613
614 if (alloc_size <= bo_cached->size)
615 allocator->bo = allocator->bo_cached;
616 else
617 pvr_bo_free(allocator->device, allocator->bo_cached);
618
619 allocator->bo_cached = NULL;
620 }
621
622 if (!allocator->bo) {
623 result = pvr_bo_alloc(allocator->device,
624 allocator->heap,
625 alloc_size,
626 align,
627 PVR_BO_ALLOC_FLAG_CPU_MAPPED,
628 &allocator->bo);
629 if (result != VK_SUCCESS) {
630 vk_free(&allocator->device->vk.alloc, suballoc_bo);
631 simple_mtx_unlock(&allocator->mtx);
632 return result;
633 }
634 }
635
636 suballoc_bo->allocator = allocator;
637 suballoc_bo->bo = pvr_bo_get_ref(allocator->bo);
638 suballoc_bo->dev_addr = allocator->bo->vma->dev_addr;
639 suballoc_bo->offset = 0;
640 suballoc_bo->size = aligned_size;
641
642 allocator->next_offset = aligned_size;
643
644 if (zero_on_alloc)
645 memset(pvr_bo_suballoc_get_map_addr(suballoc_bo), 0, aligned_size);
646
647 *suballoc_bo_out = suballoc_bo;
648 simple_mtx_unlock(&allocator->mtx);
649
650 return VK_SUCCESS;
651 }
652
653 /**
654 * \brief Interface to free a sub-allocated buffer object.
655 *
656 * \param[in] suballoc_bo Sub-allocated buffer object to free.
657 *
658 * \sa #pvr_bo_suballoc()
659 */
pvr_bo_suballoc_free(struct pvr_suballoc_bo * suballoc_bo)660 void pvr_bo_suballoc_free(struct pvr_suballoc_bo *suballoc_bo)
661 {
662 if (!suballoc_bo)
663 return;
664
665 simple_mtx_lock(&suballoc_bo->allocator->mtx);
666
667 if (p_atomic_read(&suballoc_bo->bo->ref_count) == 1 &&
668 !suballoc_bo->allocator->bo_cached) {
669 suballoc_bo->allocator->bo_cached = suballoc_bo->bo;
670 } else {
671 pvr_bo_free(suballoc_bo->allocator->device, suballoc_bo->bo);
672 }
673
674 simple_mtx_unlock(&suballoc_bo->allocator->mtx);
675
676 vk_free(&suballoc_bo->allocator->device->vk.alloc, suballoc_bo);
677 }
678
679 /**
680 * \brief Interface to retrieve sub-allocated memory offset from the host
681 * virtual address space.
682 *
683 * \param[in] suballoc_bo Sub-allocated buffer object pointer.
684 *
685 * \return Valid host virtual address on success.
686 *
687 * \sa #pvr_bo_suballoc()
688 */
pvr_bo_suballoc_get_map_addr(const struct pvr_suballoc_bo * suballoc_bo)689 void *pvr_bo_suballoc_get_map_addr(const struct pvr_suballoc_bo *suballoc_bo)
690 {
691 const struct pvr_bo *pvr_bo = suballoc_bo->bo;
692
693 assert((uint8_t *)pvr_bo->bo->map + suballoc_bo->offset <
694 (uint8_t *)pvr_bo->bo->map + pvr_bo->bo->size);
695
696 return (uint8_t *)pvr_bo->bo->map + suballoc_bo->offset;
697 }
698
699 #if defined(HAVE_VALGRIND)
pvr_bo_cpu_map_unchanged(struct pvr_device * device,struct pvr_bo * pvr_bo)700 VkResult pvr_bo_cpu_map_unchanged(struct pvr_device *device,
701 struct pvr_bo *pvr_bo)
702 {
703 VkResult result = pvr_bo_cpu_map(device, pvr_bo);
704 if (result == VK_SUCCESS) {
705 unsigned ret = VALGRIND_SET_VBITS(pvr_bo->bo->map,
706 pvr_bo->bo->vbits,
707 pvr_bo->bo->size);
708 if (ret != 0 && ret != 1)
709 mesa_loge("Failed to set vbits; expect bad valgrind results.");
710 }
711
712 return result;
713 }
714 #endif /* defined(HAVE_VALGRIND) */
715