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 bool has_current
= batch
->transient_indices
.size
;
78 bool fits_in_current
= (batch
->transient_offset
+ sz
) < TRANSIENT_SLAB_SIZE
;
80 if (likely(has_current
&& fits_in_current
)) {
81 /* We can reuse the topmost BO, so get it */
82 unsigned idx
= util_dynarray_top(&batch
->transient_indices
, unsigned);
83 bo
= pan_bo_for_index(screen
, idx
);
85 /* Use the specified offset */
86 offset
= batch
->transient_offset
;
88 } else if (sz
< TRANSIENT_SLAB_SIZE
) {
89 /* We can't reuse the topmost BO, but we can get a new one.
90 * First, look for a free slot */
92 unsigned count
= util_dynarray_num_elements(&screen
->transient_bo
, void *);
95 unsigned free
= __bitset_ffs(
96 screen
->free_transient
,
97 count
/ BITSET_WORDBITS
);
103 /* It's ours, so no longer free */
104 BITSET_CLEAR(screen
->free_transient
, index
);
107 bo
= pan_bo_for_index(screen
, index
);
109 /* Otherwise, create a new BO */
110 bo
= panfrost_create_slab(screen
, &index
);
113 /* Remember we created this */
114 util_dynarray_append(&batch
->transient_indices
, unsigned, index
);
116 update_offset
= true;
118 /* Create a new BO and reference it */
119 bo
= panfrost_drm_create_bo(screen
, ALIGN_POT(sz
, 4096), 0);
120 panfrost_job_add_bo(batch
, bo
);
122 /* Creating a BO adds a reference, and then the job adds a
123 * second one. So we need to pop back one reference */
124 panfrost_bo_unreference(&screen
->base
, bo
);
127 struct panfrost_transfer ret
= {
128 .cpu
= bo
->cpu
+ offset
,
129 .gpu
= bo
->gpu
+ offset
,
133 batch
->transient_offset
= offset
+ sz
;
140 panfrost_upload_transient(struct panfrost_context
*ctx
, const void *data
, size_t sz
)
142 struct panfrost_transfer transfer
= panfrost_allocate_transient(ctx
, sz
);
143 memcpy(transfer
.cpu
, data
, sz
);
147 /* The code below is exclusively for the use of shader memory and is subject to
148 * be rewritten soon enough since it never frees the memory it allocates. Here
149 * be dragons, etc. */
152 panfrost_upload(struct panfrost_memory
*mem
, const void *data
, size_t sz
)
154 size_t aligned_sz
= ALIGN_POT(sz
, ALIGNMENT
);
157 if ((mem
->stack_bottom
+ aligned_sz
) >= mem
->bo
->size
) {
158 printf("Out of memory, tried to upload %zd but only %zd available\n",
159 sz
, mem
->bo
->size
- mem
->stack_bottom
);
163 memcpy((uint8_t *) mem
->bo
->cpu
+ mem
->stack_bottom
, data
, sz
);
164 mali_ptr gpu
= mem
->bo
->gpu
+ mem
->stack_bottom
;
166 mem
->stack_bottom
+= aligned_sz
;