Code reorganization: placeholder for state-trackers.
[mesa.git] / src / gallium / aux / draw / draw_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_vf.h"
44
45
46 /**
47 * Vertex buffer emit stage.
48 */
49 struct vbuf_stage {
50 struct draw_stage stage; /**< This must be first (base class) */
51
52 struct vbuf_render *render;
53
54 const struct vertex_info *vinfo;
55
56 /** Vertex size in bytes */
57 unsigned vertex_size;
58
59 struct draw_vertex_fetch *vf;
60
61 /* FIXME: we have no guarantee that 'unsigned' is 32bit */
62
63 /** Vertices in hardware format */
64 unsigned *vertices;
65 unsigned *vertex_ptr;
66 unsigned max_vertices;
67 unsigned nr_vertices;
68
69 /** Indices */
70 ushort *indices;
71 unsigned max_indices;
72 unsigned nr_indices;
73
74 /** Pipe primitive */
75 unsigned prim;
76 };
77
78
79 /**
80 * Basically a cast wrapper.
81 */
82 static INLINE struct vbuf_stage *
83 vbuf_stage( struct draw_stage *stage )
84 {
85 assert(stage);
86 return (struct vbuf_stage *)stage;
87 }
88
89
90 static void vbuf_flush_indices( struct vbuf_stage *vbuf );
91 static void vbuf_flush_vertices( struct vbuf_stage *vbuf );
92 static void vbuf_alloc_vertices( struct vbuf_stage *vbuf );
93
94
95 static INLINE boolean
96 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
97 {
98 unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
99 return (used + bytes) > bufsz;
100 }
101
102
103 static INLINE void
104 check_space( struct vbuf_stage *vbuf, unsigned nr )
105 {
106 if (vbuf->nr_vertices + nr > vbuf->max_vertices ) {
107 vbuf_flush_vertices(vbuf);
108 vbuf_alloc_vertices(vbuf);
109 }
110
111 if (vbuf->nr_indices + nr > vbuf->max_indices )
112 vbuf_flush_indices(vbuf);
113 }
114
115
116 #if 0
117 static INLINE void
118 dump_emitted_vertex(const struct vertex_info *vinfo, const uint8_t *data)
119 {
120 assert(vinfo == vbuf->render->get_vertex_info(vbuf->render));
121 unsigned i, j, k;
122
123 for (i = 0; i < vinfo->num_attribs; i++) {
124 j = vinfo->src_index[i];
125 switch (vinfo->emit[i]) {
126 case EMIT_OMIT:
127 debug_printf("EMIT_OMIT:");
128 break;
129 case EMIT_ALL:
130 assert(i == 0);
131 assert(j == 0);
132 debug_printf("EMIT_ALL:\t");
133 for(k = 0; k < vinfo->size*4; ++k)
134 debug_printf("%02x ", *data++);
135 break;
136 case EMIT_1F:
137 debug_printf("EMIT_1F:\t");
138 debug_printf("%f ", *(float *)data); data += sizeof(float);
139 break;
140 case EMIT_1F_PSIZE:
141 debug_printf("EMIT_1F_PSIZE:\t");
142 debug_printf("%f ", *(float *)data); data += sizeof(float);
143 break;
144 case EMIT_2F:
145 debug_printf("EMIT_2F:\t");
146 debug_printf("%f ", *(float *)data); data += sizeof(float);
147 debug_printf("%f ", *(float *)data); data += sizeof(float);
148 break;
149 case EMIT_3F:
150 debug_printf("EMIT_3F:\t");
151 debug_printf("%f ", *(float *)data); data += sizeof(float);
152 debug_printf("%f ", *(float *)data); data += sizeof(float);
153 debug_printf("%f ", *(float *)data); data += sizeof(float);
154 data += sizeof(float);
155 break;
156 case EMIT_4F:
157 debug_printf("EMIT_4F:\t");
158 debug_printf("%f ", *(float *)data); data += sizeof(float);
159 debug_printf("%f ", *(float *)data); data += sizeof(float);
160 debug_printf("%f ", *(float *)data); data += sizeof(float);
161 debug_printf("%f ", *(float *)data); data += sizeof(float);
162 break;
163 case EMIT_4UB:
164 debug_printf("EMIT_4UB:\t");
165 debug_printf("%u ", *data++);
166 debug_printf("%u ", *data++);
167 debug_printf("%u ", *data++);
168 debug_printf("%u ", *data++);
169 break;
170 default:
171 assert(0);
172 }
173 debug_printf("\n");
174 }
175 debug_printf("\n");
176 }
177 #endif
178
179
180 /**
181 * Extract the needed fields from post-transformed vertex and emit
182 * a hardware(driver) vertex.
183 * Recall that the vertices are constructed by the 'draw' module and
184 * have a couple of slots at the beginning (1-dword header, 4-dword
185 * clip pos) that we ignore here. We only use the vertex->data[] fields.
186 */
187 static INLINE void
188 emit_vertex( struct vbuf_stage *vbuf,
189 struct vertex_header *vertex )
190 {
191 #if 0
192 debug_printf("emit vertex %d to %p\n",
193 vbuf->nr_vertices, vbuf->vertex_ptr);
194 #endif
195
196 if(vertex->vertex_id != UNDEFINED_VERTEX_ID) {
197 if(vertex->vertex_id < vbuf->nr_vertices)
198 return;
199 else
200 debug_printf("Bad vertex id 0x%04x (>= 0x%04x)\n",
201 vertex->vertex_id, vbuf->nr_vertices);
202 return;
203 }
204
205 vertex->vertex_id = vbuf->nr_vertices++;
206
207 if(!vbuf->vf) {
208 const struct vertex_info *vinfo = vbuf->vinfo;
209 uint i;
210 uint count = 0; /* for debug/sanity */
211
212 assert(vinfo == vbuf->render->get_vertex_info(vbuf->render));
213
214 for (i = 0; i < vinfo->num_attribs; i++) {
215 uint j = vinfo->src_index[i];
216 switch (vinfo->emit[i]) {
217 case EMIT_OMIT:
218 /* no-op */
219 break;
220 case EMIT_ALL:
221 /* just copy the whole vertex as-is to the vbuf */
222 assert(i == 0);
223 assert(j == 0);
224 memcpy(vbuf->vertex_ptr, vertex, vinfo->size * 4);
225 vbuf->vertex_ptr += vinfo->size;
226 count += vinfo->size;
227 break;
228 case EMIT_1F:
229 *vbuf->vertex_ptr++ = fui(vertex->data[j][0]);
230 count++;
231 break;
232 case EMIT_1F_PSIZE:
233 *vbuf->vertex_ptr++ = fui(vbuf->stage.draw->rasterizer->point_size);
234 count++;
235 break;
236 case EMIT_2F:
237 *vbuf->vertex_ptr++ = fui(vertex->data[j][0]);
238 *vbuf->vertex_ptr++ = fui(vertex->data[j][1]);
239 count += 2;
240 break;
241 case EMIT_3F:
242 *vbuf->vertex_ptr++ = fui(vertex->data[j][0]);
243 *vbuf->vertex_ptr++ = fui(vertex->data[j][1]);
244 *vbuf->vertex_ptr++ = fui(vertex->data[j][2]);
245 count += 3;
246 break;
247 case EMIT_4F:
248 *vbuf->vertex_ptr++ = fui(vertex->data[j][0]);
249 *vbuf->vertex_ptr++ = fui(vertex->data[j][1]);
250 *vbuf->vertex_ptr++ = fui(vertex->data[j][2]);
251 *vbuf->vertex_ptr++ = fui(vertex->data[j][3]);
252 count += 4;
253 break;
254 case EMIT_4UB:
255 *vbuf->vertex_ptr++ = pack_ub4(float_to_ubyte( vertex->data[j][2] ),
256 float_to_ubyte( vertex->data[j][1] ),
257 float_to_ubyte( vertex->data[j][0] ),
258 float_to_ubyte( vertex->data[j][3] ));
259 count += 1;
260 break;
261 default:
262 assert(0);
263 }
264 }
265 assert(count == vinfo->size);
266 #if 0
267 {
268 static float data[256];
269 draw_vf_emit_vertex(vbuf->vf, vertex, data);
270 if(memcmp((uint8_t *)vbuf->vertex_ptr - vbuf->vertex_size, data, vbuf->vertex_size)) {
271 debug_printf("With VF:\n");
272 dump_emitted_vertex(vbuf->vinfo, (uint8_t *)data);
273 debug_printf("Without VF:\n");
274 dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr - vbuf->vertex_size);
275 assert(0);
276 }
277 }
278 #endif
279 }
280 else {
281 draw_vf_emit_vertex(vbuf->vf, vertex, vbuf->vertex_ptr);
282
283 vbuf->vertex_ptr += vbuf->vertex_size/4;
284 }
285 }
286
287
288 static void
289 vbuf_tri( struct draw_stage *stage,
290 struct prim_header *prim )
291 {
292 struct vbuf_stage *vbuf = vbuf_stage( stage );
293 unsigned i;
294
295 check_space( vbuf, 3 );
296
297 for (i = 0; i < 3; i++) {
298 emit_vertex( vbuf, prim->v[i] );
299
300 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
301 }
302 }
303
304
305 static void
306 vbuf_line( struct draw_stage *stage,
307 struct prim_header *prim )
308 {
309 struct vbuf_stage *vbuf = vbuf_stage( stage );
310 unsigned i;
311
312 check_space( vbuf, 2 );
313
314 for (i = 0; i < 2; i++) {
315 emit_vertex( vbuf, prim->v[i] );
316
317 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
318 }
319 }
320
321
322 static void
323 vbuf_point( struct draw_stage *stage,
324 struct prim_header *prim )
325 {
326 struct vbuf_stage *vbuf = vbuf_stage( stage );
327
328 check_space( vbuf, 1 );
329
330 emit_vertex( vbuf, prim->v[0] );
331
332 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[0]->vertex_id;
333 }
334
335
336 /**
337 * Set the prim type for subsequent vertices.
338 * This may result in a new vertex size. The existing vbuffer (if any)
339 * will be flushed if needed and a new one allocated.
340 */
341 static void
342 vbuf_set_prim( struct vbuf_stage *vbuf, uint newprim )
343 {
344 const struct vertex_info *vinfo;
345 unsigned vertex_size;
346
347 assert(newprim == PIPE_PRIM_POINTS ||
348 newprim == PIPE_PRIM_LINES ||
349 newprim == PIPE_PRIM_TRIANGLES);
350
351 vbuf->prim = newprim;
352 vbuf->render->set_primitive(vbuf->render, newprim);
353
354 vinfo = vbuf->render->get_vertex_info(vbuf->render);
355 vertex_size = vinfo->size * sizeof(float);
356
357 if (vertex_size != vbuf->vertex_size)
358 vbuf_flush_vertices(vbuf);
359
360 vbuf->vinfo = vinfo;
361 vbuf->vertex_size = vertex_size;
362 if(vbuf->vf)
363 draw_vf_set_vertex_info(vbuf->vf,
364 vbuf->vinfo,
365 vbuf->stage.draw->rasterizer->point_size);
366
367 if (!vbuf->vertices)
368 vbuf_alloc_vertices(vbuf);
369 }
370
371
372 static void
373 vbuf_first_tri( struct draw_stage *stage,
374 struct prim_header *prim )
375 {
376 struct vbuf_stage *vbuf = vbuf_stage( stage );
377
378 vbuf_flush_indices( vbuf );
379 stage->tri = vbuf_tri;
380 vbuf_set_prim(vbuf, PIPE_PRIM_TRIANGLES);
381 stage->tri( stage, prim );
382 }
383
384
385 static void
386 vbuf_first_line( struct draw_stage *stage,
387 struct prim_header *prim )
388 {
389 struct vbuf_stage *vbuf = vbuf_stage( stage );
390
391 vbuf_flush_indices( vbuf );
392 stage->line = vbuf_line;
393 vbuf_set_prim(vbuf, PIPE_PRIM_LINES);
394 stage->line( stage, prim );
395 }
396
397
398 static void
399 vbuf_first_point( struct draw_stage *stage,
400 struct prim_header *prim )
401 {
402 struct vbuf_stage *vbuf = vbuf_stage( stage );
403
404 vbuf_flush_indices( vbuf );
405 stage->point = vbuf_point;
406 vbuf_set_prim(vbuf, PIPE_PRIM_POINTS);
407 stage->point( stage, prim );
408 }
409
410
411 static void
412 vbuf_flush_indices( struct vbuf_stage *vbuf )
413 {
414 if(!vbuf->nr_indices)
415 return;
416
417 assert((uint) (vbuf->vertex_ptr - vbuf->vertices) ==
418 vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
419
420 switch(vbuf->prim) {
421 case PIPE_PRIM_POINTS:
422 break;
423 case PIPE_PRIM_LINES:
424 assert(vbuf->nr_indices % 2 == 0);
425 break;
426 case PIPE_PRIM_TRIANGLES:
427 assert(vbuf->nr_indices % 3 == 0);
428 break;
429 default:
430 assert(0);
431 }
432
433 vbuf->render->draw(vbuf->render, vbuf->indices, vbuf->nr_indices);
434
435 vbuf->nr_indices = 0;
436
437 /* don't need to reset point/line/tri functions */
438 #if 0
439 stage->point = vbuf_first_point;
440 stage->line = vbuf_first_line;
441 stage->tri = vbuf_first_tri;
442 #endif
443 }
444
445
446 /**
447 * Flush existing vertex buffer and allocate a new one.
448 *
449 * XXX: We separate flush-on-index-full and flush-on-vb-full, but may
450 * raise issues uploading vertices if the hardware wants to flush when
451 * we flush.
452 */
453 static void
454 vbuf_flush_vertices( struct vbuf_stage *vbuf )
455 {
456 if(vbuf->vertices) {
457 vbuf_flush_indices(vbuf);
458
459 /* Reset temporary vertices ids */
460 if(vbuf->nr_vertices)
461 draw_reset_vertex_ids( vbuf->stage.draw );
462
463 /* Free the vertex buffer */
464 vbuf->render->release_vertices(vbuf->render,
465 vbuf->vertices,
466 vbuf->vertex_size,
467 vbuf->nr_vertices);
468 vbuf->max_vertices = vbuf->nr_vertices = 0;
469 vbuf->vertex_ptr = vbuf->vertices = NULL;
470
471 }
472 }
473
474
475 static void
476 vbuf_alloc_vertices( struct vbuf_stage *vbuf )
477 {
478 assert(!vbuf->nr_indices);
479 assert(!vbuf->vertices);
480
481 /* Allocate a new vertex buffer */
482 vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
483 vbuf->vertices = (uint *) vbuf->render->allocate_vertices(vbuf->render,
484 (ushort) vbuf->vertex_size,
485 (ushort) vbuf->max_vertices);
486 vbuf->vertex_ptr = vbuf->vertices;
487 }
488
489
490
491 static void
492 vbuf_flush( struct draw_stage *stage, unsigned flags )
493 {
494 struct vbuf_stage *vbuf = vbuf_stage( stage );
495
496 vbuf_flush_indices( vbuf );
497
498 stage->point = vbuf_first_point;
499 stage->line = vbuf_first_line;
500 stage->tri = vbuf_first_tri;
501
502 if (flags & DRAW_FLUSH_BACKEND)
503 vbuf_flush_vertices( vbuf );
504 }
505
506
507 static void
508 vbuf_reset_stipple_counter( struct draw_stage *stage )
509 {
510 /* XXX: Need to do something here for hardware with linestipple.
511 */
512 (void) stage;
513 }
514
515
516 static void vbuf_destroy( struct draw_stage *stage )
517 {
518 struct vbuf_stage *vbuf = vbuf_stage( stage );
519
520 if(vbuf->indices)
521 align_free( vbuf->indices );
522
523 if(vbuf->vf)
524 draw_vf_destroy( vbuf->vf );
525
526 if (vbuf->render)
527 vbuf->render->destroy( vbuf->render );
528
529 FREE( stage );
530 }
531
532
533 /**
534 * Create a new primitive vbuf/render stage.
535 */
536 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
537 struct vbuf_render *render )
538 {
539 struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
540
541 if(!vbuf)
542 return NULL;
543
544 vbuf->stage.draw = draw;
545 vbuf->stage.point = vbuf_first_point;
546 vbuf->stage.line = vbuf_first_line;
547 vbuf->stage.tri = vbuf_first_tri;
548 vbuf->stage.flush = vbuf_flush;
549 vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
550 vbuf->stage.destroy = vbuf_destroy;
551
552 vbuf->render = render;
553
554 assert(render->max_indices < UNDEFINED_VERTEX_ID);
555 vbuf->max_indices = render->max_indices;
556 vbuf->indices = (ushort *)
557 align_malloc( vbuf->max_indices * sizeof(vbuf->indices[0]), 16 );
558 if(!vbuf->indices)
559 vbuf_destroy(&vbuf->stage);
560
561 vbuf->vertices = NULL;
562 vbuf->vertex_ptr = vbuf->vertices;
563
564 vbuf->prim = ~0;
565
566 if(!GETENV("GALLIUM_NOVF"))
567 vbuf->vf = draw_vf_create();
568
569 return &vbuf->stage;
570 }