1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * © Copyright 2018 Alyssa Rosenzweig 3bf215546Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci * 12bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci * Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22bf215546Sopenharmony_ci * SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci */ 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "pan_device.h" 27bf215546Sopenharmony_ci#include "panvk_mempool.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci/* Knockoff u_upload_mgr. Uploads wherever we left off, allocating new entries 30bf215546Sopenharmony_ci * when needed. 31bf215546Sopenharmony_ci * 32bf215546Sopenharmony_ci * In "owned" mode, a single parent owns the entire pool, and the pool owns all 33bf215546Sopenharmony_ci * created BOs. All BOs are tracked and addable as 34bf215546Sopenharmony_ci * panvk_pool_get_bo_handles. Freeing occurs at the level of an entire pool. 35bf215546Sopenharmony_ci * This is useful for streaming uploads, where the batch owns the pool. 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * In "unowned" mode, the pool is freestanding. It does not track created BOs 38bf215546Sopenharmony_ci * or hold references. Instead, the consumer must manage the created BOs. This 39bf215546Sopenharmony_ci * is more flexible, enabling non-transient CSO state or shader code to be 40bf215546Sopenharmony_ci * packed with conservative lifetime handling. 41bf215546Sopenharmony_ci */ 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_cistatic struct panfrost_bo * 44bf215546Sopenharmony_cipanvk_pool_alloc_backing(struct panvk_pool *pool, size_t bo_sz) 45bf215546Sopenharmony_ci{ 46bf215546Sopenharmony_ci struct panfrost_bo *bo; 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci /* If there's a free BO in our BO pool, let's pick it. */ 49bf215546Sopenharmony_ci if (pool->bo_pool && bo_sz == pool->base.slab_size && 50bf215546Sopenharmony_ci util_dynarray_num_elements(&pool->bo_pool->free_bos, struct panfrost_bo *)) { 51bf215546Sopenharmony_ci bo = util_dynarray_pop(&pool->bo_pool->free_bos, struct panfrost_bo *); 52bf215546Sopenharmony_ci } else { 53bf215546Sopenharmony_ci /* We don't know what the BO will be used for, so let's flag it 54bf215546Sopenharmony_ci * RW and attach it to both the fragment and vertex/tiler jobs. 55bf215546Sopenharmony_ci * TODO: if we want fine grained BO assignment we should pass 56bf215546Sopenharmony_ci * flags to this function and keep the read/write, 57bf215546Sopenharmony_ci * fragment/vertex+tiler pools separate. 58bf215546Sopenharmony_ci */ 59bf215546Sopenharmony_ci bo = panfrost_bo_create(pool->base.dev, bo_sz, 60bf215546Sopenharmony_ci pool->base.create_flags, 61bf215546Sopenharmony_ci pool->base.label); 62bf215546Sopenharmony_ci } 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci if (bo->size == pool->base.slab_size) 65bf215546Sopenharmony_ci util_dynarray_append(&pool->bos, struct panfrost_bo *, bo); 66bf215546Sopenharmony_ci else 67bf215546Sopenharmony_ci util_dynarray_append(&pool->big_bos, struct panfrost_bo *, bo); 68bf215546Sopenharmony_ci pool->transient_bo = bo; 69bf215546Sopenharmony_ci pool->transient_offset = 0; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci return bo; 72bf215546Sopenharmony_ci} 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_cistatic struct panfrost_ptr 75bf215546Sopenharmony_cipanvk_pool_alloc_aligned(struct panvk_pool *pool, size_t sz, unsigned alignment) 76bf215546Sopenharmony_ci{ 77bf215546Sopenharmony_ci assert(alignment == util_next_power_of_two(alignment)); 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci /* Find or create a suitable BO */ 80bf215546Sopenharmony_ci struct panfrost_bo *bo = pool->transient_bo; 81bf215546Sopenharmony_ci unsigned offset = ALIGN_POT(pool->transient_offset, alignment); 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci /* If we don't fit, allocate a new backing */ 84bf215546Sopenharmony_ci if (unlikely(bo == NULL || (offset + sz) >= pool->base.slab_size)) { 85bf215546Sopenharmony_ci bo = panvk_pool_alloc_backing(pool, 86bf215546Sopenharmony_ci ALIGN_POT(MAX2(pool->base.slab_size, sz), 87bf215546Sopenharmony_ci 4096)); 88bf215546Sopenharmony_ci offset = 0; 89bf215546Sopenharmony_ci } 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci pool->transient_offset = offset + sz; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci struct panfrost_ptr ret = { 94bf215546Sopenharmony_ci .cpu = bo->ptr.cpu + offset, 95bf215546Sopenharmony_ci .gpu = bo->ptr.gpu + offset, 96bf215546Sopenharmony_ci }; 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci return ret; 99bf215546Sopenharmony_ci} 100bf215546Sopenharmony_ciPAN_POOL_ALLOCATOR(struct panvk_pool, panvk_pool_alloc_aligned) 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_civoid 103bf215546Sopenharmony_cipanvk_pool_init(struct panvk_pool *pool, 104bf215546Sopenharmony_ci struct panfrost_device *dev, struct panvk_bo_pool *bo_pool, 105bf215546Sopenharmony_ci unsigned create_flags, size_t slab_size, const char *label, 106bf215546Sopenharmony_ci bool prealloc) 107bf215546Sopenharmony_ci{ 108bf215546Sopenharmony_ci memset(pool, 0, sizeof(*pool)); 109bf215546Sopenharmony_ci pan_pool_init(&pool->base, dev, create_flags, slab_size, label); 110bf215546Sopenharmony_ci pool->bo_pool = bo_pool; 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci util_dynarray_init(&pool->bos, NULL); 113bf215546Sopenharmony_ci util_dynarray_init(&pool->big_bos, NULL); 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci if (prealloc) 116bf215546Sopenharmony_ci panvk_pool_alloc_backing(pool, pool->base.slab_size); 117bf215546Sopenharmony_ci} 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_civoid 120bf215546Sopenharmony_cipanvk_pool_reset(struct panvk_pool *pool) 121bf215546Sopenharmony_ci{ 122bf215546Sopenharmony_ci if (pool->bo_pool) { 123bf215546Sopenharmony_ci unsigned num_bos = panvk_pool_num_bos(pool); 124bf215546Sopenharmony_ci void *ptr = util_dynarray_grow(&pool->bo_pool->free_bos, 125bf215546Sopenharmony_ci struct panfrost_bo *, num_bos); 126bf215546Sopenharmony_ci memcpy(ptr, util_dynarray_begin(&pool->bos), 127bf215546Sopenharmony_ci num_bos * sizeof(struct panfrost_bo *)); 128bf215546Sopenharmony_ci } else { 129bf215546Sopenharmony_ci util_dynarray_foreach(&pool->bos, struct panfrost_bo *, bo) 130bf215546Sopenharmony_ci panfrost_bo_unreference(*bo); 131bf215546Sopenharmony_ci } 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci util_dynarray_foreach(&pool->big_bos, struct panfrost_bo *, bo) 134bf215546Sopenharmony_ci panfrost_bo_unreference(*bo); 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci util_dynarray_clear(&pool->bos); 137bf215546Sopenharmony_ci util_dynarray_clear(&pool->big_bos); 138bf215546Sopenharmony_ci pool->transient_bo = NULL; 139bf215546Sopenharmony_ci} 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_civoid 142bf215546Sopenharmony_cipanvk_pool_cleanup(struct panvk_pool *pool) 143bf215546Sopenharmony_ci{ 144bf215546Sopenharmony_ci panvk_pool_reset(pool); 145bf215546Sopenharmony_ci util_dynarray_fini(&pool->bos); 146bf215546Sopenharmony_ci util_dynarray_fini(&pool->big_bos); 147bf215546Sopenharmony_ci} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_civoid 150bf215546Sopenharmony_cipanvk_pool_get_bo_handles(struct panvk_pool *pool, uint32_t *handles) 151bf215546Sopenharmony_ci{ 152bf215546Sopenharmony_ci unsigned idx = 0; 153bf215546Sopenharmony_ci util_dynarray_foreach(&pool->bos, struct panfrost_bo *, bo) { 154bf215546Sopenharmony_ci assert((*bo)->gem_handle > 0); 155bf215546Sopenharmony_ci handles[idx++] = (*bo)->gem_handle; 156bf215546Sopenharmony_ci } 157bf215546Sopenharmony_ci} 158