2 * © Copyright 2018 Alyssa Rosenzweig
3 * Copyright (C) 2019 Collabora, Ltd.
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:
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
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
30 #include <panfrost-misc.h>
31 #include <panfrost-job.h>
32 #include "pan_context.h"
34 /* TODO: What does this actually have to be? */
37 /* Allocate a new transient slab */
39 static struct panfrost_bo
*
40 panfrost_create_slab(struct panfrost_screen
*screen
, unsigned *index
)
42 /* Allocate a new slab on the screen */
44 struct panfrost_bo
**new =
45 util_dynarray_grow(&screen
->transient_bo
,
46 struct panfrost_bo
*, 1);
48 struct panfrost_bo
*alloc
= panfrost_drm_create_bo(screen
, TRANSIENT_SLAB_SIZE
, 0);
52 /* Return the BO as well as the index we just added */
54 *index
= util_dynarray_num_elements(&screen
->transient_bo
, void *) - 1;
58 /* Transient command stream pooling: command stream uploads try to simply copy
59 * into whereever we left off. If there isn't space, we allocate a new entry
60 * into the pool and copy there */
62 struct panfrost_transfer
63 panfrost_allocate_transient(struct panfrost_context
*ctx
, size_t sz
)
65 struct panfrost_screen
*screen
= pan_screen(ctx
->base
.screen
);
66 struct panfrost_job
*batch
= panfrost_get_job_for_fbo(ctx
);
69 sz
= ALIGN_POT(sz
, ALIGNMENT
);
71 /* Find or create a suitable BO */
72 struct panfrost_bo
*bo
= NULL
;
75 bool update_offset
= false;
77 pthread_mutex_lock(&screen
->transient_lock
);
78 bool has_current
= batch
->transient_indices
.size
;
79 bool fits_in_current
= (batch
->transient_offset
+ sz
) < TRANSIENT_SLAB_SIZE
;
81 if (likely(has_current
&& fits_in_current
)) {
82 /* We can reuse the topmost BO, so get it */
83 unsigned idx
= util_dynarray_top(&batch
->transient_indices
, unsigned);
84 bo
= pan_bo_for_index(screen
, idx
);
86 /* Use the specified offset */
87 offset
= batch
->transient_offset
;
89 } else if (sz
< TRANSIENT_SLAB_SIZE
) {
90 /* We can't reuse the topmost BO, but we can get a new one.
91 * First, look for a free slot */
93 unsigned count
= util_dynarray_num_elements(&screen
->transient_bo
, void *);
96 unsigned free
= __bitset_ffs(
97 screen
->free_transient
,
98 count
/ BITSET_WORDBITS
);
104 /* It's ours, so no longer free */
105 BITSET_CLEAR(screen
->free_transient
, index
);
108 bo
= pan_bo_for_index(screen
, index
);
110 /* Otherwise, create a new BO */
111 bo
= panfrost_create_slab(screen
, &index
);
114 /* Remember we created this */
115 util_dynarray_append(&batch
->transient_indices
, unsigned, index
);
117 update_offset
= true;
119 /* Create a new BO and reference it */
120 bo
= panfrost_drm_create_bo(screen
, ALIGN_POT(sz
, 4096), 0);
121 panfrost_job_add_bo(batch
, bo
);
123 /* Creating a BO adds a reference, and then the job adds a
124 * second one. So we need to pop back one reference */
125 panfrost_bo_unreference(&screen
->base
, bo
);
128 struct panfrost_transfer ret
= {
129 .cpu
= bo
->cpu
+ offset
,
130 .gpu
= bo
->gpu
+ offset
,
134 batch
->transient_offset
= offset
+ sz
;
135 pthread_mutex_unlock(&screen
->transient_lock
);
142 panfrost_upload_transient(struct panfrost_context
*ctx
, const void *data
, size_t sz
)
144 struct panfrost_transfer transfer
= panfrost_allocate_transient(ctx
, sz
);
145 memcpy(transfer
.cpu
, data
, sz
);
149 /* The code below is exclusively for the use of shader memory and is subject to
150 * be rewritten soon enough since it never frees the memory it allocates. Here
151 * be dragons, etc. */
154 panfrost_upload(struct panfrost_memory
*mem
, const void *data
, size_t sz
)
156 size_t aligned_sz
= ALIGN_POT(sz
, ALIGNMENT
);
159 if ((mem
->stack_bottom
+ aligned_sz
) >= mem
->bo
->size
) {
160 printf("Out of memory, tried to upload %zd but only %zd available\n",
161 sz
, mem
->bo
->size
- mem
->stack_bottom
);
165 memcpy((uint8_t *) mem
->bo
->cpu
+ mem
->stack_bottom
, data
, sz
);
166 mali_ptr gpu
= mem
->bo
->gpu
+ mem
->stack_bottom
;
168 mem
->stack_bottom
+= aligned_sz
;