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