diff options
author | Marek Olšák <maraeo@gmail.com> | 2011-01-29 20:53:57 +0100 |
---|---|---|
committer | Marek Olšák <maraeo@gmail.com> | 2011-02-07 02:23:46 +0100 |
commit | 975320ab76f5c247f6ed4dab80627173845200d0 (patch) | |
tree | 888695efaf5d0056df04e85a61ebfe5beaa9c431 | |
parent | 1c2a4f0820ff2272f993e6da28dcf8bcbbc3252a (diff) |
util: import a new vertex buffer manager
This code has originally matured in r300g and was ported to r600g several
times. It was obvious it's a code duplication.
See also comments in the header file.
-rw-r--r-- | src/gallium/auxiliary/Makefile | 3 | ||||
-rw-r--r-- | src/gallium/auxiliary/SConscript | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/util/u_vbuf_mgr.c | 606 | ||||
-rw-r--r-- | src/gallium/auxiliary/util/u_vbuf_mgr.h | 113 |
4 files changed, 722 insertions, 1 deletions
diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile index ff355c47832..7d7d700eacd 100644 --- a/src/gallium/auxiliary/Makefile +++ b/src/gallium/auxiliary/Makefile | |||
@@ -142,7 +142,8 @@ C_SOURCES = \ | |||
142 | util/u_tile.c \ | 142 | util/u_tile.c \ |
143 | util/u_transfer.c \ | 143 | util/u_transfer.c \ |
144 | util/u_resource.c \ | 144 | util/u_resource.c \ |
145 | util/u_upload_mgr.c | 145 | util/u_upload_mgr.c \ |
146 | util/u_vbuf_mgr.c | ||
146 | 147 | ||
147 | # Disabling until pipe-video branch gets merged in | 148 | # Disabling until pipe-video branch gets merged in |
148 | #vl/vl_bitstream_parser.c \ | 149 | #vl/vl_bitstream_parser.c \ |
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript index fca7e5fd117..0ec63071615 100644 --- a/src/gallium/auxiliary/SConscript +++ b/src/gallium/auxiliary/SConscript | |||
@@ -190,6 +190,7 @@ source = [ | |||
190 | 'util/u_tile.c', | 190 | 'util/u_tile.c', |
191 | 'util/u_transfer.c', | 191 | 'util/u_transfer.c', |
192 | 'util/u_upload_mgr.c', | 192 | 'util/u_upload_mgr.c', |
193 | 'util/u_vbuf_mgr.c', | ||
193 | # Disabling until pipe-video branch gets merged in | 194 | # Disabling until pipe-video branch gets merged in |
194 | #'vl/vl_bitstream_parser.c', | 195 | #'vl/vl_bitstream_parser.c', |
195 | #'vl/vl_mpeg12_mc_renderer.c', | 196 | #'vl/vl_mpeg12_mc_renderer.c', |
diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.c b/src/gallium/auxiliary/util/u_vbuf_mgr.c new file mode 100644 index 00000000000..28c7f727ef8 --- /dev/null +++ b/src/gallium/auxiliary/util/u_vbuf_mgr.c | |||
@@ -0,0 +1,606 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2011 Marek Olšák <maraeo@gmail.com> | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
21 | * IN NO EVENT SHALL AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR | ||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | |||
28 | #include "util/u_vbuf_mgr.h" | ||
29 | |||
30 | #include "util/u_format.h" | ||
31 | #include "util/u_inlines.h" | ||
32 | #include "util/u_memory.h" | ||
33 | #include "util/u_upload_mgr.h" | ||
34 | #include "translate/translate.h" | ||
35 | #include "translate/translate_cache.h" | ||
36 | |||
37 | /* Hardware vertex fetcher limitations can be described by this structure. */ | ||
38 | struct u_vbuf_caps { | ||
39 | /* Vertex format CAPs. */ | ||
40 | /* TRUE if hardware supports it. */ | ||
41 | unsigned format_fixed32:1; /* PIPE_FORMAT_*32*_FIXED */ | ||
42 | unsigned format_float16:1; /* PIPE_FORMAT_*16*_FLOAT */ | ||
43 | unsigned format_float64:1; /* PIPE_FORMAT_*64*_FLOAT */ | ||
44 | unsigned format_norm32:1; /* PIPE_FORMAT_*32*NORM */ | ||
45 | unsigned format_scaled32:1; /* PIPE_FORMAT_*32*SCALED */ | ||
46 | |||
47 | /* Whether vertex fetches don't have to be dword-aligned. */ | ||
48 | /* TRUE if hardware supports it. */ | ||
49 | unsigned fetch_dword_unaligned:1; | ||
50 | }; | ||
51 | |||
52 | struct u_vbuf_mgr_elements { | ||
53 | unsigned count; | ||
54 | struct pipe_vertex_element ve[PIPE_MAX_ATTRIBS]; | ||
55 | |||
56 | /* If (velem[i].src_format != real_format[i]), the vertex buffer | ||
57 | * referenced by the vertex element cannot be used for rendering and | ||
58 | * its vertex data must be translated to real_format[i]. */ | ||
59 | enum pipe_format native_format[PIPE_MAX_ATTRIBS]; | ||
60 | unsigned native_format_size[PIPE_MAX_ATTRIBS]; | ||
61 | |||
62 | /* This might mean two things: | ||
63 | * - src_format != native_format, as discussed above. | ||
64 | * - src_offset % 4 != 0 (if the caps don't allow such an offset). */ | ||
65 | boolean incompatible_layout; | ||
66 | }; | ||
67 | |||
68 | struct u_vbuf_mgr_priv { | ||
69 | struct u_vbuf_mgr b; | ||
70 | struct u_vbuf_caps caps; | ||
71 | struct pipe_context *pipe; | ||
72 | |||
73 | struct translate_cache *translate_cache; | ||
74 | unsigned translate_vb_slot; | ||
75 | |||
76 | struct u_upload_mgr *uploader; | ||
77 | |||
78 | struct u_vbuf_mgr_elements *ve; | ||
79 | void *saved_ve, *fallback_ve; | ||
80 | boolean ve_binding_lock; | ||
81 | |||
82 | boolean any_user_vbs; | ||
83 | boolean incompatible_vb_layout; | ||
84 | }; | ||
85 | |||
86 | static void u_vbuf_mgr_init_format_caps(struct u_vbuf_mgr_priv *mgr) | ||
87 | { | ||
88 | struct pipe_screen *screen = mgr->pipe->screen; | ||
89 | |||
90 | mgr->caps.format_fixed32 = | ||
91 | screen->is_format_supported(screen, PIPE_FORMAT_R32_FIXED, PIPE_BUFFER, | ||
92 | 0, PIPE_BIND_VERTEX_BUFFER, 0); | ||
93 | |||
94 | mgr->caps.format_float16 = | ||
95 | screen->is_format_supported(screen, PIPE_FORMAT_R16_FLOAT, PIPE_BUFFER, | ||
96 | 0, PIPE_BIND_VERTEX_BUFFER, 0); | ||
97 | |||
98 | mgr->caps.format_float64 = | ||
99 | screen->is_format_supported(screen, PIPE_FORMAT_R64_FLOAT, PIPE_BUFFER, | ||
100 | 0, PIPE_BIND_VERTEX_BUFFER, 0); | ||
101 | |||
102 | mgr->caps.format_norm32 = | ||
103 | screen->is_format_supported(screen, PIPE_FORMAT_R32_UNORM, PIPE_BUFFER, | ||
104 | 0, PIPE_BIND_VERTEX_BUFFER, 0) && | ||
105 | screen->is_format_supported(screen, PIPE_FORMAT_R32_SNORM, PIPE_BUFFER, | ||
106 | 0, PIPE_BIND_VERTEX_BUFFER, 0); | ||
107 | |||
108 | mgr->caps.format_scaled32 = | ||
109 | screen->is_format_supported(screen, PIPE_FORMAT_R32_USCALED, PIPE_BUFFER, | ||
110 | 0, PIPE_BIND_VERTEX_BUFFER, 0) && | ||
111 | screen->is_format_supported(screen, PIPE_FORMAT_R32_SSCALED, PIPE_BUFFER, | ||
112 | 0, PIPE_BIND_VERTEX_BUFFER, 0); | ||
113 | } | ||
114 | |||
115 | struct u_vbuf_mgr * | ||
116 | u_vbuf_mgr_create(struct pipe_context *pipe, | ||
117 | unsigned upload_buffer_size, | ||
118 | unsigned upload_buffer_alignment, | ||
119 | enum u_fetch_alignment fetch_alignment) | ||
120 | { | ||
121 | struct u_vbuf_mgr_priv *mgr = CALLOC_STRUCT(u_vbuf_mgr_priv); | ||
122 | |||
123 | mgr->pipe = pipe; | ||
124 | mgr->translate_cache = translate_cache_create(); | ||
125 | |||
126 | mgr->uploader = u_upload_create(pipe, upload_buffer_size, | ||
127 | upload_buffer_alignment, | ||
128 | PIPE_BIND_VERTEX_BUFFER); | ||
129 | |||
130 | mgr->caps.fetch_dword_unaligned = | ||
131 | fetch_alignment == U_VERTEX_FETCH_BYTE_ALIGNED; | ||
132 | |||
133 | u_vbuf_mgr_init_format_caps(mgr); | ||
134 | |||
135 | return &mgr->b; | ||
136 | } | ||
137 | |||
138 | void u_vbuf_mgr_destroy(struct u_vbuf_mgr *mgrb) | ||
139 | { | ||
140 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
141 | unsigned i; | ||
142 | |||
143 | for (i = 0; i < mgr->b.nr_real_vertex_buffers; i++) { | ||
144 | pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, NULL); | ||
145 | pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL); | ||
146 | } | ||
147 | |||
148 | translate_cache_destroy(mgr->translate_cache); | ||
149 | u_upload_destroy(mgr->uploader); | ||
150 | FREE(mgr); | ||
151 | } | ||
152 | |||
153 | |||
154 | static void u_vbuf_translate_begin(struct u_vbuf_mgr_priv *mgr, | ||
155 | int min_index, int max_index, | ||
156 | boolean *upload_flushed) | ||
157 | { | ||
158 | struct translate_key key = {0}; | ||
159 | struct translate_element *te; | ||
160 | unsigned tr_elem_index[PIPE_MAX_ATTRIBS] = {0}; | ||
161 | struct translate *tr; | ||
162 | boolean vb_translated[PIPE_MAX_ATTRIBS] = {0}; | ||
163 | uint8_t *vb_map[PIPE_MAX_ATTRIBS] = {0}, *out_map; | ||
164 | struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = {0}; | ||
165 | struct pipe_resource *out_buffer = NULL; | ||
166 | unsigned i, num_verts, out_offset; | ||
167 | struct pipe_vertex_element new_velems[PIPE_MAX_ATTRIBS]; | ||
168 | |||
169 | /* Initialize the translate key, i.e. the recipe how vertices should be | ||
170 | * translated. */ | ||
171 | for (i = 0; i < mgr->ve->count; i++) { | ||
172 | struct pipe_vertex_buffer *vb = | ||
173 | &mgr->b.vertex_buffer[mgr->ve->ve[i].vertex_buffer_index]; | ||
174 | enum pipe_format output_format = mgr->ve->native_format[i]; | ||
175 | unsigned output_format_size = mgr->ve->native_format_size[i]; | ||
176 | |||
177 | /* Check for support. */ | ||
178 | if (mgr->ve->ve[i].src_format == mgr->ve->native_format[i] && | ||
179 | (mgr->caps.fetch_dword_unaligned || | ||
180 | (vb->buffer_offset % 4 == 0 && | ||
181 | vb->stride % 4 == 0 && | ||
182 | mgr->ve->ve[i].src_offset % 4 == 0))) { | ||
183 | continue; | ||
184 | } | ||
185 | |||
186 | /* Workaround for translate: output floats instead of halfs. */ | ||
187 | switch (output_format) { | ||
188 | case PIPE_FORMAT_R16_FLOAT: | ||
189 | output_format = PIPE_FORMAT_R32_FLOAT; | ||
190 | output_format_size = 4; | ||
191 | break; | ||
192 | case PIPE_FORMAT_R16G16_FLOAT: | ||
193 | output_format = PIPE_FORMAT_R32G32_FLOAT; | ||
194 | output_format_size = 8; | ||
195 | break; | ||
196 | case PIPE_FORMAT_R16G16B16_FLOAT: | ||
197 | output_format = PIPE_FORMAT_R32G32B32_FLOAT; | ||
198 | output_format_size = 12; | ||
199 | break; | ||
200 | case PIPE_FORMAT_R16G16B16A16_FLOAT: | ||
201 | output_format = PIPE_FORMAT_R32G32B32A32_FLOAT; | ||
202 | output_format_size = 16; | ||
203 | break; | ||
204 | default:; | ||
205 | } | ||
206 | |||
207 | /* Add this vertex element. */ | ||
208 | te = &key.element[key.nr_elements]; | ||
209 | /*te->type; | ||
210 | te->instance_divisor;*/ | ||
211 | te->input_buffer = mgr->ve->ve[i].vertex_buffer_index; | ||
212 | te->input_format = mgr->ve->ve[i].src_format; | ||
213 | te->input_offset = mgr->ve->ve[i].src_offset; | ||
214 | te->output_format = output_format; | ||
215 | te->output_offset = key.output_stride; | ||
216 | |||
217 | key.output_stride += output_format_size; | ||
218 | vb_translated[mgr->ve->ve[i].vertex_buffer_index] = TRUE; | ||
219 | tr_elem_index[i] = key.nr_elements; | ||
220 | key.nr_elements++; | ||
221 | } | ||
222 | |||
223 | /* Get a translate object. */ | ||
224 | tr = translate_cache_find(mgr->translate_cache, &key); | ||
225 | |||
226 | /* Map buffers we want to translate. */ | ||
227 | for (i = 0; i < mgr->b.nr_vertex_buffers; i++) { | ||
228 | if (vb_translated[i]) { | ||
229 | struct pipe_vertex_buffer *vb = &mgr->b.vertex_buffer[i]; | ||
230 | |||
231 | vb_map[i] = pipe_buffer_map(mgr->pipe, vb->buffer, | ||
232 | PIPE_TRANSFER_READ, &vb_transfer[i]); | ||
233 | |||
234 | tr->set_buffer(tr, i, | ||
235 | vb_map[i] + vb->buffer_offset + vb->stride * min_index, | ||
236 | vb->stride, ~0); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* Create and map the output buffer. */ | ||
241 | num_verts = max_index + 1 - min_index; | ||
242 | |||
243 | u_upload_alloc(mgr->uploader, | ||
244 | key.output_stride * min_index, | ||
245 | key.output_stride * num_verts, | ||
246 | &out_offset, &out_buffer, upload_flushed, | ||
247 | (void**)&out_map); | ||
248 | |||
249 | out_offset -= key.output_stride * min_index; | ||
250 | |||
251 | /* Translate. */ | ||
252 | tr->run(tr, 0, num_verts, 0, out_map); | ||
253 | |||
254 | /* Unmap all buffers. */ | ||
255 | for (i = 0; i < mgr->b.nr_vertex_buffers; i++) { | ||
256 | if (vb_translated[i]) { | ||
257 | pipe_buffer_unmap(mgr->pipe, vb_transfer[i]); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | /* Setup the new vertex buffer in the first free slot. */ | ||
262 | mgr->translate_vb_slot = ~0; | ||
263 | for (i = 0; i < PIPE_MAX_ATTRIBS; i++) { | ||
264 | if (!mgr->b.vertex_buffer[i].buffer) { | ||
265 | mgr->translate_vb_slot = i; | ||
266 | |||
267 | if (i >= mgr->b.nr_vertex_buffers) { | ||
268 | mgr->b.nr_real_vertex_buffers = i+1; | ||
269 | } | ||
270 | break; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | if (mgr->translate_vb_slot != ~0) { | ||
275 | /* Setup the new vertex buffer. */ | ||
276 | pipe_resource_reference( | ||
277 | &mgr->b.real_vertex_buffer[mgr->translate_vb_slot], out_buffer); | ||
278 | mgr->b.vertex_buffer[mgr->translate_vb_slot].buffer_offset = out_offset; | ||
279 | mgr->b.vertex_buffer[mgr->translate_vb_slot].stride = key.output_stride; | ||
280 | |||
281 | /* Setup new vertex elements. */ | ||
282 | for (i = 0; i < mgr->ve->count; i++) { | ||
283 | if (vb_translated[mgr->ve->ve[i].vertex_buffer_index]) { | ||
284 | te = &key.element[tr_elem_index[i]]; | ||
285 | new_velems[i].instance_divisor = mgr->ve->ve[i].instance_divisor; | ||
286 | new_velems[i].src_format = te->output_format; | ||
287 | new_velems[i].src_offset = te->output_offset; | ||
288 | new_velems[i].vertex_buffer_index = mgr->translate_vb_slot; | ||
289 | } else { | ||
290 | memcpy(&new_velems[i], &mgr->ve->ve[i], | ||
291 | sizeof(struct pipe_vertex_element)); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | mgr->fallback_ve = | ||
296 | mgr->pipe->create_vertex_elements_state(mgr->pipe, mgr->ve->count, | ||
297 | new_velems); | ||
298 | |||
299 | /* Preserve saved_ve. */ | ||
300 | mgr->ve_binding_lock = TRUE; | ||
301 | mgr->pipe->bind_vertex_elements_state(mgr->pipe, mgr->fallback_ve); | ||
302 | mgr->ve_binding_lock = FALSE; | ||
303 | } | ||
304 | |||
305 | pipe_resource_reference(&out_buffer, NULL); | ||
306 | } | ||
307 | |||
308 | static void u_vbuf_translate_end(struct u_vbuf_mgr_priv *mgr) | ||
309 | { | ||
310 | if (mgr->fallback_ve == NULL) { | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | /* Restore vertex elements. */ | ||
315 | /* Note that saved_ve will be overwritten in bind_vertex_elements_state. */ | ||
316 | mgr->pipe->bind_vertex_elements_state(mgr->pipe, mgr->saved_ve); | ||
317 | mgr->pipe->delete_vertex_elements_state(mgr->pipe, mgr->fallback_ve); | ||
318 | mgr->fallback_ve = NULL; | ||
319 | |||
320 | /* Delete the now-unused VBO. */ | ||
321 | pipe_resource_reference(&mgr->b.real_vertex_buffer[mgr->translate_vb_slot], | ||
322 | NULL); | ||
323 | mgr->b.nr_real_vertex_buffers = mgr->b.nr_vertex_buffers; | ||
324 | } | ||
325 | |||
326 | #define FORMAT_REPLACE(what, withwhat) \ | ||
327 | case PIPE_FORMAT_##what: format = PIPE_FORMAT_##withwhat; break | ||
328 | |||
329 | struct u_vbuf_mgr_elements * | ||
330 | u_vbuf_mgr_create_vertex_elements(struct u_vbuf_mgr *mgrb, | ||
331 | unsigned count, | ||
332 | const struct pipe_vertex_element *attribs, | ||
333 | struct pipe_vertex_element *native_attribs) | ||
334 | { | ||
335 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
336 | unsigned i; | ||
337 | struct u_vbuf_mgr_elements *ve = CALLOC_STRUCT(u_vbuf_mgr_elements); | ||
338 | |||
339 | ve->count = count; | ||
340 | |||
341 | if (!count) { | ||
342 | return ve; | ||
343 | } | ||
344 | |||
345 | memcpy(ve->ve, attribs, sizeof(struct pipe_vertex_element) * count); | ||
346 | memcpy(native_attribs, attribs, sizeof(struct pipe_vertex_element) * count); | ||
347 | |||
348 | /* Set the best native format in case the original format is not | ||
349 | * supported. */ | ||
350 | for (i = 0; i < count; i++) { | ||
351 | enum pipe_format format = ve->ve[i].src_format; | ||
352 | |||
353 | /* Choose a native format. | ||
354 | * For now we don't care about the alignment, that's going to | ||
355 | * be sorted out later. */ | ||
356 | if (!mgr->caps.format_fixed32) { | ||
357 | switch (format) { | ||
358 | FORMAT_REPLACE(R32_FIXED, R32_FLOAT); | ||
359 | FORMAT_REPLACE(R32G32_FIXED, R32G32_FLOAT); | ||
360 | FORMAT_REPLACE(R32G32B32_FIXED, R32G32B32_FLOAT); | ||
361 | FORMAT_REPLACE(R32G32B32A32_FIXED, R32G32B32A32_FLOAT); | ||
362 | default:; | ||
363 | } | ||
364 | } | ||
365 | if (!mgr->caps.format_float16) { | ||
366 | switch (format) { | ||
367 | FORMAT_REPLACE(R16_FLOAT, R32_FLOAT); | ||
368 | FORMAT_REPLACE(R16G16_FLOAT, R32G32_FLOAT); | ||
369 | FORMAT_REPLACE(R16G16B16_FLOAT, R32G32B32_FLOAT); | ||
370 | FORMAT_REPLACE(R16G16B16A16_FLOAT, R32G32B32A32_FLOAT); | ||
371 | default:; | ||
372 | } | ||
373 | } | ||
374 | if (!mgr->caps.format_float64) { | ||
375 | switch (format) { | ||
376 | FORMAT_REPLACE(R64_FLOAT, R32_FLOAT); | ||
377 | FORMAT_REPLACE(R64G64_FLOAT, R32G32_FLOAT); | ||
378 | FORMAT_REPLACE(R64G64B64_FLOAT, R32G32B32_FLOAT); | ||
379 | FORMAT_REPLACE(R64G64B64A64_FLOAT, R32G32B32A32_FLOAT); | ||
380 | default:; | ||
381 | } | ||
382 | } | ||
383 | if (!mgr->caps.format_norm32) { | ||
384 | switch (format) { | ||
385 | FORMAT_REPLACE(R32_UNORM, R32_FLOAT); | ||
386 | FORMAT_REPLACE(R32G32_UNORM, R32G32_FLOAT); | ||
387 | FORMAT_REPLACE(R32G32B32_UNORM, R32G32B32_FLOAT); | ||
388 | FORMAT_REPLACE(R32G32B32A32_UNORM, R32G32B32A32_FLOAT); | ||
389 | FORMAT_REPLACE(R32_SNORM, R32_FLOAT); | ||
390 | FORMAT_REPLACE(R32G32_SNORM, R32G32_FLOAT); | ||
391 | FORMAT_REPLACE(R32G32B32_SNORM, R32G32B32_FLOAT); | ||
392 | FORMAT_REPLACE(R32G32B32A32_SNORM, R32G32B32A32_FLOAT); | ||
393 | default:; | ||
394 | } | ||
395 | } | ||
396 | if (!mgr->caps.format_scaled32) { | ||
397 | switch (format) { | ||
398 | FORMAT_REPLACE(R32_USCALED, R32_FLOAT); | ||
399 | FORMAT_REPLACE(R32G32_USCALED, R32G32_FLOAT); | ||
400 | FORMAT_REPLACE(R32G32B32_USCALED, R32G32B32_FLOAT); | ||
401 | FORMAT_REPLACE(R32G32B32A32_USCALED,R32G32B32A32_FLOAT); | ||
402 | FORMAT_REPLACE(R32_SSCALED, R32_FLOAT); | ||
403 | FORMAT_REPLACE(R32G32_SSCALED, R32G32_FLOAT); | ||
404 | FORMAT_REPLACE(R32G32B32_SSCALED, R32G32B32_FLOAT); | ||
405 | FORMAT_REPLACE(R32G32B32A32_SSCALED,R32G32B32A32_FLOAT); | ||
406 | default:; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | native_attribs[i].src_format = format; | ||
411 | ve->native_format[i] = format; | ||
412 | ve->native_format_size[i] = | ||
413 | util_format_get_blocksize(ve->native_format[i]); | ||
414 | |||
415 | ve->incompatible_layout = | ||
416 | ve->incompatible_layout || | ||
417 | ve->ve[i].src_format != ve->native_format[i] || | ||
418 | (!mgr->caps.fetch_dword_unaligned && ve->ve[i].src_offset % 4 != 0); | ||
419 | } | ||
420 | |||
421 | /* Align the formats to the size of DWORD if needed. */ | ||
422 | if (!mgr->caps.fetch_dword_unaligned) { | ||
423 | for (i = 0; i < count; i++) { | ||
424 | ve->native_format_size[i] = align(ve->native_format_size[i], 4); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | return ve; | ||
429 | } | ||
430 | |||
431 | void u_vbuf_mgr_bind_vertex_elements(struct u_vbuf_mgr *mgrb, | ||
432 | void *cso, | ||
433 | struct u_vbuf_mgr_elements *ve) | ||
434 | { | ||
435 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
436 | |||
437 | if (!cso) { | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | if (!mgr->ve_binding_lock) { | ||
442 | mgr->saved_ve = cso; | ||
443 | mgr->ve = ve; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | void u_vbuf_mgr_destroy_vertex_elements(struct u_vbuf_mgr *mgr, | ||
448 | struct u_vbuf_mgr_elements *ve) | ||
449 | { | ||
450 | FREE(ve); | ||
451 | } | ||
452 | |||
453 | void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb, | ||
454 | unsigned count, | ||
455 | const struct pipe_vertex_buffer *bufs) | ||
456 | { | ||
457 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
458 | unsigned i; | ||
459 | |||
460 | mgr->b.max_index = ~0; | ||
461 | mgr->any_user_vbs = FALSE; | ||
462 | mgr->incompatible_vb_layout = FALSE; | ||
463 | |||
464 | if (!mgr->caps.fetch_dword_unaligned) { | ||
465 | /* Check if the strides and offsets are aligned to the size of DWORD. */ | ||
466 | for (i = 0; i < count; i++) { | ||
467 | if (bufs[i].buffer) { | ||
468 | if (bufs[i].stride % 4 != 0 || | ||
469 | bufs[i].buffer_offset % 4 != 0) { | ||
470 | mgr->incompatible_vb_layout = TRUE; | ||
471 | break; | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | } | ||
476 | |||
477 | for (i = 0; i < count; i++) { | ||
478 | const struct pipe_vertex_buffer *vb = &bufs[i]; | ||
479 | |||
480 | pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer); | ||
481 | pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL); | ||
482 | |||
483 | if (u_vbuf_resource(vb->buffer)->user_ptr) { | ||
484 | mgr->any_user_vbs = TRUE; | ||
485 | continue; | ||
486 | } | ||
487 | |||
488 | pipe_resource_reference(&mgr->b.real_vertex_buffer[i], vb->buffer); | ||
489 | |||
490 | /* The stride of zero means we will be fetching only the first | ||
491 | * vertex, so don't care about max_index. */ | ||
492 | if (!vb->stride) { | ||
493 | continue; | ||
494 | } | ||
495 | |||
496 | /* Update the maximum index. */ | ||
497 | mgr->b.max_index = | ||
498 | MIN2(mgr->b.max_index, | ||
499 | (vb->buffer->width0 - vb->buffer_offset) / vb->stride); | ||
500 | } | ||
501 | |||
502 | for (; i < mgr->b.nr_real_vertex_buffers; i++) { | ||
503 | pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, NULL); | ||
504 | pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL); | ||
505 | } | ||
506 | |||
507 | memcpy(mgr->b.vertex_buffer, bufs, | ||
508 | sizeof(struct pipe_vertex_buffer) * count); | ||
509 | |||
510 | mgr->b.nr_vertex_buffers = count; | ||
511 | mgr->b.nr_real_vertex_buffers = count; | ||
512 | } | ||
513 | |||
514 | static void u_vbuf_upload_buffers(struct u_vbuf_mgr_priv *mgr, | ||
515 | int min_index, int max_index, | ||
516 | boolean *upload_flushed) | ||
517 | { | ||
518 | int i, nr = mgr->ve->count; | ||
519 | unsigned count = max_index + 1 - min_index; | ||
520 | boolean uploaded[PIPE_MAX_ATTRIBS] = {0}; | ||
521 | |||
522 | for (i = 0; i < nr; i++) { | ||
523 | unsigned index = mgr->ve->ve[i].vertex_buffer_index; | ||
524 | struct pipe_vertex_buffer *vb = &mgr->b.vertex_buffer[index]; | ||
525 | |||
526 | if (vb->buffer && | ||
527 | u_vbuf_resource(vb->buffer)->user_ptr && | ||
528 | !uploaded[index]) { | ||
529 | unsigned first, size; | ||
530 | boolean flushed; | ||
531 | |||
532 | if (vb->stride) { | ||
533 | first = vb->stride * min_index; | ||
534 | size = vb->stride * count; | ||
535 | } else { | ||
536 | first = 0; | ||
537 | size = mgr->ve->native_format_size[i]; | ||
538 | } | ||
539 | |||
540 | u_upload_data(mgr->uploader, first, size, | ||
541 | u_vbuf_resource(vb->buffer)->user_ptr + first, | ||
542 | &vb->buffer_offset, | ||
543 | &mgr->b.real_vertex_buffer[index], | ||
544 | &flushed); | ||
545 | |||
546 | vb->buffer_offset -= first; | ||
547 | |||
548 | uploaded[index] = TRUE; | ||
549 | *upload_flushed = *upload_flushed || flushed; | ||
550 | } else { | ||
551 | assert(mgr->b.real_vertex_buffer[index]); | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb, | ||
557 | const struct pipe_draw_info *info, | ||
558 | boolean *buffers_updated, | ||
559 | boolean *uploader_flushed) | ||
560 | { | ||
561 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
562 | boolean bufs_updated, upload_flushed = FALSE; | ||
563 | int min_index, max_index; | ||
564 | |||
565 | min_index = info->min_index - info->index_bias; | ||
566 | max_index = MIN2(info->max_index, mgr->b.max_index) - info->index_bias; | ||
567 | |||
568 | /* Translate vertices with non-native layouts or formats. */ | ||
569 | if (mgr->incompatible_vb_layout || mgr->ve->incompatible_layout) { | ||
570 | u_vbuf_translate_begin(mgr, min_index, max_index, &upload_flushed); | ||
571 | |||
572 | if (mgr->fallback_ve) { | ||
573 | bufs_updated = TRUE; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | /* Upload user buffers. */ | ||
578 | if (mgr->any_user_vbs) { | ||
579 | u_vbuf_upload_buffers(mgr, min_index, max_index, &upload_flushed); | ||
580 | bufs_updated = TRUE; | ||
581 | } | ||
582 | |||
583 | /* Set the return values. */ | ||
584 | if (buffers_updated) { | ||
585 | *buffers_updated = bufs_updated; | ||
586 | } | ||
587 | if (uploader_flushed) { | ||
588 | *uploader_flushed = upload_flushed; | ||
589 | } | ||
590 | } | ||
591 | |||
592 | void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgrb) | ||
593 | { | ||
594 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
595 | |||
596 | if (mgr->fallback_ve) { | ||
597 | u_vbuf_translate_end(mgr); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | void u_vbuf_mgr_flush_uploader(struct u_vbuf_mgr *mgrb) | ||
602 | { | ||
603 | struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb; | ||
604 | |||
605 | u_upload_flush(mgr->uploader); | ||
606 | } | ||
diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.h b/src/gallium/auxiliary/util/u_vbuf_mgr.h new file mode 100644 index 00000000000..5eb59385f9b --- /dev/null +++ b/src/gallium/auxiliary/util/u_vbuf_mgr.h | |||
@@ -0,0 +1,113 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright 2011 Marek Olšák <maraeo@gmail.com> | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
21 | * IN NO EVENT SHALL AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR | ||
22 | * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | |||
28 | #ifndef U_VBUF_MGR_H | ||
29 | #define U_VBUF_MGR_H | ||
30 | |||
31 | /* This module builds upon u_upload_mgr and translate_cache and takes care of | ||
32 | * user buffer uploads and vertex format fallbacks. It's designed | ||
33 | * for the drivers which don't always use the Draw module. (e.g. for HWTCL) | ||
34 | */ | ||
35 | |||
36 | #include "pipe/p_context.h" | ||
37 | #include "pipe/p_state.h" | ||
38 | #include "util/u_transfer.h" | ||
39 | |||
40 | /* The manager. | ||
41 | * This structure should also be used to access vertex buffers | ||
42 | * from a driver. */ | ||
43 | struct u_vbuf_mgr { | ||
44 | /* This is what was set in set_vertex_buffers. | ||
45 | * May contain user buffers. */ | ||
46 | struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS]; | ||
47 | unsigned nr_vertex_buffers; | ||
48 | |||
49 | /* Contains only real vertex buffers. | ||
50 | * Hardware drivers should use real_vertex_buffers[i] | ||
51 | * instead of vertex_buffers[i].buffer. */ | ||
52 | struct pipe_resource *real_vertex_buffer[PIPE_MAX_ATTRIBS]; | ||
53 | int nr_real_vertex_buffers; | ||
54 | |||
55 | /* Precomputed max_index for hardware vertex buffers. */ | ||
56 | int max_index; | ||
57 | }; | ||
58 | |||
59 | struct u_vbuf_resource { | ||
60 | struct u_resource b; | ||
61 | uint8_t *user_ptr; | ||
62 | }; | ||
63 | |||
64 | /* Opaque type containing information about vertex elements for the manager. */ | ||
65 | struct u_vbuf_mgr_elements; | ||
66 | |||
67 | enum u_fetch_alignment { | ||
68 | U_VERTEX_FETCH_BYTE_ALIGNED, | ||
69 | U_VERTEX_FETCH_DWORD_ALIGNED | ||
70 | }; | ||
71 | |||
72 | |||
73 | struct u_vbuf_mgr * | ||
74 | u_vbuf_mgr_create(struct pipe_context *pipe, | ||
75 | unsigned upload_buffer_size, | ||
76 | unsigned upload_buffer_alignment, | ||
77 | enum u_fetch_alignment fetch_alignment); | ||
78 | |||
79 | void u_vbuf_mgr_destroy(struct u_vbuf_mgr *mgr); | ||
80 | |||
81 | struct u_vbuf_mgr_elements * | ||
82 | u_vbuf_mgr_create_vertex_elements(struct u_vbuf_mgr *mgr, | ||
83 | unsigned count, | ||
84 | const struct pipe_vertex_element *attrs, | ||
85 | struct pipe_vertex_element *native_attrs); | ||
86 | |||
87 | void u_vbuf_mgr_bind_vertex_elements(struct u_vbuf_mgr *mgr, | ||
88 | void *cso, | ||
89 | struct u_vbuf_mgr_elements *ve); | ||
90 | |||
91 | void u_vbuf_mgr_destroy_vertex_elements(struct u_vbuf_mgr *mgr, | ||
92 | struct u_vbuf_mgr_elements *ve); | ||
93 | |||
94 | void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgr, | ||
95 | unsigned count, | ||
96 | const struct pipe_vertex_buffer *bufs); | ||
97 | |||
98 | void u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgr, | ||
99 | const struct pipe_draw_info *info, | ||
100 | boolean *buffers_updated, | ||
101 | boolean *uploader_flushed); | ||
102 | |||
103 | void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgr); | ||
104 | |||
105 | void u_vbuf_mgr_flush_uploader(struct u_vbuf_mgr *mgr); | ||
106 | |||
107 | |||
108 | static INLINE struct u_vbuf_resource *u_vbuf_resource(struct pipe_resource *r) | ||
109 | { | ||
110 | return (struct u_vbuf_resource*)r; | ||
111 | } | ||
112 | |||
113 | #endif | ||