1/* 2 * © Copyright 2018 Alyssa Rosenzweig 3 * Copyright (C) 2019 Collabora, Ltd. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 */ 25 26#include "agx_bo.h" 27#include "agx_device.h" 28#include "pool.h" 29 30/* Transient command stream pooling: command stream uploads try to simply copy 31 * into whereever we left off. If there isn't space, we allocate a new entry 32 * into the pool and copy there */ 33 34#define POOL_SLAB_SIZE (256 * 1024) 35 36static struct agx_bo * 37agx_pool_alloc_backing(struct agx_pool *pool, size_t bo_sz) 38{ 39 struct agx_bo *bo = agx_bo_create(pool->dev, bo_sz, 40 pool->create_flags); 41 42 util_dynarray_append(&pool->bos, struct agx_bo *, bo); 43 pool->transient_bo = bo; 44 pool->transient_offset = 0; 45 46 return bo; 47} 48 49void 50agx_pool_init(struct agx_pool *pool, struct agx_device *dev, 51 unsigned create_flags, bool prealloc) 52{ 53 memset(pool, 0, sizeof(*pool)); 54 pool->dev = dev; 55 pool->create_flags = create_flags; 56 util_dynarray_init(&pool->bos, dev->memctx); 57 58 if (prealloc) 59 agx_pool_alloc_backing(pool, POOL_SLAB_SIZE); 60} 61 62void 63agx_pool_cleanup(struct agx_pool *pool) 64{ 65 util_dynarray_foreach(&pool->bos, struct agx_bo *, bo) { 66 agx_bo_unreference(*bo); 67 } 68 69 util_dynarray_fini(&pool->bos); 70} 71 72void 73agx_pool_get_bo_handles(struct agx_pool *pool, uint32_t *handles) 74{ 75 unsigned idx = 0; 76 util_dynarray_foreach(&pool->bos, struct agx_bo *, bo) { 77 handles[idx++] = (*bo)->handle; 78 } 79} 80 81struct agx_ptr 82agx_pool_alloc_aligned(struct agx_pool *pool, size_t sz, unsigned alignment) 83{ 84 alignment = MAX2(alignment, 4096); 85 assert(alignment == util_next_power_of_two(alignment)); 86 87 /* Find or create a suitable BO */ 88 struct agx_bo *bo = pool->transient_bo; 89 unsigned offset = ALIGN_POT(pool->transient_offset, alignment); 90 91 /* If we don't fit, allocate a new backing */ 92 if (unlikely(bo == NULL || (offset + sz) >= POOL_SLAB_SIZE)) { 93 bo = agx_pool_alloc_backing(pool, 94 ALIGN_POT(MAX2(POOL_SLAB_SIZE, sz), 4096)); 95 offset = 0; 96 } 97 98 pool->transient_offset = offset + sz; 99 100 struct agx_ptr ret = { 101 .cpu = bo->ptr.cpu + offset, 102 .gpu = bo->ptr.gpu + offset, 103 }; 104 105 return ret; 106} 107 108uint64_t 109agx_pool_upload(struct agx_pool *pool, const void *data, size_t sz) 110{ 111 return agx_pool_upload_aligned(pool, data, sz, util_next_power_of_two(sz)); 112} 113 114uint64_t 115agx_pool_upload_aligned(struct agx_pool *pool, const void *data, size_t sz, unsigned alignment) 116{ 117 alignment = MAX2(alignment, 4096); 118 struct agx_ptr transfer = agx_pool_alloc_aligned(pool, sz, alignment); 119 memcpy(transfer.cpu, data, sz); 120 return transfer.gpu; 121} 122