Merge branch 'gallium-0.1' into gallium-tex-surfaces
[mesa.git] / src / gallium / auxiliary / draw / draw_pipe_vbuf.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 /**
29 * \file
30 * Vertex buffer drawing stage.
31 *
32 * \author José Fonseca <jrfonsec@tungstengraphics.com>
33 * \author Keith Whitwell <keith@tungstengraphics.com>
34 */
35
36
37 #include "pipe/p_debug.h"
38 #include "pipe/p_util.h"
39
40 #include "draw_vbuf.h"
41 #include "draw_private.h"
42 #include "draw_vertex.h"
43 #include "draw_pipe.h"
44 #include "translate/translate.h"
45 #include "translate/translate_cache.h"
46
47
48 /**
49 * Vertex buffer emit stage.
50 */
51 struct vbuf_stage {
52 struct draw_stage stage; /**< This must be first (base class) */
53
54 struct vbuf_render *render;
55
56 const struct vertex_info *vinfo;
57
58 /** Vertex size in bytes */
59 unsigned vertex_size;
60
61 struct translate *translate;
62
63 /* FIXME: we have no guarantee that 'unsigned' is 32bit */
64
65 /** Vertices in hardware format */
66 unsigned *vertices;
67 unsigned *vertex_ptr;
68 unsigned max_vertices;
69 unsigned nr_vertices;
70
71 /** Indices */
72 ushort *indices;
73 unsigned max_indices;
74 unsigned nr_indices;
75
76 /* Cache point size somewhere it's address won't change:
77 */
78 float point_size;
79
80 struct translate_cache *cache;
81 };
82
83
84 /**
85 * Basically a cast wrapper.
86 */
87 static INLINE struct vbuf_stage *
88 vbuf_stage( struct draw_stage *stage )
89 {
90 assert(stage);
91 return (struct vbuf_stage *)stage;
92 }
93
94
95 static void vbuf_flush_indices( struct vbuf_stage *vbuf );
96 static void vbuf_flush_vertices( struct vbuf_stage *vbuf );
97 static void vbuf_alloc_vertices( struct vbuf_stage *vbuf );
98
99
100 static INLINE boolean
101 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
102 {
103 unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
104 return (used + bytes) > bufsz;
105 }
106
107
108 static INLINE void
109 check_space( struct vbuf_stage *vbuf, unsigned nr )
110 {
111 if (vbuf->nr_vertices + nr > vbuf->max_vertices ) {
112 vbuf_flush_vertices(vbuf);
113 vbuf_alloc_vertices(vbuf);
114 }
115
116 if (vbuf->nr_indices + nr > vbuf->max_indices )
117 vbuf_flush_indices(vbuf);
118 }
119
120
121
122
123 /**
124 * Extract the needed fields from post-transformed vertex and emit
125 * a hardware(driver) vertex.
126 * Recall that the vertices are constructed by the 'draw' module and
127 * have a couple of slots at the beginning (1-dword header, 4-dword
128 * clip pos) that we ignore here. We only use the vertex->data[] fields.
129 */
130 static INLINE ushort
131 emit_vertex( struct vbuf_stage *vbuf,
132 struct vertex_header *vertex )
133 {
134 if(vertex->vertex_id == UNDEFINED_VERTEX_ID) {
135 /* Hmm - vertices are emitted one at a time - better make sure
136 * set_buffer is efficient. Consider a special one-shot mode for
137 * translate.
138 */
139 vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0);
140 vbuf->translate->run(vbuf->translate, 0, 1, vbuf->vertex_ptr);
141
142 if (0) draw_dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
143
144 vbuf->vertex_ptr += vbuf->vertex_size/4;
145 vertex->vertex_id = vbuf->nr_vertices++;
146 }
147
148 return vertex->vertex_id;
149 }
150
151
152 static void
153 vbuf_tri( struct draw_stage *stage,
154 struct prim_header *prim )
155 {
156 struct vbuf_stage *vbuf = vbuf_stage( stage );
157 unsigned i;
158
159 check_space( vbuf, 3 );
160
161 for (i = 0; i < 3; i++) {
162 vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
163 }
164 }
165
166
167 static void
168 vbuf_line( struct draw_stage *stage,
169 struct prim_header *prim )
170 {
171 struct vbuf_stage *vbuf = vbuf_stage( stage );
172 unsigned i;
173
174 check_space( vbuf, 2 );
175
176 for (i = 0; i < 2; i++) {
177 vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
178 }
179 }
180
181
182 static void
183 vbuf_point( struct draw_stage *stage,
184 struct prim_header *prim )
185 {
186 struct vbuf_stage *vbuf = vbuf_stage( stage );
187
188 check_space( vbuf, 1 );
189
190 vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
191 }
192
193
194
195
196 /**
197 * Set the prim type for subsequent vertices.
198 * This may result in a new vertex size. The existing vbuffer (if any)
199 * will be flushed if needed and a new one allocated.
200 */
201 static void
202 vbuf_set_prim( struct vbuf_stage *vbuf, uint prim )
203 {
204 struct translate_key hw_key;
205 unsigned dst_offset;
206 unsigned i;
207
208 vbuf->render->set_primitive(vbuf->render, prim);
209
210 /* Must do this after set_primitive() above:
211 *
212 * XXX: need some state managment to track when this needs to be
213 * recalculated. The driver should tell us whether there was a
214 * state change.
215 */
216 vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
217
218 if (vbuf->vertex_size != vbuf->vinfo->size * sizeof(float)) {
219 vbuf_flush_vertices(vbuf);
220 vbuf->vertex_size = vbuf->vinfo->size * sizeof(float);
221 }
222
223 /* Translate from pipeline vertices to hw vertices.
224 */
225 dst_offset = 0;
226
227 for (i = 0; i < vbuf->vinfo->num_attribs; i++) {
228 unsigned emit_sz = 0;
229 unsigned src_buffer = 0;
230 unsigned output_format;
231 unsigned src_offset = (vbuf->vinfo->src_index[i] * 4 * sizeof(float) );
232
233 switch (vbuf->vinfo->emit[i]) {
234 case EMIT_4F:
235 output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
236 emit_sz = 4 * sizeof(float);
237 break;
238 case EMIT_3F:
239 output_format = PIPE_FORMAT_R32G32B32_FLOAT;
240 emit_sz = 3 * sizeof(float);
241 break;
242 case EMIT_2F:
243 output_format = PIPE_FORMAT_R32G32_FLOAT;
244 emit_sz = 2 * sizeof(float);
245 break;
246 case EMIT_1F:
247 output_format = PIPE_FORMAT_R32_FLOAT;
248 emit_sz = 1 * sizeof(float);
249 break;
250 case EMIT_1F_PSIZE:
251 output_format = PIPE_FORMAT_R32_FLOAT;
252 emit_sz = 1 * sizeof(float);
253 src_buffer = 1;
254 src_offset = 0;
255 break;
256 case EMIT_4UB:
257 output_format = PIPE_FORMAT_B8G8R8A8_UNORM;
258 emit_sz = 4 * sizeof(ubyte);
259 break;
260 default:
261 assert(0);
262 output_format = PIPE_FORMAT_NONE;
263 emit_sz = 0;
264 break;
265 }
266
267 hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
268 hw_key.element[i].input_buffer = src_buffer;
269 hw_key.element[i].input_offset = src_offset;
270 hw_key.element[i].output_format = output_format;
271 hw_key.element[i].output_offset = dst_offset;
272
273 dst_offset += emit_sz;
274 }
275
276 hw_key.nr_elements = vbuf->vinfo->num_attribs;
277 hw_key.output_stride = vbuf->vinfo->size * 4;
278
279 /* Don't bother with caching at this stage:
280 */
281 if (!vbuf->translate ||
282 translate_key_compare(&vbuf->translate->key, &hw_key) != 0)
283 {
284 translate_key_sanitize(&hw_key);
285 vbuf->translate = translate_cache_find(vbuf->cache, &hw_key);
286
287 vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0);
288 }
289
290 vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
291
292 /* Allocate new buffer?
293 */
294 if (!vbuf->vertices)
295 vbuf_alloc_vertices(vbuf);
296 }
297
298
299 static void
300 vbuf_first_tri( struct draw_stage *stage,
301 struct prim_header *prim )
302 {
303 struct vbuf_stage *vbuf = vbuf_stage( stage );
304
305 vbuf_flush_indices( vbuf );
306 stage->tri = vbuf_tri;
307 vbuf_set_prim(vbuf, PIPE_PRIM_TRIANGLES);
308 stage->tri( stage, prim );
309 }
310
311
312 static void
313 vbuf_first_line( struct draw_stage *stage,
314 struct prim_header *prim )
315 {
316 struct vbuf_stage *vbuf = vbuf_stage( stage );
317
318 vbuf_flush_indices( vbuf );
319 stage->line = vbuf_line;
320 vbuf_set_prim(vbuf, PIPE_PRIM_LINES);
321 stage->line( stage, prim );
322 }
323
324
325 static void
326 vbuf_first_point( struct draw_stage *stage,
327 struct prim_header *prim )
328 {
329 struct vbuf_stage *vbuf = vbuf_stage( stage );
330
331 vbuf_flush_indices( vbuf );
332 stage->point = vbuf_point;
333 vbuf_set_prim(vbuf, PIPE_PRIM_POINTS);
334 stage->point( stage, prim );
335 }
336
337
338 static void
339 vbuf_flush_indices( struct vbuf_stage *vbuf )
340 {
341 if(!vbuf->nr_indices)
342 return;
343
344 assert((uint) (vbuf->vertex_ptr - vbuf->vertices) ==
345 vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
346
347 vbuf->render->draw(vbuf->render, vbuf->indices, vbuf->nr_indices);
348
349 vbuf->nr_indices = 0;
350 }
351
352
353 /**
354 * Flush existing vertex buffer and allocate a new one.
355 *
356 * XXX: We separate flush-on-index-full and flush-on-vb-full, but may
357 * raise issues uploading vertices if the hardware wants to flush when
358 * we flush.
359 */
360 static void
361 vbuf_flush_vertices( struct vbuf_stage *vbuf )
362 {
363 if(vbuf->vertices) {
364 vbuf_flush_indices(vbuf);
365
366 /* Reset temporary vertices ids */
367 if(vbuf->nr_vertices)
368 draw_reset_vertex_ids( vbuf->stage.draw );
369
370 /* Free the vertex buffer */
371 vbuf->render->release_vertices(vbuf->render,
372 vbuf->vertices,
373 vbuf->vertex_size,
374 vbuf->nr_vertices);
375 vbuf->max_vertices = vbuf->nr_vertices = 0;
376 vbuf->vertex_ptr = vbuf->vertices = NULL;
377
378 }
379 }
380
381
382 static void
383 vbuf_alloc_vertices( struct vbuf_stage *vbuf )
384 {
385 assert(!vbuf->nr_indices);
386 assert(!vbuf->vertices);
387
388 /* Allocate a new vertex buffer */
389 vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
390 vbuf->vertices = (uint *) vbuf->render->allocate_vertices(vbuf->render,
391 (ushort) vbuf->vertex_size,
392 (ushort) vbuf->max_vertices);
393 vbuf->vertex_ptr = vbuf->vertices;
394 }
395
396
397
398 static void
399 vbuf_flush( struct draw_stage *stage, unsigned flags )
400 {
401 struct vbuf_stage *vbuf = vbuf_stage( stage );
402
403 vbuf_flush_indices( vbuf );
404
405 stage->point = vbuf_first_point;
406 stage->line = vbuf_first_line;
407 stage->tri = vbuf_first_tri;
408
409 if (flags & DRAW_FLUSH_BACKEND)
410 vbuf_flush_vertices( vbuf );
411 }
412
413
414 static void
415 vbuf_reset_stipple_counter( struct draw_stage *stage )
416 {
417 /* XXX: Need to do something here for hardware with linestipple.
418 */
419 (void) stage;
420 }
421
422
423 static void vbuf_destroy( struct draw_stage *stage )
424 {
425 struct vbuf_stage *vbuf = vbuf_stage( stage );
426
427 if(vbuf->indices)
428 align_free( vbuf->indices );
429
430 if (vbuf->render)
431 vbuf->render->destroy( vbuf->render );
432
433 if (vbuf->cache)
434 translate_cache_destroy(vbuf->cache);
435
436 FREE( stage );
437 }
438
439
440 /**
441 * Create a new primitive vbuf/render stage.
442 */
443 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
444 struct vbuf_render *render )
445 {
446 struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
447 if (vbuf == NULL)
448 goto fail;
449
450 vbuf->stage.draw = draw;
451 vbuf->stage.point = vbuf_first_point;
452 vbuf->stage.line = vbuf_first_line;
453 vbuf->stage.tri = vbuf_first_tri;
454 vbuf->stage.flush = vbuf_flush;
455 vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
456 vbuf->stage.destroy = vbuf_destroy;
457
458 vbuf->render = render;
459 vbuf->max_indices = MAX2(render->max_indices, UNDEFINED_VERTEX_ID-1);
460
461 vbuf->indices = (ushort *) align_malloc( vbuf->max_indices *
462 sizeof(vbuf->indices[0]),
463 16 );
464 if (!vbuf->indices)
465 goto fail;
466
467 vbuf->cache = translate_cache_create();
468 if (!vbuf->cache)
469 goto fail;
470
471
472 vbuf->vertices = NULL;
473 vbuf->vertex_ptr = vbuf->vertices;
474
475 return &vbuf->stage;
476
477 fail:
478 if (vbuf)
479 vbuf_destroy(&vbuf->stage);
480
481 return NULL;
482 }