• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2009 VMware, Inc.
4  * Copyright 2016 Axel Davy <axel.davy@ens.fr>
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->caps.buffer_map_persistent_coherent)
124         return NULL;
125 
126     upload = CALLOC_STRUCT(nine_buffer_upload);
127 
128     if (!upload)
129         return NULL;
130 
131     slab_create(&upload->buffer_pool, sizeof(struct nine_subbuffer), 4096);
132 
133     upload->pipe = pipe;
134     upload->buffers_size = align(buffers_size, 4096);
135     upload->num_buffers = num_buffers;
136 
137     upload->buffers = CALLOC(num_buffers, sizeof(struct nine_buffer_group));
138     if (!upload->buffers)
139         goto buffers_fail;
140 
141     for (i = 0; i < num_buffers; i++)
142         nine_upload_create_buffer_group(upload, &upload->buffers[i]);
143 
144     return upload;
145 
146 buffers_fail:
147     slab_destroy(&upload->buffer_pool);
148     FREE(upload);
149     return NULL;
150 }
151 
152 void
nine_upload_destroy(struct nine_buffer_upload * upload)153 nine_upload_destroy(struct nine_buffer_upload *upload)
154 {
155     int i;
156 
157     DBG("%p\n", upload);
158 
159     for (i = 0; i < upload->num_buffers; i++)
160         nine_upload_destroy_buffer_group(upload, &upload->buffers[i]);
161     slab_destroy(&upload->buffer_pool);
162     FREE(upload);
163 }
164 
165 struct nine_subbuffer *
nine_upload_create_buffer(struct nine_buffer_upload * upload,unsigned buffer_size)166 nine_upload_create_buffer(struct nine_buffer_upload *upload,
167                           unsigned buffer_size)
168 {
169     struct nine_subbuffer *buf = slab_alloc_st(&upload->buffer_pool);
170     struct nine_buffer_group *group = NULL;
171     unsigned size = align(buffer_size, 4096);
172     int i = 0;
173 
174     DBG("%p %d\n", upload, buffer_size);
175 
176     if (!buf)
177         return NULL;
178 
179     for (i = 0; i < upload->num_buffers; i++) {
180         group = &upload->buffers[i];
181         if (group->resource &&
182             group->free_offset + size <= upload->buffers_size)
183             break;
184     }
185 
186     if (i == upload->num_buffers) {
187         /* Allocate lonely buffer */
188         struct pipe_resource resource;
189         struct pipe_screen *screen = upload->pipe->screen;
190 
191         DBG("Allocating buffer\n");
192         buf->parent = NULL;
193 
194         memset(&resource, 0, sizeof(resource));
195         resource.target = PIPE_BUFFER;
196         resource.format = PIPE_FORMAT_R8_UNORM;
197         resource.bind = PIPE_BIND_VERTEX_BUFFER;
198         resource.usage = PIPE_USAGE_STREAM;
199         resource.width0 = buffer_size;
200         resource.height0 = 1;
201         resource.depth0 = 1;
202         resource.array_size = 1;
203         resource.flags = PIPE_RESOURCE_FLAG_MAP_PERSISTENT |
204                          PIPE_RESOURCE_FLAG_MAP_COHERENT;
205 
206         buf->resource = screen->resource_create(screen, &resource);
207         if (buf->resource == NULL) {
208             slab_free_st(&upload->buffer_pool, buf);
209             return NULL;
210         }
211 
212         buf->map = pipe_buffer_map_range(upload->pipe, buf->resource,
213                                          0, buffer_size,
214                                          PIPE_MAP_WRITE |
215 #if DETECT_ARCH_X86
216                                          PIPE_MAP_ONCE |
217 #endif
218                                          PIPE_MAP_PERSISTENT |
219                                          PIPE_MAP_COHERENT,
220                                          &buf->transfer);
221         if (buf->map == NULL) {
222             pipe_resource_reference(&buf->resource, NULL);
223             slab_free_st(&upload->buffer_pool, buf);
224             return NULL;
225         }
226         buf->offset = 0;
227         return buf;
228     }
229 
230     DBG("Using buffer group %d\n", i);
231 
232     buf->parent = group;
233     buf->resource = NULL;
234     pipe_resource_reference(&buf->resource, group->resource);
235     buf->offset = group->free_offset;
236 
237     group->free_offset += size;
238     group->refcount += 1;
239 
240     return buf;
241 }
242 
243 void
nine_upload_release_buffer(struct nine_buffer_upload * upload,struct nine_subbuffer * buf)244 nine_upload_release_buffer(struct nine_buffer_upload *upload,
245                            struct nine_subbuffer *buf)
246 {
247     DBG("%p %p %p\n", upload, buf, buf->parent);
248 
249     if (buf->parent) {
250         pipe_resource_reference(&buf->resource, NULL);
251         buf->parent->refcount--;
252         if (buf->parent->refcount == 0) {
253             /* Allocate new buffer */
254             nine_upload_destroy_buffer_group(upload, buf->parent);
255             nine_upload_create_buffer_group(upload, buf->parent);
256         }
257     } else {
258         /* lonely buffer */
259         if (buf->transfer)
260             pipe_buffer_unmap(upload->pipe, buf->transfer);
261         pipe_resource_reference(&buf->resource, NULL);
262     }
263 
264     slab_free_st(&upload->buffer_pool, buf);
265 }
266 
267 uint8_t *
nine_upload_buffer_get_map(struct nine_subbuffer * buf)268 nine_upload_buffer_get_map(struct nine_subbuffer *buf)
269 {
270     if (buf->parent) {
271         DBG("%d\n", buf->parent->refcount);
272         return buf->parent->map + buf->offset;
273     }
274     /* lonely buffer */
275     return buf->map;
276 }
277 
278 struct pipe_resource *
nine_upload_buffer_resource_and_offset(struct nine_subbuffer * buf,unsigned * offset)279 nine_upload_buffer_resource_and_offset(struct nine_subbuffer *buf,
280                                        unsigned *offset)
281 {
282     *offset = buf->offset;
283     return buf->resource;
284 }
285