diff --git a/src/asahi/lib/meson.build b/src/asahi/lib/meson.build index b6e4d5688eb..15b151dcbe6 100644 --- a/src/asahi/lib/meson.build +++ b/src/asahi/lib/meson.build @@ -23,6 +23,7 @@ dep_iokit = dependency('IOKit', required : false) libasahi_lib_files = files( 'agx_device.c', + 'pool.c', 'tiling.c', ) diff --git a/src/asahi/lib/pool.c b/src/asahi/lib/pool.c new file mode 100644 index 00000000000..00ca9e78431 --- /dev/null +++ b/src/asahi/lib/pool.c @@ -0,0 +1,122 @@ +/* + * © Copyright 2018 Alyssa Rosenzweig + * Copyright (C) 2019 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "agx_bo.h" +#include "agx_device.h" +#include "pool.h" + +/* Transient command stream pooling: command stream uploads try to simply copy + * into whereever we left off. If there isn't space, we allocate a new entry + * into the pool and copy there */ + +#define POOL_SLAB_SIZE (256 * 1024) + +static struct agx_bo * +agx_pool_alloc_backing(struct agx_pool *pool, size_t bo_sz) +{ + struct agx_bo *bo = agx_bo_create(pool->dev, bo_sz, + pool->create_flags); + + util_dynarray_append(&pool->bos, struct agx_bo *, bo); + pool->transient_bo = bo; + pool->transient_offset = 0; + + return bo; +} + +void +agx_pool_init(struct agx_pool *pool, struct agx_device *dev, + unsigned create_flags, bool prealloc) +{ + memset(pool, 0, sizeof(*pool)); + pool->dev = dev; + pool->create_flags = create_flags; + util_dynarray_init(&pool->bos, dev->memctx); + + if (prealloc) + agx_pool_alloc_backing(pool, POOL_SLAB_SIZE); +} + +void +agx_pool_cleanup(struct agx_pool *pool) +{ + util_dynarray_foreach(&pool->bos, struct agx_bo *, bo) { + agx_bo_unreference(*bo); + } + + util_dynarray_fini(&pool->bos); +} + +void +agx_pool_get_bo_handles(struct agx_pool *pool, uint32_t *handles) +{ + unsigned idx = 0; + util_dynarray_foreach(&pool->bos, struct agx_bo *, bo) { + handles[idx++] = (*bo)->handle; + (*bo)->access = AGX_BO_ACCESS_RW; + } +} + +struct agx_ptr +agx_pool_alloc_aligned(struct agx_pool *pool, size_t sz, unsigned alignment) +{ + alignment = MAX2(alignment, 4096); + assert(alignment == util_next_power_of_two(alignment)); + + /* Find or create a suitable BO */ + struct agx_bo *bo = pool->transient_bo; + unsigned offset = ALIGN_POT(pool->transient_offset, alignment); + + /* If we don't fit, allocate a new backing */ + if (unlikely(bo == NULL || (offset + sz) >= POOL_SLAB_SIZE)) { + bo = agx_pool_alloc_backing(pool, + ALIGN_POT(MAX2(POOL_SLAB_SIZE, sz), 4096)); + offset = 0; + } + + pool->transient_offset = offset + sz; + + struct agx_ptr ret = { + .cpu = bo->ptr.cpu + offset, + .gpu = bo->ptr.gpu + offset, + }; + + return ret; +} + +uint64_t +agx_pool_upload(struct agx_pool *pool, const void *data, size_t sz) +{ + return agx_pool_upload_aligned(pool, data, sz, util_next_power_of_two(sz)); +} + +uint64_t +agx_pool_upload_aligned(struct agx_pool *pool, const void *data, size_t sz, unsigned alignment) +{ + alignment = MAX2(alignment, 4096); + struct agx_ptr transfer = agx_pool_alloc_aligned(pool, sz, alignment); + memcpy(transfer.cpu, data, sz); + return transfer.gpu; +} diff --git a/src/asahi/lib/pool.h b/src/asahi/lib/pool.h new file mode 100644 index 00000000000..7d0e2ac4a45 --- /dev/null +++ b/src/asahi/lib/pool.h @@ -0,0 +1,129 @@ +/* + * © Copyright 2017-2018 Alyssa Rosenzweig + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __AGX_POOL_H__ +#define __AGX_POOL_H__ + +#include +#include "asahi/lib/agx_pack.h" +#include "agx_bo.h" + +#include "util/u_dynarray.h" + +/* Represents a pool of memory that can only grow, used to allocate objects + * with the same lifetime as the pool itself. In OpenGL, a pool is owned by the + * batch for transient structures. In Vulkan, it may be owned by e.g. the + * command pool */ + +struct agx_pool { + /* Parent device for allocation */ + struct agx_device *dev; + + /* BOs allocated by this pool */ + struct util_dynarray bos; + + /* Current transient BO */ + struct agx_bo *transient_bo; + + /* Within the topmost transient BO, how much has been used? */ + unsigned transient_offset; + + /* BO flags to use in the pool */ + unsigned create_flags; +}; + +void +agx_pool_init(struct agx_pool *pool, struct agx_device *dev, + unsigned create_flags, bool prealloc); + +void +agx_pool_cleanup(struct agx_pool *pool); + +static inline unsigned +agx_pool_num_bos(struct agx_pool *pool) +{ + return util_dynarray_num_elements(&pool->bos, struct agx_bo *); +} + +void +agx_pool_get_bo_handles(struct agx_pool *pool, uint32_t *handles); + +/* Represents a fat pointer for GPU-mapped memory, returned from the transient + * allocator and not used for much else */ + +struct agx_ptr +agx_pool_alloc_aligned(struct agx_pool *pool, size_t sz, unsigned alignment); + +uint64_t +agx_pool_upload(struct agx_pool *pool, const void *data, size_t sz); + +uint64_t +agx_pool_upload_aligned(struct agx_pool *pool, const void *data, size_t sz, unsigned alignment); + +struct agx_desc_alloc_info { + unsigned size; + unsigned align; + unsigned nelems; +}; + +#define AGX_DESC_ARRAY(count, name) \ + { \ + .size = MALI_ ## name ## _LENGTH, \ + .align = MALI_ ## name ## _ALIGN, \ + .nelems = count, \ + } + +#define AGX_DESC(name) AGX_DESC_ARRAY(1, name) + +#define AGX_DESC_AGGREGATE(...) \ + (struct agx_desc_alloc_info[]) { \ + __VA_ARGS__, \ + { 0 }, \ + } + +static inline struct agx_ptr +agx_pool_alloc_descs(struct agx_pool *pool, + const struct agx_desc_alloc_info *descs) +{ + unsigned size = 0; + unsigned align = descs[0].align; + + for (unsigned i = 0; descs[i].size; i++) { + assert(!(size & (descs[i].align - 1))); + size += descs[i].size * descs[i].nelems; + } + + return agx_pool_alloc_aligned(pool, size, align); +} + +#define agx_pool_alloc_desc(pool, name) \ + agx_pool_alloc_descs(pool, AGX_DESC_AGGREGATE(AGX_DESC(name))) + +#define agx_pool_alloc_desc_array(pool, count, name) \ + agx_pool_alloc_descs(pool, AGX_DESC_AGGREGATE(AGX_DESC_ARRAY(count, name))) + +#define agx_pool_alloc_desc_aggregate(pool, ...) \ + agx_pool_alloc_descs(pool, AGX_DESC_AGGREGATE(__VA_ARGS__)) + +#endif