1 /**************************************************************************
3 * Copyright 2009 VMware, Inc.
4 * Copyright 2016 Axel Davy <axel.davy@ens.fr>
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
28 /* Adapted from u_upload_mgr.
29 * Makes suballocations from bigger allocations,
30 * while enabling fast mapping. */
32 #include "pipe/p_defines.h"
33 #include "util/u_inlines.h"
34 #include "pipe/p_context.h"
35 #include "util/u_memory.h"
36 #include "util/u_math.h"
37 #include "util/slab.h"
39 #include "nine_buffer_upload.h"
41 #include "nine_debug.h"
43 #define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER)
45 struct nine_buffer_group
{
46 unsigned refcount
; /* How many sub-buffers live inside the buffer */
47 struct pipe_resource
*resource
;
48 struct pipe_transfer
*transfer
;
50 unsigned free_offset
; /* Aligned offset to the upload buffer, pointing
51 * at the first unused byte. */
54 struct nine_subbuffer
{
55 struct nine_buffer_group
*parent
; /* Can be NULL */
56 struct pipe_resource
*resource
; /* The parent resource if apply */
57 unsigned offset
; /* Offset inside the resource */
58 /* If there is no parent, the resource map. Else NULL. */
59 struct pipe_transfer
*transfer
;
63 struct nine_buffer_upload
{
64 struct pipe_context
*pipe
;
65 struct slab_mempool buffer_pool
;
67 unsigned buffers_size
; /* Size of the big allocated buffers */
69 struct nine_buffer_group
*buffers
;
73 nine_upload_create_buffer_group(struct nine_buffer_upload
*upload
,
74 struct nine_buffer_group
*group
)
76 struct pipe_resource resource
;
77 struct pipe_screen
*screen
= upload
->pipe
->screen
;
78 DBG("%p %p\n", upload
, group
);
80 memset(&resource
, 0, sizeof(resource
));
81 resource
.target
= PIPE_BUFFER
;
82 resource
.format
= PIPE_FORMAT_R8_UNORM
;
83 resource
.bind
= PIPE_BIND_VERTEX_BUFFER
;
84 resource
.usage
= PIPE_USAGE_STREAM
;
85 resource
.width0
= upload
->buffers_size
;
88 resource
.array_size
= 1;
89 resource
.flags
= PIPE_RESOURCE_FLAG_MAP_PERSISTENT
|
90 PIPE_RESOURCE_FLAG_MAP_COHERENT
;
93 group
->resource
= screen
->resource_create(screen
, &resource
);
94 if (group
->resource
== NULL
)
97 group
->map
= pipe_buffer_map_range(upload
->pipe
, group
->resource
,
98 0, upload
->buffers_size
,
100 PIPE_TRANSFER_PERSISTENT
|
101 PIPE_TRANSFER_COHERENT
,
103 if (group
->map
== NULL
) {
104 group
->transfer
= NULL
;
105 pipe_resource_reference(&group
->resource
, NULL
);
109 group
->free_offset
= 0;
113 nine_upload_destroy_buffer_group(struct nine_buffer_upload
*upload
,
114 struct nine_buffer_group
*group
)
116 DBG("%p %p\n", upload
, group
);
117 assert(group
->refcount
== 0);
120 pipe_transfer_unmap(upload
->pipe
, group
->transfer
);
122 pipe_resource_reference(&group
->resource
, NULL
);
123 group
->transfer
= NULL
;
127 struct nine_buffer_upload
*
128 nine_upload_create(struct pipe_context
*pipe
, unsigned buffers_size
,
129 unsigned num_buffers
)
131 struct nine_buffer_upload
*upload
;
136 if (!pipe
->screen
->get_param(pipe
->screen
,
137 PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT
))
140 upload
= CALLOC_STRUCT(nine_buffer_upload
);
145 slab_create(&upload
->buffer_pool
, sizeof(struct nine_subbuffer
), 4096);
148 upload
->buffers_size
= align(buffers_size
, 4096);
149 upload
->num_buffers
= num_buffers
;
151 upload
->buffers
= CALLOC(num_buffers
, sizeof(struct nine_buffer_group
));
152 if (!upload
->buffers
)
155 for (i
= 0; i
< num_buffers
; i
++)
156 nine_upload_create_buffer_group(upload
, &upload
->buffers
[i
]);
161 slab_destroy(&upload
->buffer_pool
);
167 nine_upload_destroy(struct nine_buffer_upload
*upload
)
173 for (i
= 0; i
< upload
->num_buffers
; i
++)
174 nine_upload_destroy_buffer_group(upload
, &upload
->buffers
[i
]);
175 slab_destroy(&upload
->buffer_pool
);
179 struct nine_subbuffer
*
180 nine_upload_create_buffer(struct nine_buffer_upload
*upload
,
181 unsigned buffer_size
)
183 struct nine_subbuffer
*buf
= slab_alloc_st(&upload
->buffer_pool
);
184 struct nine_buffer_group
*group
= NULL
;
185 unsigned size
= align(buffer_size
, 4096);
188 DBG("%p %d\n", upload
, buffer_size
);
193 for (i
= 0; i
< upload
->num_buffers
; i
++) {
194 group
= &upload
->buffers
[i
];
195 if (group
->resource
&&
196 group
->free_offset
+ size
<= upload
->buffers_size
)
200 if (i
== upload
->num_buffers
) {
201 /* Allocate lonely buffer */
202 struct pipe_resource resource
;
203 struct pipe_screen
*screen
= upload
->pipe
->screen
;
205 DBG("Allocating buffer\n");
208 memset(&resource
, 0, sizeof(resource
));
209 resource
.target
= PIPE_BUFFER
;
210 resource
.format
= PIPE_FORMAT_R8_UNORM
;
211 resource
.bind
= PIPE_BIND_VERTEX_BUFFER
;
212 resource
.usage
= PIPE_USAGE_STREAM
;
213 resource
.width0
= buffer_size
;
214 resource
.height0
= 1;
216 resource
.array_size
= 1;
217 resource
.flags
= PIPE_RESOURCE_FLAG_MAP_PERSISTENT
|
218 PIPE_RESOURCE_FLAG_MAP_COHERENT
;
220 buf
->resource
= screen
->resource_create(screen
, &resource
);
221 if (buf
->resource
== NULL
) {
222 slab_free_st(&upload
->buffer_pool
, buf
);
226 buf
->map
= pipe_buffer_map_range(upload
->pipe
, buf
->resource
,
228 PIPE_TRANSFER_WRITE
|
229 PIPE_TRANSFER_PERSISTENT
|
230 PIPE_TRANSFER_COHERENT
,
232 if (buf
->map
== NULL
) {
233 pipe_resource_reference(&buf
->resource
, NULL
);
234 slab_free_st(&upload
->buffer_pool
, buf
);
241 DBG("Using buffer group %d\n", i
);
244 buf
->resource
= NULL
;
245 pipe_resource_reference(&buf
->resource
, group
->resource
);
246 buf
->offset
= group
->free_offset
;
248 group
->free_offset
+= size
;
249 group
->refcount
+= 1;
255 nine_upload_release_buffer(struct nine_buffer_upload
*upload
,
256 struct nine_subbuffer
*buf
)
258 DBG("%p %p %p\n", upload
, buf
, buf
->parent
);
261 pipe_resource_reference(&buf
->resource
, NULL
);
262 buf
->parent
->refcount
--;
263 if (buf
->parent
->refcount
== 0) {
264 /* Allocate new buffer */
265 nine_upload_destroy_buffer_group(upload
, buf
->parent
);
266 nine_upload_create_buffer_group(upload
, buf
->parent
);
271 pipe_transfer_unmap(upload
->pipe
, buf
->transfer
);
272 pipe_resource_reference(&buf
->resource
, NULL
);
275 slab_free_st(&upload
->buffer_pool
, buf
);
279 nine_upload_buffer_get_map(struct nine_subbuffer
*buf
)
282 return buf
->parent
->map
+ buf
->offset
;
288 struct pipe_resource
*
289 nine_upload_buffer_resource_and_offset(struct nine_subbuffer
*buf
,
292 *offset
= buf
->offset
;
293 return buf
->resource
;