panfrost: s/job/batch/
[mesa.git] / src / gallium / drivers / panfrost / pan_allocate.c
1 /*
2 * © Copyright 2018 Alyssa Rosenzweig
3 * Copyright (C) 2019 Collabora, Ltd.
4 *
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:
11 *
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
14 * Software.
15 *
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
22 * SOFTWARE.
23 *
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <panfrost-misc.h>
31 #include <panfrost-job.h>
32 #include "pan_context.h"
33
34 /* TODO: What does this actually have to be? */
35 #define ALIGNMENT 128
36
37 /* Allocate a new transient slab */
38
39 static struct panfrost_bo *
40 panfrost_create_slab(struct panfrost_screen *screen, unsigned *index)
41 {
42 /* Allocate a new slab on the screen */
43
44 struct panfrost_bo **new =
45 util_dynarray_grow(&screen->transient_bo,
46 struct panfrost_bo *, 1);
47
48 struct panfrost_bo *alloc = panfrost_drm_create_bo(screen, TRANSIENT_SLAB_SIZE, 0);
49
50 *new = alloc;
51
52 /* Return the BO as well as the index we just added */
53
54 *index = util_dynarray_num_elements(&screen->transient_bo, void *) - 1;
55 return alloc;
56 }
57
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 */
61
62 struct panfrost_transfer
63 panfrost_allocate_transient(struct panfrost_context *ctx, size_t sz)
64 {
65 struct panfrost_screen *screen = pan_screen(ctx->base.screen);
66 struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
67
68 /* Pad the size */
69 sz = ALIGN_POT(sz, ALIGNMENT);
70
71 /* Find or create a suitable BO */
72 struct panfrost_bo *bo = NULL;
73
74 unsigned offset = 0;
75 bool update_offset = false;
76
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;
80
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);
85
86 /* Use the specified offset */
87 offset = batch->transient_offset;
88 update_offset = true;
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 */
92
93 unsigned count = util_dynarray_num_elements(&screen->transient_bo, void *);
94 unsigned index = 0;
95
96 unsigned free = __bitset_ffs(
97 screen->free_transient,
98 count / BITSET_WORDBITS);
99
100 if (likely(free)) {
101 /* Use this one */
102 index = free - 1;
103
104 /* It's ours, so no longer free */
105 BITSET_CLEAR(screen->free_transient, index);
106
107 /* Grab the BO */
108 bo = pan_bo_for_index(screen, index);
109 } else {
110 /* Otherwise, create a new BO */
111 bo = panfrost_create_slab(screen, &index);
112 }
113
114 panfrost_batch_add_bo(batch, bo);
115
116 /* Remember we created this */
117 util_dynarray_append(&batch->transient_indices, unsigned, index);
118
119 update_offset = true;
120 } else {
121 /* Create a new BO and reference it */
122 bo = panfrost_drm_create_bo(screen, ALIGN_POT(sz, 4096), 0);
123 panfrost_batch_add_bo(batch, bo);
124
125 /* Creating a BO adds a reference, and then the job adds a
126 * second one. So we need to pop back one reference */
127 panfrost_bo_unreference(&screen->base, bo);
128 }
129
130 struct panfrost_transfer ret = {
131 .cpu = bo->cpu + offset,
132 .gpu = bo->gpu + offset,
133 };
134
135 if (update_offset)
136 batch->transient_offset = offset + sz;
137 pthread_mutex_unlock(&screen->transient_lock);
138
139 return ret;
140
141 }
142
143 mali_ptr
144 panfrost_upload_transient(struct panfrost_context *ctx, const void *data, size_t sz)
145 {
146 struct panfrost_transfer transfer = panfrost_allocate_transient(ctx, sz);
147 memcpy(transfer.cpu, data, sz);
148 return transfer.gpu;
149 }