xref: /aosp_15_r20/external/mesa3d/src/panfrost/vulkan/panvk_mempool.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * © Copyright 2018 Alyssa Rosenzweig
3*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2019 Collabora, Ltd.
4*61046927SAndroid Build Coastguard Worker  *
5*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
6*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
7*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
8*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
10*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
11*61046927SAndroid Build Coastguard Worker  *
12*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
13*61046927SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
14*61046927SAndroid Build Coastguard Worker  * Software.
15*61046927SAndroid Build Coastguard Worker  *
16*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*61046927SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*61046927SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*61046927SAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*61046927SAndroid Build Coastguard Worker  * SOFTWARE.
23*61046927SAndroid Build Coastguard Worker  *
24*61046927SAndroid Build Coastguard Worker  */
25*61046927SAndroid Build Coastguard Worker 
26*61046927SAndroid Build Coastguard Worker #include "panvk_mempool.h"
27*61046927SAndroid Build Coastguard Worker #include "panvk_priv_bo.h"
28*61046927SAndroid Build Coastguard Worker 
29*61046927SAndroid Build Coastguard Worker #include "kmod/pan_kmod.h"
30*61046927SAndroid Build Coastguard Worker 
31*61046927SAndroid Build Coastguard Worker void
panvk_bo_pool_cleanup(struct panvk_bo_pool * bo_pool)32*61046927SAndroid Build Coastguard Worker panvk_bo_pool_cleanup(struct panvk_bo_pool *bo_pool)
33*61046927SAndroid Build Coastguard Worker {
34*61046927SAndroid Build Coastguard Worker    list_for_each_entry_safe(struct panvk_priv_bo, bo, &bo_pool->free_bos,
35*61046927SAndroid Build Coastguard Worker                             node) {
36*61046927SAndroid Build Coastguard Worker       list_del(&bo->node);
37*61046927SAndroid Build Coastguard Worker       panvk_priv_bo_unref(bo);
38*61046927SAndroid Build Coastguard Worker    }
39*61046927SAndroid Build Coastguard Worker }
40*61046927SAndroid Build Coastguard Worker 
41*61046927SAndroid Build Coastguard Worker /* Knockoff u_upload_mgr. Uploads wherever we left off, allocating new entries
42*61046927SAndroid Build Coastguard Worker  * when needed.
43*61046927SAndroid Build Coastguard Worker  *
44*61046927SAndroid Build Coastguard Worker  * In "owned" mode, a single parent owns the entire pool, and the pool owns all
45*61046927SAndroid Build Coastguard Worker  * created BOs. All BOs are tracked and addable as
46*61046927SAndroid Build Coastguard Worker  * panvk_pool_get_bo_handles. Freeing occurs at the level of an entire pool.
47*61046927SAndroid Build Coastguard Worker  * This is useful for streaming uploads, where the batch owns the pool.
48*61046927SAndroid Build Coastguard Worker  *
49*61046927SAndroid Build Coastguard Worker  * In "unowned" mode, the pool is freestanding. It does not track created BOs
50*61046927SAndroid Build Coastguard Worker  * or hold references. Instead, the consumer must manage the created BOs. This
51*61046927SAndroid Build Coastguard Worker  * is more flexible, enabling non-transient CSO state or shader code to be
52*61046927SAndroid Build Coastguard Worker  * packed with conservative lifetime handling.
53*61046927SAndroid Build Coastguard Worker  */
54*61046927SAndroid Build Coastguard Worker 
55*61046927SAndroid Build Coastguard Worker static struct panvk_priv_bo *
panvk_pool_alloc_backing(struct panvk_pool * pool,size_t sz)56*61046927SAndroid Build Coastguard Worker panvk_pool_alloc_backing(struct panvk_pool *pool, size_t sz)
57*61046927SAndroid Build Coastguard Worker {
58*61046927SAndroid Build Coastguard Worker    size_t bo_sz = ALIGN_POT(MAX2(pool->base.slab_size, sz), 4096);
59*61046927SAndroid Build Coastguard Worker    struct panvk_priv_bo *bo;
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker    /* If there's a free BO in our BO pool, let's pick it. */
62*61046927SAndroid Build Coastguard Worker    if (pool->bo_pool && bo_sz == pool->base.slab_size &&
63*61046927SAndroid Build Coastguard Worker        !list_is_empty(&pool->bo_pool->free_bos)) {
64*61046927SAndroid Build Coastguard Worker       bo =
65*61046927SAndroid Build Coastguard Worker          list_first_entry(&pool->bo_pool->free_bos, struct panvk_priv_bo, node);
66*61046927SAndroid Build Coastguard Worker       list_del(&bo->node);
67*61046927SAndroid Build Coastguard Worker    } else {
68*61046927SAndroid Build Coastguard Worker       /* We don't know what the BO will be used for, so let's flag it
69*61046927SAndroid Build Coastguard Worker        * RW and attach it to both the fragment and vertex/tiler jobs.
70*61046927SAndroid Build Coastguard Worker        * TODO: if we want fine grained BO assignment we should pass
71*61046927SAndroid Build Coastguard Worker        * flags to this function and keep the read/write,
72*61046927SAndroid Build Coastguard Worker        * fragment/vertex+tiler pools separate.
73*61046927SAndroid Build Coastguard Worker        */
74*61046927SAndroid Build Coastguard Worker       bo = panvk_priv_bo_create(pool->dev, bo_sz, pool->props.create_flags,
75*61046927SAndroid Build Coastguard Worker                                 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
76*61046927SAndroid Build Coastguard Worker    }
77*61046927SAndroid Build Coastguard Worker 
78*61046927SAndroid Build Coastguard Worker    if (bo == NULL)
79*61046927SAndroid Build Coastguard Worker       return NULL;
80*61046927SAndroid Build Coastguard Worker 
81*61046927SAndroid Build Coastguard Worker    if (pool->props.owns_bos) {
82*61046927SAndroid Build Coastguard Worker       if (pan_kmod_bo_size(bo->bo) == pool->base.slab_size)
83*61046927SAndroid Build Coastguard Worker          list_addtail(&bo->node, &pool->bos);
84*61046927SAndroid Build Coastguard Worker       else
85*61046927SAndroid Build Coastguard Worker          list_addtail(&bo->node, &pool->big_bos);
86*61046927SAndroid Build Coastguard Worker       pool->bo_count++;
87*61046927SAndroid Build Coastguard Worker    }
88*61046927SAndroid Build Coastguard Worker 
89*61046927SAndroid Build Coastguard Worker    size_t new_remaining_size = pan_kmod_bo_size(bo->bo) - sz;
90*61046927SAndroid Build Coastguard Worker    size_t prev_remaining_size =
91*61046927SAndroid Build Coastguard Worker       pool->transient_bo
92*61046927SAndroid Build Coastguard Worker          ? pan_kmod_bo_size(pool->transient_bo->bo) - pool->transient_offset
93*61046927SAndroid Build Coastguard Worker          : 0;
94*61046927SAndroid Build Coastguard Worker 
95*61046927SAndroid Build Coastguard Worker    /* If there's less room in the new BO after the allocation, we stick to the
96*61046927SAndroid Build Coastguard Worker     * previous one. We also don't hold on BOs that are bigger than the pool
97*61046927SAndroid Build Coastguard Worker     * allocation granularity, to avoid memory fragmentation (retaining a big
98*61046927SAndroid Build Coastguard Worker     * BO which has just one tiny allocation active is not great). */
99*61046927SAndroid Build Coastguard Worker    if (prev_remaining_size < new_remaining_size &&
100*61046927SAndroid Build Coastguard Worker        (pool->props.owns_bos || bo_sz <= pool->base.slab_size)) {
101*61046927SAndroid Build Coastguard Worker       if (!pool->props.owns_bos)
102*61046927SAndroid Build Coastguard Worker          panvk_priv_bo_unref(pool->transient_bo);
103*61046927SAndroid Build Coastguard Worker 
104*61046927SAndroid Build Coastguard Worker       pool->transient_bo = bo;
105*61046927SAndroid Build Coastguard Worker       pool->transient_offset = 0;
106*61046927SAndroid Build Coastguard Worker    }
107*61046927SAndroid Build Coastguard Worker 
108*61046927SAndroid Build Coastguard Worker    return bo;
109*61046927SAndroid Build Coastguard Worker }
110*61046927SAndroid Build Coastguard Worker 
111*61046927SAndroid Build Coastguard Worker struct panvk_priv_mem
panvk_pool_alloc_mem(struct panvk_pool * pool,struct panvk_pool_alloc_info info)112*61046927SAndroid Build Coastguard Worker panvk_pool_alloc_mem(struct panvk_pool *pool, struct panvk_pool_alloc_info info)
113*61046927SAndroid Build Coastguard Worker {
114*61046927SAndroid Build Coastguard Worker    assert(info.alignment == util_next_power_of_two(info.alignment));
115*61046927SAndroid Build Coastguard Worker 
116*61046927SAndroid Build Coastguard Worker    if (pool->props.needs_locking)
117*61046927SAndroid Build Coastguard Worker       simple_mtx_lock(&pool->lock);
118*61046927SAndroid Build Coastguard Worker 
119*61046927SAndroid Build Coastguard Worker    /* Find or create a suitable BO */
120*61046927SAndroid Build Coastguard Worker    struct panvk_priv_bo *bo = pool->transient_bo;
121*61046927SAndroid Build Coastguard Worker    unsigned offset = ALIGN_POT(pool->transient_offset, info.alignment);
122*61046927SAndroid Build Coastguard Worker 
123*61046927SAndroid Build Coastguard Worker    /* If we don't fit, allocate a new backing */
124*61046927SAndroid Build Coastguard Worker    if (unlikely(bo == NULL || (offset + info.size) >= pool->base.slab_size)) {
125*61046927SAndroid Build Coastguard Worker       bo = panvk_pool_alloc_backing(pool, info.size);
126*61046927SAndroid Build Coastguard Worker       offset = 0;
127*61046927SAndroid Build Coastguard Worker    }
128*61046927SAndroid Build Coastguard Worker 
129*61046927SAndroid Build Coastguard Worker    if (bo != NULL && pool->transient_bo == bo) {
130*61046927SAndroid Build Coastguard Worker       pool->transient_offset = offset + info.size;
131*61046927SAndroid Build Coastguard Worker       if (!pool->props.owns_bos)
132*61046927SAndroid Build Coastguard Worker          panvk_priv_bo_ref(bo);
133*61046927SAndroid Build Coastguard Worker    }
134*61046927SAndroid Build Coastguard Worker 
135*61046927SAndroid Build Coastguard Worker    struct panvk_priv_mem ret = {
136*61046927SAndroid Build Coastguard Worker       .bo = bo,
137*61046927SAndroid Build Coastguard Worker       .offset = offset,
138*61046927SAndroid Build Coastguard Worker    };
139*61046927SAndroid Build Coastguard Worker 
140*61046927SAndroid Build Coastguard Worker    if (pool->props.needs_locking)
141*61046927SAndroid Build Coastguard Worker       simple_mtx_unlock(&pool->lock);
142*61046927SAndroid Build Coastguard Worker 
143*61046927SAndroid Build Coastguard Worker    return ret;
144*61046927SAndroid Build Coastguard Worker }
145*61046927SAndroid Build Coastguard Worker 
146*61046927SAndroid Build Coastguard Worker static struct panfrost_ptr
panvk_pool_alloc_aligned(struct panvk_pool * pool,size_t sz,unsigned alignment)147*61046927SAndroid Build Coastguard Worker panvk_pool_alloc_aligned(struct panvk_pool *pool, size_t sz, unsigned alignment)
148*61046927SAndroid Build Coastguard Worker {
149*61046927SAndroid Build Coastguard Worker    /* We just return the host/dev address, so callers can't
150*61046927SAndroid Build Coastguard Worker     * release the BO ref they acquired. */
151*61046927SAndroid Build Coastguard Worker    assert(pool->props.owns_bos);
152*61046927SAndroid Build Coastguard Worker 
153*61046927SAndroid Build Coastguard Worker    struct panvk_pool_alloc_info info = {
154*61046927SAndroid Build Coastguard Worker       .size = sz,
155*61046927SAndroid Build Coastguard Worker       .alignment = alignment,
156*61046927SAndroid Build Coastguard Worker    };
157*61046927SAndroid Build Coastguard Worker    struct panvk_priv_mem mem = panvk_pool_alloc_mem(pool, info);
158*61046927SAndroid Build Coastguard Worker 
159*61046927SAndroid Build Coastguard Worker    return (struct panfrost_ptr){
160*61046927SAndroid Build Coastguard Worker       .cpu = panvk_priv_mem_host_addr(mem),
161*61046927SAndroid Build Coastguard Worker       .gpu = panvk_priv_mem_dev_addr(mem),
162*61046927SAndroid Build Coastguard Worker    };
163*61046927SAndroid Build Coastguard Worker }
PAN_POOL_ALLOCATOR(struct panvk_pool,panvk_pool_alloc_aligned)164*61046927SAndroid Build Coastguard Worker PAN_POOL_ALLOCATOR(struct panvk_pool, panvk_pool_alloc_aligned)
165*61046927SAndroid Build Coastguard Worker 
166*61046927SAndroid Build Coastguard Worker void
167*61046927SAndroid Build Coastguard Worker panvk_pool_init(struct panvk_pool *pool, struct panvk_device *dev,
168*61046927SAndroid Build Coastguard Worker                 struct panvk_bo_pool *bo_pool,
169*61046927SAndroid Build Coastguard Worker                 const struct panvk_pool_properties *props)
170*61046927SAndroid Build Coastguard Worker {
171*61046927SAndroid Build Coastguard Worker    memset(pool, 0, sizeof(*pool));
172*61046927SAndroid Build Coastguard Worker    pool->props = *props;
173*61046927SAndroid Build Coastguard Worker    simple_mtx_init(&pool->lock, mtx_plain);
174*61046927SAndroid Build Coastguard Worker    pan_pool_init(&pool->base, pool->props.slab_size);
175*61046927SAndroid Build Coastguard Worker    pool->dev = dev;
176*61046927SAndroid Build Coastguard Worker    pool->bo_pool = bo_pool;
177*61046927SAndroid Build Coastguard Worker 
178*61046927SAndroid Build Coastguard Worker    list_inithead(&pool->bos);
179*61046927SAndroid Build Coastguard Worker    list_inithead(&pool->big_bos);
180*61046927SAndroid Build Coastguard Worker 
181*61046927SAndroid Build Coastguard Worker    if (props->prealloc)
182*61046927SAndroid Build Coastguard Worker       panvk_pool_alloc_backing(pool, pool->base.slab_size);
183*61046927SAndroid Build Coastguard Worker }
184*61046927SAndroid Build Coastguard Worker 
185*61046927SAndroid Build Coastguard Worker void
panvk_pool_reset(struct panvk_pool * pool)186*61046927SAndroid Build Coastguard Worker panvk_pool_reset(struct panvk_pool *pool)
187*61046927SAndroid Build Coastguard Worker {
188*61046927SAndroid Build Coastguard Worker    if (pool->bo_pool) {
189*61046927SAndroid Build Coastguard Worker       list_splicetail(&pool->bos, &pool->bo_pool->free_bos);
190*61046927SAndroid Build Coastguard Worker       list_inithead(&pool->bos);
191*61046927SAndroid Build Coastguard Worker    } else {
192*61046927SAndroid Build Coastguard Worker       list_for_each_entry_safe(struct panvk_priv_bo, bo, &pool->bos, node) {
193*61046927SAndroid Build Coastguard Worker          list_del(&bo->node);
194*61046927SAndroid Build Coastguard Worker          panvk_priv_bo_unref(bo);
195*61046927SAndroid Build Coastguard Worker       }
196*61046927SAndroid Build Coastguard Worker    }
197*61046927SAndroid Build Coastguard Worker 
198*61046927SAndroid Build Coastguard Worker    list_for_each_entry_safe(struct panvk_priv_bo, bo, &pool->big_bos, node) {
199*61046927SAndroid Build Coastguard Worker       list_del(&bo->node);
200*61046927SAndroid Build Coastguard Worker       panvk_priv_bo_unref(bo);
201*61046927SAndroid Build Coastguard Worker    }
202*61046927SAndroid Build Coastguard Worker 
203*61046927SAndroid Build Coastguard Worker    if (!pool->props.owns_bos)
204*61046927SAndroid Build Coastguard Worker       panvk_priv_bo_unref(pool->transient_bo);
205*61046927SAndroid Build Coastguard Worker 
206*61046927SAndroid Build Coastguard Worker    pool->bo_count = 0;
207*61046927SAndroid Build Coastguard Worker    pool->transient_bo = NULL;
208*61046927SAndroid Build Coastguard Worker }
209*61046927SAndroid Build Coastguard Worker 
210*61046927SAndroid Build Coastguard Worker void
panvk_pool_cleanup(struct panvk_pool * pool)211*61046927SAndroid Build Coastguard Worker panvk_pool_cleanup(struct panvk_pool *pool)
212*61046927SAndroid Build Coastguard Worker {
213*61046927SAndroid Build Coastguard Worker    panvk_pool_reset(pool);
214*61046927SAndroid Build Coastguard Worker }
215*61046927SAndroid Build Coastguard Worker 
216*61046927SAndroid Build Coastguard Worker void
panvk_pool_get_bo_handles(struct panvk_pool * pool,uint32_t * handles)217*61046927SAndroid Build Coastguard Worker panvk_pool_get_bo_handles(struct panvk_pool *pool, uint32_t *handles)
218*61046927SAndroid Build Coastguard Worker {
219*61046927SAndroid Build Coastguard Worker    unsigned idx = 0;
220*61046927SAndroid Build Coastguard Worker 
221*61046927SAndroid Build Coastguard Worker    list_for_each_entry(struct panvk_priv_bo, bo, &pool->bos, node)
222*61046927SAndroid Build Coastguard Worker       handles[idx++] = pan_kmod_bo_handle(bo->bo);
223*61046927SAndroid Build Coastguard Worker 
224*61046927SAndroid Build Coastguard Worker    list_for_each_entry(struct panvk_priv_bo, bo, &pool->big_bos, node)
225*61046927SAndroid Build Coastguard Worker       handles[idx++] = pan_kmod_bo_handle(bo->bo);
226*61046927SAndroid Build Coastguard Worker }
227