1/* 2 * Copyright © 2011 Marek Olšák <maraeo@gmail.com> 3 * Copyright © 2015 Advanced Micro Devices, Inc. 4 * Copyright © 2021 Valve Corporation 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS 19 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 * USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * The above copyright notice and this permission notice (including the 25 * next paragraph) shall be included in all copies or substantial portions 26 * of the Software. 27 * 28 * Authors: 29 * Mike Blumenkrantz <michael.blumenkrantz@gmail.com> 30 */ 31 32#include "zink_context.h" 33#include "zink_bo.h" 34#include "zink_resource.h" 35#include "zink_screen.h" 36#include "util/u_hash_table.h" 37 38#if !defined(__APPLE__) && !defined(_WIN32) 39#define ZINK_USE_DMABUF 40#include <xf86drm.h> 41#endif 42 43struct zink_bo; 44 45struct zink_sparse_backing_chunk { 46 uint32_t begin, end; 47}; 48 49 50/* 51 * Sub-allocation information for a real buffer used as backing memory of a 52 * sparse buffer. 53 */ 54struct zink_sparse_backing { 55 struct list_head list; 56 57 struct zink_bo *bo; 58 59 /* Sorted list of free chunks. */ 60 struct zink_sparse_backing_chunk *chunks; 61 uint32_t max_chunks; 62 uint32_t num_chunks; 63}; 64 65struct zink_sparse_commitment { 66 struct zink_sparse_backing *backing; 67 uint32_t page; 68}; 69 70struct zink_slab { 71 struct pb_slab base; 72 unsigned entry_size; 73 struct zink_bo *buffer; 74 struct zink_bo *entries; 75}; 76 77 78ALWAYS_INLINE static struct zink_slab * 79zink_slab(struct pb_slab *pslab) 80{ 81 return (struct zink_slab*)pslab; 82} 83 84static struct pb_slabs * 85get_slabs(struct zink_screen *screen, uint64_t size, enum zink_alloc_flag flags) 86{ 87 //struct pb_slabs *bo_slabs = ((flags & RADEON_FLAG_ENCRYPTED) && screen->info.has_tmz_support) ? 88 //screen->bo_slabs_encrypted : screen->bo_slabs; 89 90 struct pb_slabs *bo_slabs = screen->pb.bo_slabs; 91 /* Find the correct slab allocator for the given size. */ 92 for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 93 struct pb_slabs *slabs = &bo_slabs[i]; 94 95 if (size <= 1ULL << (slabs->min_order + slabs->num_orders - 1)) 96 return slabs; 97 } 98 99 assert(0); 100 return NULL; 101} 102 103/* Return the power of two size of a slab entry matching the input size. */ 104static unsigned 105get_slab_pot_entry_size(struct zink_screen *screen, unsigned size) 106{ 107 unsigned entry_size = util_next_power_of_two(size); 108 unsigned min_entry_size = 1 << screen->pb.bo_slabs[0].min_order; 109 110 return MAX2(entry_size, min_entry_size); 111} 112 113/* Return the slab entry alignment. */ 114static unsigned get_slab_entry_alignment(struct zink_screen *screen, unsigned size) 115{ 116 unsigned entry_size = get_slab_pot_entry_size(screen, size); 117 118 if (size <= entry_size * 3 / 4) 119 return entry_size / 4; 120 121 return entry_size; 122} 123 124static void 125bo_destroy(struct zink_screen *screen, struct pb_buffer *pbuf) 126{ 127 struct zink_bo *bo = zink_bo(pbuf); 128 129#ifdef ZINK_USE_DMABUF 130 if (bo->mem && !bo->u.real.use_reusable_pool) { 131 simple_mtx_lock(&bo->u.real.export_lock); 132 list_for_each_entry_safe(struct bo_export, export, &bo->u.real.exports, link) { 133 struct drm_gem_close args = { .handle = export->gem_handle }; 134 drmIoctl(export->drm_fd, DRM_IOCTL_GEM_CLOSE, &args); 135 list_del(&export->link); 136 free(export); 137 } 138 simple_mtx_unlock(&bo->u.real.export_lock); 139 simple_mtx_destroy(&bo->u.real.export_lock); 140 } 141#endif 142 143 if (!bo->u.real.is_user_ptr && bo->u.real.cpu_ptr) { 144 bo->u.real.map_count = 1; 145 bo->u.real.cpu_ptr = NULL; 146 zink_bo_unmap(screen, bo); 147 } 148 149 VKSCR(FreeMemory)(screen->dev, bo->mem, NULL); 150 151 simple_mtx_destroy(&bo->lock); 152 FREE(bo); 153} 154 155static bool 156bo_can_reclaim(struct zink_screen *screen, struct pb_buffer *pbuf) 157{ 158 struct zink_bo *bo = zink_bo(pbuf); 159 160 return zink_screen_usage_check_completion(screen, bo->reads) && zink_screen_usage_check_completion(screen, bo->writes); 161} 162 163static bool 164bo_can_reclaim_slab(void *priv, struct pb_slab_entry *entry) 165{ 166 struct zink_bo *bo = container_of(entry, struct zink_bo, u.slab.entry); 167 168 return bo_can_reclaim(priv, &bo->base); 169} 170 171static void 172bo_slab_free(struct zink_screen *screen, struct pb_slab *pslab) 173{ 174 struct zink_slab *slab = zink_slab(pslab); 175 ASSERTED unsigned slab_size = slab->buffer->base.size; 176 177 assert(slab->base.num_entries * slab->entry_size <= slab_size); 178 FREE(slab->entries); 179 zink_bo_unref(screen, slab->buffer); 180 FREE(slab); 181} 182 183static void 184bo_slab_destroy(struct zink_screen *screen, struct pb_buffer *pbuf) 185{ 186 struct zink_bo *bo = zink_bo(pbuf); 187 188 assert(!bo->mem); 189 190 //if (bo->base.usage & RADEON_FLAG_ENCRYPTED) 191 //pb_slab_free(get_slabs(screen, bo->base.size, RADEON_FLAG_ENCRYPTED), &bo->u.slab.entry); 192 //else 193 pb_slab_free(get_slabs(screen, bo->base.size, 0), &bo->u.slab.entry); 194} 195 196static void 197clean_up_buffer_managers(struct zink_screen *screen) 198{ 199 for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 200 pb_slabs_reclaim(&screen->pb.bo_slabs[i]); 201 //if (screen->info.has_tmz_support) 202 //pb_slabs_reclaim(&screen->bo_slabs_encrypted[i]); 203 } 204 205 pb_cache_release_all_buffers(&screen->pb.bo_cache); 206} 207 208static unsigned 209get_optimal_alignment(struct zink_screen *screen, uint64_t size, unsigned alignment) 210{ 211 /* Increase the alignment for faster address translation and better memory 212 * access pattern. 213 */ 214 if (size >= 4096) { 215 alignment = MAX2(alignment, 4096); 216 } else if (size) { 217 unsigned msb = util_last_bit(size); 218 219 alignment = MAX2(alignment, 1u << (msb - 1)); 220 } 221 return alignment; 222} 223 224static void 225bo_destroy_or_cache(struct zink_screen *screen, struct pb_buffer *pbuf) 226{ 227 struct zink_bo *bo = zink_bo(pbuf); 228 229 assert(bo->mem); /* slab buffers have a separate vtbl */ 230 bo->reads = NULL; 231 bo->writes = NULL; 232 233 if (bo->u.real.use_reusable_pool) 234 pb_cache_add_buffer(bo->cache_entry); 235 else 236 bo_destroy(screen, pbuf); 237} 238 239static const struct pb_vtbl bo_vtbl = { 240 /* Cast to void* because one of the function parameters is a struct pointer instead of void*. */ 241 (void*)bo_destroy_or_cache 242 /* other functions are never called */ 243}; 244 245static struct zink_bo * 246bo_create_internal(struct zink_screen *screen, 247 uint64_t size, 248 unsigned alignment, 249 enum zink_heap heap, 250 unsigned flags, 251 const void *pNext) 252{ 253 struct zink_bo *bo = NULL; 254 bool init_pb_cache; 255 256 /* too big for vk alloc */ 257 if (size > UINT32_MAX) 258 return NULL; 259 260 alignment = get_optimal_alignment(screen, size, alignment); 261 262 VkMemoryAllocateInfo mai; 263 mai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 264 mai.pNext = pNext; 265 mai.allocationSize = size; 266 mai.memoryTypeIndex = screen->heap_map[heap]; 267 if (screen->info.mem_props.memoryTypes[mai.memoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { 268 alignment = MAX2(alignment, screen->info.props.limits.minMemoryMapAlignment); 269 mai.allocationSize = align64(mai.allocationSize, screen->info.props.limits.minMemoryMapAlignment); 270 } 271 unsigned heap_idx = screen->info.mem_props.memoryTypes[screen->heap_map[heap]].heapIndex; 272 if (mai.allocationSize > screen->info.mem_props.memoryHeaps[heap_idx].size) { 273 mesa_loge("zink: can't allocate %"PRIu64" bytes from heap that's only %"PRIu64" bytes!\n", mai.allocationSize, screen->info.mem_props.memoryHeaps[heap_idx].size); 274 return NULL; 275 } 276 277 /* all non-suballocated bo can cache */ 278 init_pb_cache = !pNext; 279 280 if (!bo) 281 bo = CALLOC(1, sizeof(struct zink_bo) + init_pb_cache * sizeof(struct pb_cache_entry)); 282 if (!bo) { 283 return NULL; 284 } 285 286 VkResult ret = VKSCR(AllocateMemory)(screen->dev, &mai, NULL, &bo->mem); 287 if (!zink_screen_handle_vkresult(screen, ret)) { 288 mesa_loge("zink: couldn't allocate memory: heap=%u size=%" PRIu64, heap, size); 289 goto fail; 290 } 291 292 if (init_pb_cache) { 293 bo->u.real.use_reusable_pool = true; 294 pb_cache_init_entry(&screen->pb.bo_cache, bo->cache_entry, &bo->base, heap); 295 } else { 296#ifdef ZINK_USE_DMABUF 297 list_inithead(&bo->u.real.exports); 298 simple_mtx_init(&bo->u.real.export_lock, mtx_plain); 299#endif 300 } 301 302 303 simple_mtx_init(&bo->lock, mtx_plain); 304 pipe_reference_init(&bo->base.reference, 1); 305 bo->base.alignment_log2 = util_logbase2(alignment); 306 bo->base.size = mai.allocationSize; 307 bo->base.vtbl = &bo_vtbl; 308 bo->base.placement = screen->heap_flags[heap]; 309 bo->base.usage = flags; 310 bo->unique_id = p_atomic_inc_return(&screen->pb.next_bo_unique_id); 311 312 return bo; 313 314fail: 315 bo_destroy(screen, (void*)bo); 316 return NULL; 317} 318 319/* 320 * Attempt to allocate the given number of backing pages. Fewer pages may be 321 * allocated (depending on the fragmentation of existing backing buffers), 322 * which will be reflected by a change to *pnum_pages. 323 */ 324static struct zink_sparse_backing * 325sparse_backing_alloc(struct zink_screen *screen, struct zink_bo *bo, 326 uint32_t *pstart_page, uint32_t *pnum_pages) 327{ 328 struct zink_sparse_backing *best_backing; 329 unsigned best_idx; 330 uint32_t best_num_pages; 331 332 best_backing = NULL; 333 best_idx = 0; 334 best_num_pages = 0; 335 336 /* This is a very simple and inefficient best-fit algorithm. */ 337 list_for_each_entry(struct zink_sparse_backing, backing, &bo->u.sparse.backing, list) { 338 for (unsigned idx = 0; idx < backing->num_chunks; ++idx) { 339 uint32_t cur_num_pages = backing->chunks[idx].end - backing->chunks[idx].begin; 340 if ((best_num_pages < *pnum_pages && cur_num_pages > best_num_pages) || 341 (best_num_pages > *pnum_pages && cur_num_pages < best_num_pages)) { 342 best_backing = backing; 343 best_idx = idx; 344 best_num_pages = cur_num_pages; 345 } 346 } 347 } 348 349 /* Allocate a new backing buffer if necessary. */ 350 if (!best_backing) { 351 struct pb_buffer *buf; 352 uint64_t size; 353 uint32_t pages; 354 355 best_backing = CALLOC_STRUCT(zink_sparse_backing); 356 if (!best_backing) 357 return NULL; 358 359 best_backing->max_chunks = 4; 360 best_backing->chunks = CALLOC(best_backing->max_chunks, 361 sizeof(*best_backing->chunks)); 362 if (!best_backing->chunks) { 363 FREE(best_backing); 364 return NULL; 365 } 366 367 assert(bo->u.sparse.num_backing_pages < DIV_ROUND_UP(bo->base.size, ZINK_SPARSE_BUFFER_PAGE_SIZE)); 368 369 size = MIN3(bo->base.size / 16, 370 8 * 1024 * 1024, 371 bo->base.size - (uint64_t)bo->u.sparse.num_backing_pages * ZINK_SPARSE_BUFFER_PAGE_SIZE); 372 size = MAX2(size, ZINK_SPARSE_BUFFER_PAGE_SIZE); 373 374 buf = zink_bo_create(screen, size, ZINK_SPARSE_BUFFER_PAGE_SIZE, 375 ZINK_HEAP_DEVICE_LOCAL, 0, NULL); 376 if (!buf) { 377 FREE(best_backing->chunks); 378 FREE(best_backing); 379 return NULL; 380 } 381 382 /* We might have gotten a bigger buffer than requested via caching. */ 383 pages = buf->size / ZINK_SPARSE_BUFFER_PAGE_SIZE; 384 385 best_backing->bo = zink_bo(buf); 386 best_backing->num_chunks = 1; 387 best_backing->chunks[0].begin = 0; 388 best_backing->chunks[0].end = pages; 389 390 list_add(&best_backing->list, &bo->u.sparse.backing); 391 bo->u.sparse.num_backing_pages += pages; 392 393 best_idx = 0; 394 best_num_pages = pages; 395 } 396 397 *pnum_pages = MIN2(*pnum_pages, best_num_pages); 398 *pstart_page = best_backing->chunks[best_idx].begin; 399 best_backing->chunks[best_idx].begin += *pnum_pages; 400 401 if (best_backing->chunks[best_idx].begin >= best_backing->chunks[best_idx].end) { 402 memmove(&best_backing->chunks[best_idx], &best_backing->chunks[best_idx + 1], 403 sizeof(*best_backing->chunks) * (best_backing->num_chunks - best_idx - 1)); 404 best_backing->num_chunks--; 405 } 406 407 return best_backing; 408} 409 410static void 411sparse_free_backing_buffer(struct zink_screen *screen, struct zink_bo *bo, 412 struct zink_sparse_backing *backing) 413{ 414 bo->u.sparse.num_backing_pages -= backing->bo->base.size / ZINK_SPARSE_BUFFER_PAGE_SIZE; 415 416 list_del(&backing->list); 417 zink_bo_unref(screen, backing->bo); 418 FREE(backing->chunks); 419 FREE(backing); 420} 421 422/* 423 * Return a range of pages from the given backing buffer back into the 424 * free structure. 425 */ 426static bool 427sparse_backing_free(struct zink_screen *screen, struct zink_bo *bo, 428 struct zink_sparse_backing *backing, 429 uint32_t start_page, uint32_t num_pages) 430{ 431 uint32_t end_page = start_page + num_pages; 432 unsigned low = 0; 433 unsigned high = backing->num_chunks; 434 435 /* Find the first chunk with begin >= start_page. */ 436 while (low < high) { 437 unsigned mid = low + (high - low) / 2; 438 439 if (backing->chunks[mid].begin >= start_page) 440 high = mid; 441 else 442 low = mid + 1; 443 } 444 445 assert(low >= backing->num_chunks || end_page <= backing->chunks[low].begin); 446 assert(low == 0 || backing->chunks[low - 1].end <= start_page); 447 448 if (low > 0 && backing->chunks[low - 1].end == start_page) { 449 backing->chunks[low - 1].end = end_page; 450 451 if (low < backing->num_chunks && end_page == backing->chunks[low].begin) { 452 backing->chunks[low - 1].end = backing->chunks[low].end; 453 memmove(&backing->chunks[low], &backing->chunks[low + 1], 454 sizeof(*backing->chunks) * (backing->num_chunks - low - 1)); 455 backing->num_chunks--; 456 } 457 } else if (low < backing->num_chunks && end_page == backing->chunks[low].begin) { 458 backing->chunks[low].begin = start_page; 459 } else { 460 if (backing->num_chunks >= backing->max_chunks) { 461 unsigned new_max_chunks = 2 * backing->max_chunks; 462 struct zink_sparse_backing_chunk *new_chunks = 463 REALLOC(backing->chunks, 464 sizeof(*backing->chunks) * backing->max_chunks, 465 sizeof(*backing->chunks) * new_max_chunks); 466 if (!new_chunks) 467 return false; 468 469 backing->max_chunks = new_max_chunks; 470 backing->chunks = new_chunks; 471 } 472 473 memmove(&backing->chunks[low + 1], &backing->chunks[low], 474 sizeof(*backing->chunks) * (backing->num_chunks - low)); 475 backing->chunks[low].begin = start_page; 476 backing->chunks[low].end = end_page; 477 backing->num_chunks++; 478 } 479 480 if (backing->num_chunks == 1 && backing->chunks[0].begin == 0 && 481 backing->chunks[0].end == backing->bo->base.size / ZINK_SPARSE_BUFFER_PAGE_SIZE) 482 sparse_free_backing_buffer(screen, bo, backing); 483 484 return true; 485} 486 487static void 488bo_sparse_destroy(struct zink_screen *screen, struct pb_buffer *pbuf) 489{ 490 struct zink_bo *bo = zink_bo(pbuf); 491 492 assert(!bo->mem && bo->base.usage & ZINK_ALLOC_SPARSE); 493 494 while (!list_is_empty(&bo->u.sparse.backing)) { 495 sparse_free_backing_buffer(screen, bo, 496 container_of(bo->u.sparse.backing.next, 497 struct zink_sparse_backing, list)); 498 } 499 500 FREE(bo->u.sparse.commitments); 501 simple_mtx_destroy(&bo->lock); 502 FREE(bo); 503} 504 505static const struct pb_vtbl bo_sparse_vtbl = { 506 /* Cast to void* because one of the function parameters is a struct pointer instead of void*. */ 507 (void*)bo_sparse_destroy 508 /* other functions are never called */ 509}; 510 511static struct pb_buffer * 512bo_sparse_create(struct zink_screen *screen, uint64_t size) 513{ 514 struct zink_bo *bo; 515 516 /* We use 32-bit page numbers; refuse to attempt allocating sparse buffers 517 * that exceed this limit. This is not really a restriction: we don't have 518 * that much virtual address space anyway. 519 */ 520 if (size > (uint64_t)INT32_MAX * ZINK_SPARSE_BUFFER_PAGE_SIZE) 521 return NULL; 522 523 bo = CALLOC_STRUCT(zink_bo); 524 if (!bo) 525 return NULL; 526 527 simple_mtx_init(&bo->lock, mtx_plain); 528 pipe_reference_init(&bo->base.reference, 1); 529 bo->base.alignment_log2 = util_logbase2(ZINK_SPARSE_BUFFER_PAGE_SIZE); 530 bo->base.size = size; 531 bo->base.vtbl = &bo_sparse_vtbl; 532 bo->base.placement = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 533 bo->unique_id = p_atomic_inc_return(&screen->pb.next_bo_unique_id); 534 bo->base.usage = ZINK_ALLOC_SPARSE; 535 536 bo->u.sparse.num_va_pages = DIV_ROUND_UP(size, ZINK_SPARSE_BUFFER_PAGE_SIZE); 537 bo->u.sparse.commitments = CALLOC(bo->u.sparse.num_va_pages, 538 sizeof(*bo->u.sparse.commitments)); 539 if (!bo->u.sparse.commitments) 540 goto error_alloc_commitments; 541 542 list_inithead(&bo->u.sparse.backing); 543 544 return &bo->base; 545 546error_alloc_commitments: 547 simple_mtx_destroy(&bo->lock); 548 FREE(bo); 549 return NULL; 550} 551 552struct pb_buffer * 553zink_bo_create(struct zink_screen *screen, uint64_t size, unsigned alignment, enum zink_heap heap, enum zink_alloc_flag flags, const void *pNext) 554{ 555 struct zink_bo *bo; 556 /* pull in sparse flag */ 557 flags |= zink_alloc_flags_from_heap(heap); 558 559 //struct pb_slabs *slabs = ((flags & RADEON_FLAG_ENCRYPTED) && screen->info.has_tmz_support) ? 560 //screen->bo_slabs_encrypted : screen->bo_slabs; 561 struct pb_slabs *slabs = screen->pb.bo_slabs; 562 563 struct pb_slabs *last_slab = &slabs[NUM_SLAB_ALLOCATORS - 1]; 564 unsigned max_slab_entry_size = 1 << (last_slab->min_order + last_slab->num_orders - 1); 565 566 /* Sub-allocate small buffers from slabs. */ 567 if (!(flags & (ZINK_ALLOC_NO_SUBALLOC | ZINK_ALLOC_SPARSE)) && 568 size <= max_slab_entry_size) { 569 struct pb_slab_entry *entry; 570 571 if (heap < 0 || heap >= ZINK_HEAP_MAX) 572 goto no_slab; 573 574 unsigned alloc_size = size; 575 576 /* Always use slabs for sizes less than 4 KB because the kernel aligns 577 * everything to 4 KB. 578 */ 579 if (size < alignment && alignment <= 4 * 1024) 580 alloc_size = alignment; 581 582 if (alignment > get_slab_entry_alignment(screen, alloc_size)) { 583 /* 3/4 allocations can return too small alignment. Try again with a power of two 584 * allocation size. 585 */ 586 unsigned pot_size = get_slab_pot_entry_size(screen, alloc_size); 587 588 if (alignment <= pot_size) { 589 /* This size works but wastes some memory to fulfil the alignment. */ 590 alloc_size = pot_size; 591 } else { 592 goto no_slab; /* can't fulfil alignment requirements */ 593 } 594 } 595 596 struct pb_slabs *slabs = get_slabs(screen, alloc_size, flags); 597 bool reclaim_all = false; 598 if (heap == ZINK_HEAP_DEVICE_LOCAL_VISIBLE && !screen->resizable_bar) { 599 unsigned low_bound = 128 * 1024 * 1024; //128MB is a very small BAR 600 if (screen->info.driver_props.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) 601 low_bound *= 2; //nvidia has fat textures or something 602 unsigned heapidx = screen->info.mem_props.memoryTypes[screen->heap_map[heap]].heapIndex; 603 reclaim_all = screen->info.mem_props.memoryHeaps[heapidx].size <= low_bound; 604 } 605 entry = pb_slab_alloc_reclaimed(slabs, alloc_size, heap, reclaim_all); 606 if (!entry) { 607 /* Clean up buffer managers and try again. */ 608 clean_up_buffer_managers(screen); 609 610 entry = pb_slab_alloc_reclaimed(slabs, alloc_size, heap, true); 611 } 612 if (!entry) 613 return NULL; 614 615 bo = container_of(entry, struct zink_bo, u.slab.entry); 616 pipe_reference_init(&bo->base.reference, 1); 617 bo->base.size = size; 618 assert(alignment <= 1 << bo->base.alignment_log2); 619 620 return &bo->base; 621 } 622no_slab: 623 624 if (flags & ZINK_ALLOC_SPARSE) { 625 assert(ZINK_SPARSE_BUFFER_PAGE_SIZE % alignment == 0); 626 627 return bo_sparse_create(screen, size); 628 } 629 630 /* Align size to page size. This is the minimum alignment for normal 631 * BOs. Aligning this here helps the cached bufmgr. Especially small BOs, 632 * like constant/uniform buffers, can benefit from better and more reuse. 633 */ 634 if (heap == ZINK_HEAP_DEVICE_LOCAL_VISIBLE) { 635 size = align64(size, screen->info.props.limits.minMemoryMapAlignment); 636 alignment = align(alignment, screen->info.props.limits.minMemoryMapAlignment); 637 } 638 639 bool use_reusable_pool = !(flags & ZINK_ALLOC_NO_SUBALLOC); 640 641 if (use_reusable_pool) { 642 /* Get a buffer from the cache. */ 643 bo = (struct zink_bo*) 644 pb_cache_reclaim_buffer(&screen->pb.bo_cache, size, alignment, 0, heap); 645 if (bo) 646 return &bo->base; 647 } 648 649 /* Create a new one. */ 650 bo = bo_create_internal(screen, size, alignment, heap, flags, pNext); 651 if (!bo) { 652 /* Clean up buffer managers and try again. */ 653 clean_up_buffer_managers(screen); 654 655 bo = bo_create_internal(screen, size, alignment, heap, flags, pNext); 656 if (!bo) 657 return NULL; 658 } 659 660 return &bo->base; 661} 662 663void * 664zink_bo_map(struct zink_screen *screen, struct zink_bo *bo) 665{ 666 void *cpu = NULL; 667 uint64_t offset = 0; 668 struct zink_bo *real; 669 670 if (bo->mem) { 671 real = bo; 672 } else { 673 real = bo->u.slab.real; 674 offset = bo->offset - real->offset; 675 } 676 677 cpu = p_atomic_read(&real->u.real.cpu_ptr); 678 if (!cpu) { 679 simple_mtx_lock(&real->lock); 680 /* Must re-check due to the possibility of a race. Re-check need not 681 * be atomic thanks to the lock. */ 682 cpu = real->u.real.cpu_ptr; 683 if (!cpu) { 684 VkResult result = VKSCR(MapMemory)(screen->dev, real->mem, 0, real->base.size, 0, &cpu); 685 if (result != VK_SUCCESS) { 686 mesa_loge("ZINK: vkMapMemory failed (%s)", vk_Result_to_str(result)); 687 simple_mtx_unlock(&real->lock); 688 return NULL; 689 } 690 p_atomic_set(&real->u.real.cpu_ptr, cpu); 691 } 692 simple_mtx_unlock(&real->lock); 693 } 694 p_atomic_inc(&real->u.real.map_count); 695 696 return (uint8_t*)cpu + offset; 697} 698 699void 700zink_bo_unmap(struct zink_screen *screen, struct zink_bo *bo) 701{ 702 struct zink_bo *real = bo->mem ? bo : bo->u.slab.real; 703 704 assert(real->u.real.map_count != 0 && "too many unmaps"); 705 706 if (p_atomic_dec_zero(&real->u.real.map_count)) { 707 p_atomic_set(&real->u.real.cpu_ptr, NULL); 708 VKSCR(UnmapMemory)(screen->dev, real->mem); 709 } 710} 711 712static VkSemaphore 713get_semaphore(struct zink_screen *screen) 714{ 715 VkSemaphoreCreateInfo sci = { 716 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 717 NULL, 718 0 719 }; 720 VkSemaphore sem; 721 VkResult ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &sem); 722 return ret == VK_SUCCESS ? sem : VK_NULL_HANDLE; 723} 724 725static VkSemaphore 726buffer_commit_single(struct zink_screen *screen, struct zink_resource *res, struct zink_bo *bo, uint32_t bo_offset, uint32_t offset, uint32_t size, bool commit, VkSemaphore wait) 727{ 728 VkSemaphore sem = get_semaphore(screen); 729 VkBindSparseInfo sparse = {0}; 730 sparse.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; 731 sparse.bufferBindCount = res->obj->storage_buffer ? 2 : 1; 732 sparse.waitSemaphoreCount = !!wait; 733 sparse.pWaitSemaphores = &wait; 734 sparse.signalSemaphoreCount = 1; 735 sparse.pSignalSemaphores = &sem; 736 737 VkSparseBufferMemoryBindInfo sparse_bind[2]; 738 sparse_bind[0].buffer = res->obj->buffer; 739 sparse_bind[1].buffer = res->obj->storage_buffer; 740 sparse_bind[0].bindCount = 1; 741 sparse_bind[1].bindCount = 1; 742 sparse.pBufferBinds = sparse_bind; 743 744 VkSparseMemoryBind mem_bind; 745 mem_bind.resourceOffset = offset; 746 mem_bind.size = MIN2(res->base.b.width0 - offset, size); 747 mem_bind.memory = commit ? (bo->mem ? bo->mem : bo->u.slab.real->mem) : VK_NULL_HANDLE; 748 mem_bind.memoryOffset = bo_offset * ZINK_SPARSE_BUFFER_PAGE_SIZE + (commit ? (bo->mem ? 0 : bo->offset) : 0); 749 mem_bind.flags = 0; 750 sparse_bind[0].pBinds = &mem_bind; 751 sparse_bind[1].pBinds = &mem_bind; 752 753 VkResult ret = VKSCR(QueueBindSparse)(screen->queue_sparse, 1, &sparse, VK_NULL_HANDLE); 754 if (zink_screen_handle_vkresult(screen, ret)) 755 return sem; 756 VKSCR(DestroySemaphore)(screen->dev, sem, NULL); 757 return VK_NULL_HANDLE; 758} 759 760static bool 761buffer_bo_commit(struct zink_screen *screen, struct zink_resource *res, uint32_t offset, uint32_t size, bool commit, VkSemaphore *sem) 762{ 763 bool ok = true; 764 struct zink_bo *bo = res->obj->bo; 765 assert(offset % ZINK_SPARSE_BUFFER_PAGE_SIZE == 0); 766 assert(offset <= bo->base.size); 767 assert(size <= bo->base.size - offset); 768 assert(size % ZINK_SPARSE_BUFFER_PAGE_SIZE == 0 || offset + size == bo->base.size); 769 770 struct zink_sparse_commitment *comm = bo->u.sparse.commitments; 771 772 uint32_t va_page = offset / ZINK_SPARSE_BUFFER_PAGE_SIZE; 773 uint32_t end_va_page = va_page + DIV_ROUND_UP(size, ZINK_SPARSE_BUFFER_PAGE_SIZE); 774 VkSemaphore cur_sem = VK_NULL_HANDLE; 775 if (commit) { 776 while (va_page < end_va_page) { 777 uint32_t span_va_page; 778 779 /* Skip pages that are already committed. */ 780 if (comm[va_page].backing) { 781 va_page++; 782 continue; 783 } 784 785 /* Determine length of uncommitted span. */ 786 span_va_page = va_page; 787 while (va_page < end_va_page && !comm[va_page].backing) 788 va_page++; 789 790 /* Fill the uncommitted span with chunks of backing memory. */ 791 while (span_va_page < va_page) { 792 struct zink_sparse_backing *backing; 793 uint32_t backing_start, backing_size; 794 795 backing_size = va_page - span_va_page; 796 backing = sparse_backing_alloc(screen, bo, &backing_start, &backing_size); 797 if (!backing) { 798 ok = false; 799 goto out; 800 } 801 cur_sem = buffer_commit_single(screen, res, backing->bo, backing_start, 802 (uint64_t)span_va_page * ZINK_SPARSE_BUFFER_PAGE_SIZE, 803 (uint64_t)backing_size * ZINK_SPARSE_BUFFER_PAGE_SIZE, true, cur_sem); 804 if (!cur_sem) { 805 ok = sparse_backing_free(screen, bo, backing, backing_start, backing_size); 806 assert(ok && "sufficient memory should already be allocated"); 807 808 ok = false; 809 goto out; 810 } 811 812 while (backing_size) { 813 comm[span_va_page].backing = backing; 814 comm[span_va_page].page = backing_start; 815 span_va_page++; 816 backing_start++; 817 backing_size--; 818 } 819 } 820 } 821 } else { 822 bool done = false; 823 uint32_t base_page = va_page; 824 while (va_page < end_va_page) { 825 struct zink_sparse_backing *backing; 826 uint32_t backing_start; 827 uint32_t span_pages; 828 829 /* Skip pages that are already uncommitted. */ 830 if (!comm[va_page].backing) { 831 va_page++; 832 continue; 833 } 834 835 if (!done) { 836 cur_sem = buffer_commit_single(screen, res, NULL, 0, 837 (uint64_t)base_page * ZINK_SPARSE_BUFFER_PAGE_SIZE, 838 (uint64_t)(end_va_page - base_page) * ZINK_SPARSE_BUFFER_PAGE_SIZE, false, cur_sem); 839 if (!cur_sem) { 840 ok = false; 841 goto out; 842 } 843 } 844 done = true; 845 846 /* Group contiguous spans of pages. */ 847 backing = comm[va_page].backing; 848 backing_start = comm[va_page].page; 849 comm[va_page].backing = NULL; 850 851 span_pages = 1; 852 va_page++; 853 854 while (va_page < end_va_page && 855 comm[va_page].backing == backing && 856 comm[va_page].page == backing_start + span_pages) { 857 comm[va_page].backing = NULL; 858 va_page++; 859 span_pages++; 860 } 861 862 if (!sparse_backing_free(screen, bo, backing, backing_start, span_pages)) { 863 /* Couldn't allocate tracking data structures, so we have to leak */ 864 fprintf(stderr, "zink: leaking sparse backing memory\n"); 865 ok = false; 866 } 867 } 868 } 869out: 870 *sem = cur_sem; 871 return ok; 872} 873 874static VkSemaphore 875texture_commit_single(struct zink_screen *screen, struct zink_resource *res, VkSparseImageMemoryBind *ibind, unsigned num_binds, bool commit, VkSemaphore wait) 876{ 877 VkSemaphore sem = get_semaphore(screen); 878 VkBindSparseInfo sparse = {0}; 879 sparse.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; 880 sparse.imageBindCount = 1; 881 sparse.waitSemaphoreCount = !!wait; 882 sparse.pWaitSemaphores = &wait; 883 sparse.signalSemaphoreCount = 1; 884 sparse.pSignalSemaphores = &sem; 885 886 VkSparseImageMemoryBindInfo sparse_ibind; 887 sparse_ibind.image = res->obj->image; 888 sparse_ibind.bindCount = num_binds; 889 sparse_ibind.pBinds = ibind; 890 sparse.pImageBinds = &sparse_ibind; 891 892 VkResult ret = VKSCR(QueueBindSparse)(screen->queue_sparse, 1, &sparse, VK_NULL_HANDLE); 893 if (zink_screen_handle_vkresult(screen, ret)) 894 return sem; 895 VKSCR(DestroySemaphore)(screen->dev, sem, NULL); 896 return VK_NULL_HANDLE; 897} 898 899static VkSemaphore 900texture_commit_miptail(struct zink_screen *screen, struct zink_resource *res, struct zink_bo *bo, uint32_t bo_offset, uint32_t offset, bool commit, VkSemaphore wait) 901{ 902 VkSemaphore sem = get_semaphore(screen); 903 VkBindSparseInfo sparse = {0}; 904 sparse.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; 905 sparse.imageOpaqueBindCount = 1; 906 sparse.waitSemaphoreCount = !!wait; 907 sparse.pWaitSemaphores = &wait; 908 sparse.signalSemaphoreCount = 1; 909 sparse.pSignalSemaphores = &sem; 910 911 VkSparseImageOpaqueMemoryBindInfo sparse_bind; 912 sparse_bind.image = res->obj->image; 913 sparse_bind.bindCount = 1; 914 sparse.pImageOpaqueBinds = &sparse_bind; 915 916 VkSparseMemoryBind mem_bind; 917 mem_bind.resourceOffset = offset; 918 mem_bind.size = MIN2(ZINK_SPARSE_BUFFER_PAGE_SIZE, res->sparse.imageMipTailSize - offset); 919 mem_bind.memory = commit ? (bo->mem ? bo->mem : bo->u.slab.real->mem) : VK_NULL_HANDLE; 920 mem_bind.memoryOffset = bo_offset + (commit ? (bo->mem ? 0 : bo->offset) : 0); 921 mem_bind.flags = 0; 922 sparse_bind.pBinds = &mem_bind; 923 924 VkResult ret = VKSCR(QueueBindSparse)(screen->queue_sparse, 1, &sparse, VK_NULL_HANDLE); 925 if (zink_screen_handle_vkresult(screen, ret)) 926 return sem; 927 VKSCR(DestroySemaphore)(screen->dev, sem, NULL); 928 return VK_NULL_HANDLE; 929} 930 931bool 932zink_bo_commit(struct zink_screen *screen, struct zink_resource *res, unsigned level, struct pipe_box *box, bool commit, VkSemaphore *sem) 933{ 934 bool ok = true; 935 struct zink_bo *bo = res->obj->bo; 936 VkSemaphore cur_sem = VK_NULL_HANDLE; 937 938 if (screen->faked_e5sparse && res->base.b.format == PIPE_FORMAT_R9G9B9E5_FLOAT) 939 return true; 940 941 simple_mtx_lock(&screen->queue_lock); 942 simple_mtx_lock(&bo->lock); 943 if (res->base.b.target == PIPE_BUFFER) { 944 ok = buffer_bo_commit(screen, res, box->x, box->width, commit, sem); 945 goto out; 946 } 947 948 int gwidth, gheight, gdepth; 949 gwidth = res->sparse.formatProperties.imageGranularity.width; 950 gheight = res->sparse.formatProperties.imageGranularity.height; 951 gdepth = res->sparse.formatProperties.imageGranularity.depth; 952 assert(gwidth && gheight && gdepth); 953 954 struct zink_sparse_commitment *comm = bo->u.sparse.commitments; 955 VkImageSubresource subresource = { res->aspect, level, 0 }; 956 unsigned nwidth = DIV_ROUND_UP(box->width, gwidth); 957 unsigned nheight = DIV_ROUND_UP(box->height, gheight); 958 unsigned ndepth = DIV_ROUND_UP(box->depth, gdepth); 959 VkExtent3D lastBlockExtent = { 960 (box->width % gwidth) ? box->width % gwidth : gwidth, 961 (box->height % gheight) ? box->height % gheight : gheight, 962 (box->depth % gdepth) ? box->depth % gdepth : gdepth 963 }; 964#define NUM_BATCHED_BINDS 50 965 VkSparseImageMemoryBind ibind[NUM_BATCHED_BINDS]; 966 uint32_t backing_start[NUM_BATCHED_BINDS], backing_size[NUM_BATCHED_BINDS]; 967 struct zink_sparse_backing *backing[NUM_BATCHED_BINDS]; 968 unsigned i = 0; 969 bool commits_pending = false; 970 uint32_t va_page_offset = 0; 971 for (unsigned l = 0; l < level; l++) { 972 unsigned mipwidth = DIV_ROUND_UP(MAX2(res->base.b.width0 >> l, 1), gwidth); 973 unsigned mipheight = DIV_ROUND_UP(MAX2(res->base.b.height0 >> l, 1), gheight); 974 unsigned mipdepth = DIV_ROUND_UP(res->base.b.array_size > 1 ? res->base.b.array_size : MAX2(res->base.b.depth0 >> l, 1), gdepth); 975 va_page_offset += mipwidth * mipheight * mipdepth; 976 } 977 for (unsigned d = 0; d < ndepth; d++) { 978 for (unsigned h = 0; h < nheight; h++) { 979 for (unsigned w = 0; w < nwidth; w++) { 980 ibind[i].subresource = subresource; 981 ibind[i].flags = 0; 982 // Offset 983 ibind[i].offset.x = w * gwidth; 984 ibind[i].offset.y = h * gheight; 985 if (res->base.b.array_size > 1) { 986 ibind[i].subresource.arrayLayer = d * gdepth; 987 ibind[i].offset.z = 0; 988 } else { 989 ibind[i].offset.z = d * gdepth; 990 } 991 // Size of the page 992 ibind[i].extent.width = (w == nwidth - 1) ? lastBlockExtent.width : gwidth; 993 ibind[i].extent.height = (h == nheight - 1) ? lastBlockExtent.height : gheight; 994 ibind[i].extent.depth = (d == ndepth - 1 && res->base.b.target != PIPE_TEXTURE_CUBE) ? lastBlockExtent.depth : gdepth; 995 uint32_t va_page = va_page_offset + 996 (d + (box->z / gdepth)) * ((MAX2(res->base.b.width0 >> level, 1) / gwidth) * (MAX2(res->base.b.height0 >> level, 1) / gheight)) + 997 (h + (box->y / gheight)) * (MAX2(res->base.b.width0 >> level, 1) / gwidth) + 998 (w + (box->x / gwidth)); 999 1000 uint32_t end_va_page = va_page + 1; 1001 1002 if (commit) { 1003 while (va_page < end_va_page) { 1004 uint32_t span_va_page; 1005 1006 /* Skip pages that are already committed. */ 1007 if (comm[va_page].backing) { 1008 va_page++; 1009 continue; 1010 } 1011 1012 /* Determine length of uncommitted span. */ 1013 span_va_page = va_page; 1014 while (va_page < end_va_page && !comm[va_page].backing) 1015 va_page++; 1016 1017 /* Fill the uncommitted span with chunks of backing memory. */ 1018 while (span_va_page < va_page) { 1019 backing_size[i] = va_page - span_va_page; 1020 backing[i] = sparse_backing_alloc(screen, bo, &backing_start[i], &backing_size[i]); 1021 if (!backing[i]) { 1022 ok = false; 1023 goto out; 1024 } 1025 if (level >= res->sparse.imageMipTailFirstLod) { 1026 uint32_t offset = res->sparse.imageMipTailOffset + d * res->sparse.imageMipTailStride; 1027 cur_sem = texture_commit_miptail(screen, res, backing[i]->bo, backing_start[i], offset, commit, cur_sem); 1028 if (!cur_sem) 1029 goto out; 1030 } else { 1031 ibind[i].memory = backing[i]->bo->mem ? backing[i]->bo->mem : backing[i]->bo->u.slab.real->mem; 1032 ibind[i].memoryOffset = backing_start[i] * ZINK_SPARSE_BUFFER_PAGE_SIZE + 1033 (backing[i]->bo->mem ? 0 : backing[i]->bo->offset); 1034 commits_pending = true; 1035 } 1036 1037 while (backing_size[i]) { 1038 comm[span_va_page].backing = backing[i]; 1039 comm[span_va_page].page = backing_start[i]; 1040 span_va_page++; 1041 backing_start[i]++; 1042 backing_size[i]--; 1043 } 1044 i++; 1045 } 1046 } 1047 } else { 1048 ibind[i].memory = VK_NULL_HANDLE; 1049 ibind[i].memoryOffset = 0; 1050 1051 while (va_page < end_va_page) { 1052 /* Skip pages that are already uncommitted. */ 1053 if (!comm[va_page].backing) { 1054 va_page++; 1055 continue; 1056 } 1057 1058 /* Group contiguous spans of pages. */ 1059 backing[i] = comm[va_page].backing; 1060 backing_start[i] = comm[va_page].page; 1061 comm[va_page].backing = NULL; 1062 1063 backing_size[i] = 1; 1064 va_page++; 1065 1066 while (va_page < end_va_page && 1067 comm[va_page].backing == backing[i] && 1068 comm[va_page].page == backing_start[i] + backing_size[i]) { 1069 comm[va_page].backing = NULL; 1070 va_page++; 1071 backing_size[i]++; 1072 } 1073 if (level >= res->sparse.imageMipTailFirstLod) { 1074 uint32_t offset = res->sparse.imageMipTailOffset + d * res->sparse.imageMipTailStride; 1075 cur_sem = texture_commit_miptail(screen, res, NULL, 0, offset, commit, cur_sem); 1076 if (!cur_sem) 1077 goto out; 1078 } else { 1079 commits_pending = true; 1080 } 1081 i++; 1082 } 1083 } 1084 if (i == ARRAY_SIZE(ibind)) { 1085 cur_sem = texture_commit_single(screen, res, ibind, ARRAY_SIZE(ibind), commit, cur_sem); 1086 if (!cur_sem) { 1087 for (unsigned s = 0; s < i; s++) { 1088 ok = sparse_backing_free(screen, backing[s]->bo, backing[s], backing_start[s], backing_size[s]); 1089 if (!ok) { 1090 /* Couldn't allocate tracking data structures, so we have to leak */ 1091 fprintf(stderr, "zink: leaking sparse backing memory\n"); 1092 } 1093 } 1094 ok = false; 1095 goto out; 1096 } 1097 commits_pending = false; 1098 i = 0; 1099 } 1100 } 1101 } 1102 } 1103 if (commits_pending) { 1104 cur_sem = texture_commit_single(screen, res, ibind, i, commit, cur_sem); 1105 if (!cur_sem) { 1106 for (unsigned s = 0; s < i; s++) { 1107 ok = sparse_backing_free(screen, backing[s]->bo, backing[s], backing_start[s], backing_size[s]); 1108 if (!ok) { 1109 /* Couldn't allocate tracking data structures, so we have to leak */ 1110 fprintf(stderr, "zink: leaking sparse backing memory\n"); 1111 } 1112 } 1113 } 1114 ok = false; 1115 } 1116out: 1117 1118 simple_mtx_unlock(&bo->lock); 1119 simple_mtx_unlock(&screen->queue_lock); 1120 *sem = cur_sem; 1121 return ok; 1122} 1123 1124bool 1125zink_bo_get_kms_handle(struct zink_screen *screen, struct zink_bo *bo, int fd, uint32_t *handle) 1126{ 1127#ifdef ZINK_USE_DMABUF 1128 assert(bo->mem && !bo->u.real.use_reusable_pool); 1129 simple_mtx_lock(&bo->u.real.export_lock); 1130 list_for_each_entry(struct bo_export, export, &bo->u.real.exports, link) { 1131 if (export->drm_fd == fd) { 1132 simple_mtx_unlock(&bo->u.real.export_lock); 1133 *handle = export->gem_handle; 1134 return true; 1135 } 1136 } 1137 struct bo_export *export = CALLOC_STRUCT(bo_export); 1138 if (!export) { 1139 simple_mtx_unlock(&bo->u.real.export_lock); 1140 return false; 1141 } 1142 bool success = drmPrimeFDToHandle(screen->drm_fd, fd, handle) == 0; 1143 if (success) { 1144 list_addtail(&export->link, &bo->u.real.exports); 1145 export->gem_handle = *handle; 1146 export->drm_fd = screen->drm_fd; 1147 } else { 1148 mesa_loge("zink: failed drmPrimeFDToHandle %s", strerror(errno)); 1149 FREE(export); 1150 } 1151 simple_mtx_unlock(&bo->u.real.export_lock); 1152 return success; 1153#else 1154 return false; 1155#endif 1156} 1157 1158static const struct pb_vtbl bo_slab_vtbl = { 1159 /* Cast to void* because one of the function parameters is a struct pointer instead of void*. */ 1160 (void*)bo_slab_destroy 1161 /* other functions are never called */ 1162}; 1163 1164static struct pb_slab * 1165bo_slab_alloc(void *priv, unsigned heap, unsigned entry_size, unsigned group_index, bool encrypted) 1166{ 1167 struct zink_screen *screen = priv; 1168 uint32_t base_id; 1169 unsigned slab_size = 0; 1170 struct zink_slab *slab = CALLOC_STRUCT(zink_slab); 1171 1172 if (!slab) 1173 return NULL; 1174 1175 //struct pb_slabs *slabs = ((flags & RADEON_FLAG_ENCRYPTED) && screen->info.has_tmz_support) ? 1176 //screen->bo_slabs_encrypted : screen->bo_slabs; 1177 struct pb_slabs *slabs = screen->pb.bo_slabs; 1178 1179 /* Determine the slab buffer size. */ 1180 for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 1181 unsigned max_entry_size = 1 << (slabs[i].min_order + slabs[i].num_orders - 1); 1182 1183 if (entry_size <= max_entry_size) { 1184 /* The slab size is twice the size of the largest possible entry. */ 1185 slab_size = max_entry_size * 2; 1186 1187 if (!util_is_power_of_two_nonzero(entry_size)) { 1188 assert(util_is_power_of_two_nonzero(entry_size * 4 / 3)); 1189 1190 /* If the entry size is 3/4 of a power of two, we would waste space and not gain 1191 * anything if we allocated only twice the power of two for the backing buffer: 1192 * 2 * 3/4 = 1.5 usable with buffer size 2 1193 * 1194 * Allocating 5 times the entry size leads us to the next power of two and results 1195 * in a much better memory utilization: 1196 * 5 * 3/4 = 3.75 usable with buffer size 4 1197 */ 1198 if (entry_size * 5 > slab_size) 1199 slab_size = util_next_power_of_two(entry_size * 5); 1200 } 1201 1202 break; 1203 } 1204 } 1205 assert(slab_size != 0); 1206 1207 slab->buffer = zink_bo(zink_bo_create(screen, slab_size, slab_size, heap, 0, NULL)); 1208 if (!slab->buffer) 1209 goto fail; 1210 1211 slab_size = slab->buffer->base.size; 1212 1213 slab->base.num_entries = slab_size / entry_size; 1214 slab->base.num_free = slab->base.num_entries; 1215 slab->entry_size = entry_size; 1216 slab->entries = CALLOC(slab->base.num_entries, sizeof(*slab->entries)); 1217 if (!slab->entries) 1218 goto fail_buffer; 1219 1220 list_inithead(&slab->base.free); 1221 1222 base_id = p_atomic_fetch_add(&screen->pb.next_bo_unique_id, slab->base.num_entries); 1223 for (unsigned i = 0; i < slab->base.num_entries; ++i) { 1224 struct zink_bo *bo = &slab->entries[i]; 1225 1226 simple_mtx_init(&bo->lock, mtx_plain); 1227 bo->base.alignment_log2 = util_logbase2(get_slab_entry_alignment(screen, entry_size)); 1228 bo->base.size = entry_size; 1229 bo->base.vtbl = &bo_slab_vtbl; 1230 bo->offset = slab->buffer->offset + i * entry_size; 1231 bo->unique_id = base_id + i; 1232 bo->u.slab.entry.slab = &slab->base; 1233 bo->u.slab.entry.group_index = group_index; 1234 bo->u.slab.entry.entry_size = entry_size; 1235 1236 if (slab->buffer->mem) { 1237 /* The slab is not suballocated. */ 1238 bo->u.slab.real = slab->buffer; 1239 } else { 1240 /* The slab is allocated out of a bigger slab. */ 1241 bo->u.slab.real = slab->buffer->u.slab.real; 1242 assert(bo->u.slab.real->mem); 1243 } 1244 bo->base.placement = bo->u.slab.real->base.placement; 1245 1246 list_addtail(&bo->u.slab.entry.head, &slab->base.free); 1247 } 1248 1249 /* Wasted alignment due to slabs with 3/4 allocations being aligned to a power of two. */ 1250 assert(slab->base.num_entries * entry_size <= slab_size); 1251 1252 return &slab->base; 1253 1254fail_buffer: 1255 zink_bo_unref(screen, slab->buffer); 1256fail: 1257 FREE(slab); 1258 return NULL; 1259} 1260 1261static struct pb_slab * 1262bo_slab_alloc_normal(void *priv, unsigned heap, unsigned entry_size, unsigned group_index) 1263{ 1264 return bo_slab_alloc(priv, heap, entry_size, group_index, false); 1265} 1266 1267bool 1268zink_bo_init(struct zink_screen *screen) 1269{ 1270 uint64_t total_mem = 0; 1271 for (uint32_t i = 0; i < screen->info.mem_props.memoryHeapCount; ++i) 1272 total_mem += screen->info.mem_props.memoryHeaps[i].size; 1273 /* Create managers. */ 1274 pb_cache_init(&screen->pb.bo_cache, ZINK_HEAP_MAX, 1275 500000, 2.0f, 0, 1276 total_mem / 8, screen, 1277 (void*)bo_destroy, (void*)bo_can_reclaim); 1278 1279 unsigned min_slab_order = MIN_SLAB_ORDER; /* 256 bytes */ 1280 unsigned max_slab_order = 20; /* 1 MB (slab size = 2 MB) */ 1281 unsigned num_slab_orders_per_allocator = (max_slab_order - min_slab_order) / 1282 NUM_SLAB_ALLOCATORS; 1283 1284 /* Divide the size order range among slab managers. */ 1285 for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 1286 unsigned min_order = min_slab_order; 1287 unsigned max_order = MIN2(min_order + num_slab_orders_per_allocator, 1288 max_slab_order); 1289 1290 if (!pb_slabs_init(&screen->pb.bo_slabs[i], 1291 min_order, max_order, 1292 ZINK_HEAP_MAX, true, 1293 screen, 1294 bo_can_reclaim_slab, 1295 bo_slab_alloc_normal, 1296 (void*)bo_slab_free)) { 1297 return false; 1298 } 1299 min_slab_order = max_order + 1; 1300 } 1301 screen->pb.min_alloc_size = 1 << screen->pb.bo_slabs[0].min_order; 1302 return true; 1303} 1304 1305void 1306zink_bo_deinit(struct zink_screen *screen) 1307{ 1308 for (unsigned i = 0; i < NUM_SLAB_ALLOCATORS; i++) { 1309 if (screen->pb.bo_slabs[i].groups) 1310 pb_slabs_deinit(&screen->pb.bo_slabs[i]); 1311 } 1312 pb_cache_deinit(&screen->pb.bo_cache); 1313} 1314