xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/nine/nine_buffer_upload.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  *
3  * Copyright 2009 VMware, Inc.
4  * Copyright 2016 Axel Davy <[email protected]>
5  * All Rights Reserved.
6  *
7  * SPDX-License-Identifier: MIT
8  */
9 
10 /* Adapted from u_upload_mgr.
11  * Makes suballocations from bigger allocations,
12  * while enabling fast mapping. */
13 
14 #include "pipe/p_defines.h"
15 #include "util/u_inlines.h"
16 #include "pipe/p_context.h"
17 #include "util/u_memory.h"
18 #include "util/u_math.h"
19 #include "util/slab.h"
20 
21 #include "nine_buffer_upload.h"
22 
23 #include "nine_debug.h"
24 
25 #define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER)
26 
27 struct nine_buffer_group {
28     unsigned refcount; /* How many sub-buffers live inside the buffer */
29     struct pipe_resource *resource;
30     struct pipe_transfer *transfer;
31     uint8_t *map;
32     unsigned free_offset; /* Aligned offset to the upload buffer, pointing
33                            * at the first unused byte. */
34 };
35 
36 struct nine_subbuffer {
37     struct nine_buffer_group *parent; /* Can be NULL */
38     struct pipe_resource *resource; /* The parent resource if apply */
39     unsigned offset; /* Offset inside the resource */
40     /* If there is no parent, the resource map. Else NULL. */
41     struct pipe_transfer *transfer;
42     uint8_t *map;
43 };
44 
45 struct nine_buffer_upload {
46     struct pipe_context *pipe;
47     struct slab_mempool buffer_pool;
48 
49     unsigned buffers_size; /* Size of the big allocated buffers */
50     unsigned num_buffers;
51     struct nine_buffer_group *buffers;
52 };
53 
54 static void
nine_upload_create_buffer_group(struct nine_buffer_upload * upload,struct nine_buffer_group * group)55 nine_upload_create_buffer_group(struct nine_buffer_upload *upload,
56                                 struct nine_buffer_group *group)
57 {
58     struct pipe_resource resource;
59     struct pipe_screen *screen = upload->pipe->screen;
60     DBG("Allocating %p %p\n", upload, group);
61 
62     memset(&resource, 0, sizeof(resource));
63     resource.target = PIPE_BUFFER;
64     resource.format = PIPE_FORMAT_R8_UNORM;
65     resource.bind = PIPE_BIND_VERTEX_BUFFER;
66     resource.usage = PIPE_USAGE_STREAM;
67     resource.width0 = upload->buffers_size;
68     resource.height0 = 1;
69     resource.depth0 = 1;
70     resource.array_size = 1;
71     resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT |
72                      PIPE_RESOURCE_FLAG_MAP_COHERENT;
73 
74     group->refcount = 0;
75     group->resource = screen->resource_create(screen, &resource);
76     if (group->resource == NULL)
77         return;
78 
79     group->map = pipe_buffer_map_range(upload->pipe, group->resource,
80                                        0, upload->buffers_size,
81                                        PIPE_MAP_WRITE |
82 #if DETECT_ARCH_X86
83                                        PIPE_MAP_ONCE |
84 #endif
85                                        PIPE_MAP_PERSISTENT |
86                                        PIPE_MAP_COHERENT,
87                                        &group->transfer);
88     if (group->map == NULL) {
89         group->transfer = NULL;
90         pipe_resource_reference(&group->resource, NULL);
91         return;
92     }
93 
94     group->free_offset = 0;
95     DBG("Success: %p %p\n", group->map, group->map+upload->buffers_size);
96 }
97 
98 static void
nine_upload_destroy_buffer_group(struct nine_buffer_upload * upload,struct nine_buffer_group * group)99 nine_upload_destroy_buffer_group(struct nine_buffer_upload *upload,
100                                  struct nine_buffer_group *group)
101 {
102     DBG("%p %p\n", upload, group);
103     DBG("Release: %p %p\n", group->map, group->map+upload->buffers_size);
104     assert(group->refcount == 0);
105 
106     if (group->transfer)
107         pipe_buffer_unmap(upload->pipe, group->transfer);
108     if (group->resource)
109         pipe_resource_reference(&group->resource, NULL);
110     group->transfer = NULL;
111     group->map = NULL;
112 }
113 
114 struct nine_buffer_upload *
nine_upload_create(struct pipe_context * pipe,unsigned buffers_size,unsigned num_buffers)115 nine_upload_create(struct pipe_context *pipe, unsigned buffers_size,
116                    unsigned num_buffers)
117 {
118     struct nine_buffer_upload *upload;
119     int i;
120 
121     DBG("\n");
122 
123     if (!pipe->screen->get_param(pipe->screen,
124                                  PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT))
125         return NULL;
126 
127     upload = CALLOC_STRUCT(nine_buffer_upload);
128 
129     if (!upload)
130         return NULL;
131 
132     slab_create(&upload->buffer_pool, sizeof(struct nine_subbuffer), 4096);
133 
134     upload->pipe = pipe;
135     upload->buffers_size = align(buffers_size, 4096);
136     upload->num_buffers = num_buffers;
137 
138     upload->buffers = CALLOC(num_buffers, sizeof(struct nine_buffer_group));
139     if (!upload->buffers)
140         goto buffers_fail;
141 
142     for (i = 0; i < num_buffers; i++)
143         nine_upload_create_buffer_group(upload, &upload->buffers[i]);
144 
145     return upload;
146 
147 buffers_fail:
148     slab_destroy(&upload->buffer_pool);
149     FREE(upload);
150     return NULL;
151 }
152 
153 void
nine_upload_destroy(struct nine_buffer_upload * upload)154 nine_upload_destroy(struct nine_buffer_upload *upload)
155 {
156     int i;
157 
158     DBG("%p\n", upload);
159 
160     for (i = 0; i < upload->num_buffers; i++)
161         nine_upload_destroy_buffer_group(upload, &upload->buffers[i]);
162     slab_destroy(&upload->buffer_pool);
163     FREE(upload);
164 }
165 
166 struct nine_subbuffer *
nine_upload_create_buffer(struct nine_buffer_upload * upload,unsigned buffer_size)167 nine_upload_create_buffer(struct nine_buffer_upload *upload,
168                           unsigned buffer_size)
169 {
170     struct nine_subbuffer *buf = slab_alloc_st(&upload->buffer_pool);
171     struct nine_buffer_group *group = NULL;
172     unsigned size = align(buffer_size, 4096);
173     int i = 0;
174 
175     DBG("%p %d\n", upload, buffer_size);
176 
177     if (!buf)
178         return NULL;
179 
180     for (i = 0; i < upload->num_buffers; i++) {
181         group = &upload->buffers[i];
182         if (group->resource &&
183             group->free_offset + size <= upload->buffers_size)
184             break;
185     }
186 
187     if (i == upload->num_buffers) {
188         /* Allocate lonely buffer */
189         struct pipe_resource resource;
190         struct pipe_screen *screen = upload->pipe->screen;
191 
192         DBG("Allocating buffer\n");
193         buf->parent = NULL;
194 
195         memset(&resource, 0, sizeof(resource));
196         resource.target = PIPE_BUFFER;
197         resource.format = PIPE_FORMAT_R8_UNORM;
198         resource.bind = PIPE_BIND_VERTEX_BUFFER;
199         resource.usage = PIPE_USAGE_STREAM;
200         resource.width0 = buffer_size;
201         resource.height0 = 1;
202         resource.depth0 = 1;
203         resource.array_size = 1;
204         resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT |
205                          PIPE_RESOURCE_FLAG_MAP_COHERENT;
206 
207         buf->resource = screen->resource_create(screen, &resource);
208         if (buf->resource == NULL) {
209             slab_free_st(&upload->buffer_pool, buf);
210             return NULL;
211         }
212 
213         buf->map = pipe_buffer_map_range(upload->pipe, buf->resource,
214                                          0, buffer_size,
215                                          PIPE_MAP_WRITE |
216 #if DETECT_ARCH_X86
217                                          PIPE_MAP_ONCE |
218 #endif
219                                          PIPE_MAP_PERSISTENT |
220                                          PIPE_MAP_COHERENT,
221                                          &buf->transfer);
222         if (buf->map == NULL) {
223             pipe_resource_reference(&buf->resource, NULL);
224             slab_free_st(&upload->buffer_pool, buf);
225             return NULL;
226         }
227         buf->offset = 0;
228         return buf;
229     }
230 
231     DBG("Using buffer group %d\n", i);
232 
233     buf->parent = group;
234     buf->resource = NULL;
235     pipe_resource_reference(&buf->resource, group->resource);
236     buf->offset = group->free_offset;
237 
238     group->free_offset += size;
239     group->refcount += 1;
240 
241     return buf;
242 }
243 
244 void
nine_upload_release_buffer(struct nine_buffer_upload * upload,struct nine_subbuffer * buf)245 nine_upload_release_buffer(struct nine_buffer_upload *upload,
246                            struct nine_subbuffer *buf)
247 {
248     DBG("%p %p %p\n", upload, buf, buf->parent);
249 
250     if (buf->parent) {
251         pipe_resource_reference(&buf->resource, NULL);
252         buf->parent->refcount--;
253         if (buf->parent->refcount == 0) {
254             /* Allocate new buffer */
255             nine_upload_destroy_buffer_group(upload, buf->parent);
256             nine_upload_create_buffer_group(upload, buf->parent);
257         }
258     } else {
259         /* lonely buffer */
260         if (buf->transfer)
261             pipe_buffer_unmap(upload->pipe, buf->transfer);
262         pipe_resource_reference(&buf->resource, NULL);
263     }
264 
265     slab_free_st(&upload->buffer_pool, buf);
266 }
267 
268 uint8_t *
nine_upload_buffer_get_map(struct nine_subbuffer * buf)269 nine_upload_buffer_get_map(struct nine_subbuffer *buf)
270 {
271     if (buf->parent) {
272         DBG("%d\n", buf->parent->refcount);
273         return buf->parent->map + buf->offset;
274     }
275     /* lonely buffer */
276     return buf->map;
277 }
278 
279 struct pipe_resource *
nine_upload_buffer_resource_and_offset(struct nine_subbuffer * buf,unsigned * offset)280 nine_upload_buffer_resource_and_offset(struct nine_subbuffer *buf,
281                                        unsigned *offset)
282 {
283     *offset = buf->offset;
284     return buf->resource;
285 }
286