2 * © Copyright 2018 Alyssa Rosenzweig
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 #include <panfrost-misc.h>
30 #include <panfrost-job.h>
31 #include "pan_context.h"
33 /* TODO: What does this actually have to be? */
36 /* Allocate a mapped chunk directly from a heap */
38 struct panfrost_transfer
39 panfrost_allocate_chunk(struct panfrost_context
*ctx
, size_t size
, unsigned heap_id
)
41 size
= ALIGN(size
, ALIGNMENT
);
43 struct pipe_context
*gallium
= (struct pipe_context
*) ctx
;
44 struct panfrost_screen
*screen
= pan_screen(gallium
->screen
);
46 struct pb_slab_entry
*entry
= pb_slab_alloc(&screen
->slabs
, size
, heap_id
);
47 struct panfrost_memory_entry
*p_entry
= (struct panfrost_memory_entry
*) entry
;
48 struct panfrost_memory
*backing
= (struct panfrost_memory
*) entry
->slab
;
50 struct panfrost_transfer transfer
= {
51 .cpu
= backing
->cpu
+ p_entry
->offset
,
52 .gpu
= backing
->gpu
+ p_entry
->offset
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
)
66 sz
= ALIGN(sz
, ALIGNMENT
);
68 /* Check if there is room in the current entry */
69 struct panfrost_transient_pool
*pool
= &ctx
->transient_pools
[ctx
->cmdstream_i
];
71 if ((pool
->entry_offset
+ sz
) > pool
->entry_size
) {
72 /* Don't overflow this entry -- advance to the next */
74 pool
->entry_offset
= 0;
77 assert(pool
->entry_index
< PANFROST_MAX_TRANSIENT_ENTRIES
);
79 /* Check if this entry exists */
81 if (pool
->entry_index
>= pool
->entry_count
) {
82 /* Don't overflow the pool -- allocate a new one */
83 struct pipe_context
*gallium
= (struct pipe_context
*) ctx
;
84 struct panfrost_screen
*screen
= pan_screen(gallium
->screen
);
85 struct pb_slab_entry
*entry
= pb_slab_alloc(&screen
->slabs
, pool
->entry_size
, HEAP_TRANSIENT
);
88 pool
->entries
[pool
->entry_index
] = (struct panfrost_memory_entry
*) entry
;
91 /* Make sure we -still- won't overflow */
92 assert(sz
< pool
->entry_size
);
95 /* We have an entry we can write to, so do the upload! */
96 struct panfrost_memory_entry
*p_entry
= pool
->entries
[pool
->entry_index
];
97 struct panfrost_memory
*backing
= (struct panfrost_memory
*) p_entry
->base
.slab
;
99 struct panfrost_transfer ret
= {
100 .cpu
= backing
->cpu
+ p_entry
->offset
+ pool
->entry_offset
,
101 .gpu
= backing
->gpu
+ p_entry
->offset
+ pool
->entry_offset
104 /* Advance the pointer */
105 pool
->entry_offset
+= sz
;
112 panfrost_upload_transient(struct panfrost_context
*ctx
, const void *data
, size_t sz
)
114 struct panfrost_transfer transfer
= panfrost_allocate_transient(ctx
, sz
);
115 memcpy(transfer
.cpu
, data
, sz
);
119 // TODO: An actual allocator, perhaps
120 // TODO: Multiple stacks for multiple bases?
122 int hack_stack_bottom
= 4096; /* Don't interfere with constant offsets */
126 pandev_allocate_offset(int *stack
, size_t sz
)
128 /* First, align the stack bottom to something nice; it's not critical
129 * at this point if we waste a little space to do so. */
131 int excess
= *stack
& (ALIGNMENT
- 1);
133 /* Add the secret of my */
135 *stack
+= ALIGNMENT
- excess
;
137 /* Finally, use the new bottom for the allocation and move down the
146 pandev_upload(int cheating_offset
, int *stack_bottom
, mali_ptr base
, void *base_map
, const void *data
, size_t sz
, bool no_pad
)
150 /* We're not positive about the sizes of all objects, but we don't want
151 * them to crash against each other either. Let the caller disable
152 * padding if they so choose, though. */
154 size_t padded_size
= no_pad
? sz
: sz
* 2;
156 /* If no specific bottom is specified, use a global one... don't do
157 * this in production, kids */
160 stack_bottom
= &hack_stack_bottom
;
162 /* Allocate space for the new GPU object, if required */
164 if (cheating_offset
== -1) {
165 offset
= pandev_allocate_offset(stack_bottom
, padded_size
);
167 offset
= cheating_offset
;
168 *stack_bottom
= offset
+ sz
;
171 /* Save last offset for sequential uploads (job descriptors) */
172 last_offset
= offset
+ padded_size
;
175 memcpy((uint8_t *) base_map
+ offset
, data
, sz
);
177 /* Return the GPU address */
178 return base
+ offset
;
181 /* Upload immediately after the last allocation */
184 pandev_upload_sequential(mali_ptr base
, void *base_map
, const void *data
, size_t sz
)
186 return pandev_upload(last_offset
, NULL
, base
, base_map
, data
, sz
, /* false */ true);
189 /* Simplified APIs for the real driver, rather than replays */
192 panfrost_upload(struct panfrost_memory
*mem
, const void *data
, size_t sz
, bool no_pad
)
195 if ((mem
->stack_bottom
+ sz
) >= mem
->size
) {
196 printf("Out of memory, tried to upload %zd but only %zd available\n", sz
, mem
->size
- mem
->stack_bottom
);
200 return pandev_upload(-1, &mem
->stack_bottom
, mem
->gpu
, mem
->cpu
, data
, sz
, no_pad
);
204 panfrost_upload_sequential(struct panfrost_memory
*mem
, const void *data
, size_t sz
)
206 return pandev_upload(last_offset
, &mem
->stack_bottom
, mem
->gpu
, mem
->cpu
, data
, sz
, true);
209 /* Simplified interface to allocate a chunk without any upload, to allow
210 * zero-copy uploads. This is particularly useful when the copy would happen
211 * anyway, for instance with texture swizzling. */
214 panfrost_allocate_transfer(struct panfrost_memory
*mem
, size_t sz
, mali_ptr
*gpu
)
216 int offset
= pandev_allocate_offset(&mem
->stack_bottom
, sz
);
218 *gpu
= mem
->gpu
+ offset
;
219 return mem
->cpu
+ offset
;