1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
30 * Vertex buffer drawing stage.
32 * \author José Fonseca <jrfonsec@tungstengraphics.com>
33 * \author Keith Whitwell <keith@tungstengraphics.com>
37 #include "pipe/p_debug.h"
38 #include "pipe/p_util.h"
40 #include "draw_vbuf.h"
41 #include "draw_private.h"
42 #include "draw_vertex.h"
47 * Vertex buffer emit stage.
50 struct draw_stage stage
; /**< This must be first (base class) */
52 struct vbuf_render
*render
;
54 const struct vertex_info
*vinfo
;
56 /** Vertex size in bytes */
59 struct draw_vertex_fetch
*vf
;
61 /* FIXME: we have no guarantee that 'unsigned' is 32bit */
63 /** Vertices in hardware format */
66 unsigned max_vertices
;
80 * Basically a cast wrapper.
82 static INLINE
struct vbuf_stage
*
83 vbuf_stage( struct draw_stage
*stage
)
86 return (struct vbuf_stage
*)stage
;
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
);
96 overflow( void *map
, void *ptr
, unsigned bytes
, unsigned bufsz
)
98 unsigned long used
= (unsigned long) ((char *)ptr
- (char *)map
);
99 return (used
+ bytes
) > bufsz
;
104 check_space( struct vbuf_stage
*vbuf
, unsigned nr
)
106 if (vbuf
->nr_vertices
+ nr
> vbuf
->max_vertices
) {
107 vbuf_flush_vertices(vbuf
);
108 vbuf_alloc_vertices(vbuf
);
111 if (vbuf
->nr_indices
+ nr
> vbuf
->max_indices
)
112 vbuf_flush_indices(vbuf
);
118 dump_emitted_vertex(const struct vertex_info
*vinfo
, const uint8_t *data
)
120 assert(vinfo
== vbuf
->render
->get_vertex_info(vbuf
->render
));
123 for (i
= 0; i
< vinfo
->num_attribs
; i
++) {
124 j
= vinfo
->src_index
[i
];
125 switch (vinfo
->emit
[i
]) {
127 debug_printf("EMIT_OMIT:");
132 debug_printf("EMIT_ALL:\t");
133 for(k
= 0; k
< vinfo
->size
*4; ++k
)
134 debug_printf("%02x ", *data
++);
137 debug_printf("EMIT_1F:\t");
138 debug_printf("%f ", *(float *)data
); data
+= sizeof(float);
141 debug_printf("EMIT_1F_PSIZE:\t");
142 debug_printf("%f ", *(float *)data
); data
+= sizeof(float);
145 debug_printf("EMIT_2F:\t");
146 debug_printf("%f ", *(float *)data
); data
+= sizeof(float);
147 debug_printf("%f ", *(float *)data
); data
+= sizeof(float);
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);
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);
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
++);
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.
188 emit_vertex( struct vbuf_stage
*vbuf
,
189 struct vertex_header
*vertex
)
192 debug_printf("emit vertex %d to %p\n",
193 vbuf
->nr_vertices
, vbuf
->vertex_ptr
);
196 if(vertex
->vertex_id
!= UNDEFINED_VERTEX_ID
) {
197 if(vertex
->vertex_id
< vbuf
->nr_vertices
)
200 debug_printf("Bad vertex id 0x%04x (>= 0x%04x)\n",
201 vertex
->vertex_id
, vbuf
->nr_vertices
);
205 vertex
->vertex_id
= vbuf
->nr_vertices
++;
208 const struct vertex_info
*vinfo
= vbuf
->vinfo
;
210 uint count
= 0; /* for debug/sanity */
212 assert(vinfo
== vbuf
->render
->get_vertex_info(vbuf
->render
));
214 for (i
= 0; i
< vinfo
->num_attribs
; i
++) {
215 uint j
= vinfo
->src_index
[i
];
216 switch (vinfo
->emit
[i
]) {
221 /* just copy the whole vertex as-is to the vbuf */
224 memcpy(vbuf
->vertex_ptr
, vertex
, vinfo
->size
* 4);
225 vbuf
->vertex_ptr
+= vinfo
->size
;
226 count
+= vinfo
->size
;
229 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][0]);
233 *vbuf
->vertex_ptr
++ = fui(vbuf
->stage
.draw
->rasterizer
->point_size
);
237 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][0]);
238 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][1]);
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]);
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]);
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] ));
265 assert(count
== vinfo
->size
);
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
);
281 draw_vf_emit_vertex(vbuf
->vf
, vertex
, vbuf
->vertex_ptr
);
283 vbuf
->vertex_ptr
+= vbuf
->vertex_size
/4;
289 vbuf_tri( struct draw_stage
*stage
,
290 struct prim_header
*prim
)
292 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
295 check_space( vbuf
, 3 );
297 for (i
= 0; i
< 3; i
++) {
298 emit_vertex( vbuf
, prim
->v
[i
] );
300 vbuf
->indices
[vbuf
->nr_indices
++] = (ushort
) prim
->v
[i
]->vertex_id
;
306 vbuf_line( struct draw_stage
*stage
,
307 struct prim_header
*prim
)
309 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
312 check_space( vbuf
, 2 );
314 for (i
= 0; i
< 2; i
++) {
315 emit_vertex( vbuf
, prim
->v
[i
] );
317 vbuf
->indices
[vbuf
->nr_indices
++] = (ushort
) prim
->v
[i
]->vertex_id
;
323 vbuf_point( struct draw_stage
*stage
,
324 struct prim_header
*prim
)
326 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
328 check_space( vbuf
, 1 );
330 emit_vertex( vbuf
, prim
->v
[0] );
332 vbuf
->indices
[vbuf
->nr_indices
++] = (ushort
) prim
->v
[0]->vertex_id
;
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.
342 vbuf_set_prim( struct vbuf_stage
*vbuf
, uint newprim
)
344 const struct vertex_info
*vinfo
;
345 unsigned vertex_size
;
347 assert(newprim
== PIPE_PRIM_POINTS
||
348 newprim
== PIPE_PRIM_LINES
||
349 newprim
== PIPE_PRIM_TRIANGLES
);
351 vbuf
->prim
= newprim
;
352 vbuf
->render
->set_primitive(vbuf
->render
, newprim
);
354 vinfo
= vbuf
->render
->get_vertex_info(vbuf
->render
);
355 vertex_size
= vinfo
->size
* sizeof(float);
357 if (vertex_size
!= vbuf
->vertex_size
)
358 vbuf_flush_vertices(vbuf
);
361 vbuf
->vertex_size
= vertex_size
;
363 draw_vf_set_vertex_info(vbuf
->vf
,
365 vbuf
->stage
.draw
->rasterizer
->point_size
);
368 vbuf_alloc_vertices(vbuf
);
373 vbuf_first_tri( struct draw_stage
*stage
,
374 struct prim_header
*prim
)
376 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
378 vbuf_flush_indices( vbuf
);
379 stage
->tri
= vbuf_tri
;
380 vbuf_set_prim(vbuf
, PIPE_PRIM_TRIANGLES
);
381 stage
->tri( stage
, prim
);
386 vbuf_first_line( struct draw_stage
*stage
,
387 struct prim_header
*prim
)
389 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
391 vbuf_flush_indices( vbuf
);
392 stage
->line
= vbuf_line
;
393 vbuf_set_prim(vbuf
, PIPE_PRIM_LINES
);
394 stage
->line( stage
, prim
);
399 vbuf_first_point( struct draw_stage
*stage
,
400 struct prim_header
*prim
)
402 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
404 vbuf_flush_indices( vbuf
);
405 stage
->point
= vbuf_point
;
406 vbuf_set_prim(vbuf
, PIPE_PRIM_POINTS
);
407 stage
->point( stage
, prim
);
412 vbuf_flush_indices( struct vbuf_stage
*vbuf
)
414 if(!vbuf
->nr_indices
)
417 assert((uint
) (vbuf
->vertex_ptr
- vbuf
->vertices
) ==
418 vbuf
->nr_vertices
* vbuf
->vertex_size
/ sizeof(unsigned));
421 case PIPE_PRIM_POINTS
:
423 case PIPE_PRIM_LINES
:
424 assert(vbuf
->nr_indices
% 2 == 0);
426 case PIPE_PRIM_TRIANGLES
:
427 assert(vbuf
->nr_indices
% 3 == 0);
433 vbuf
->render
->draw(vbuf
->render
, vbuf
->indices
, vbuf
->nr_indices
);
435 vbuf
->nr_indices
= 0;
437 /* don't need to reset point/line/tri functions */
439 stage
->point
= vbuf_first_point
;
440 stage
->line
= vbuf_first_line
;
441 stage
->tri
= vbuf_first_tri
;
447 * Flush existing vertex buffer and allocate a new one.
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
454 vbuf_flush_vertices( struct vbuf_stage
*vbuf
)
457 vbuf_flush_indices(vbuf
);
459 /* Reset temporary vertices ids */
460 if(vbuf
->nr_vertices
)
461 draw_reset_vertex_ids( vbuf
->stage
.draw
);
463 /* Free the vertex buffer */
464 vbuf
->render
->release_vertices(vbuf
->render
,
468 vbuf
->max_vertices
= vbuf
->nr_vertices
= 0;
469 vbuf
->vertex_ptr
= vbuf
->vertices
= NULL
;
476 vbuf_alloc_vertices( struct vbuf_stage
*vbuf
)
478 assert(!vbuf
->nr_indices
);
479 assert(!vbuf
->vertices
);
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
;
492 vbuf_flush( struct draw_stage
*stage
, unsigned flags
)
494 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
496 vbuf_flush_indices( vbuf
);
498 stage
->point
= vbuf_first_point
;
499 stage
->line
= vbuf_first_line
;
500 stage
->tri
= vbuf_first_tri
;
502 if (flags
& DRAW_FLUSH_BACKEND
)
503 vbuf_flush_vertices( vbuf
);
508 vbuf_reset_stipple_counter( struct draw_stage
*stage
)
510 /* XXX: Need to do something here for hardware with linestipple.
516 static void vbuf_destroy( struct draw_stage
*stage
)
518 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
521 align_free( vbuf
->indices
);
524 draw_vf_destroy( vbuf
->vf
);
527 vbuf
->render
->destroy( vbuf
->render
);
534 * Create a new primitive vbuf/render stage.
536 struct draw_stage
*draw_vbuf_stage( struct draw_context
*draw
,
537 struct vbuf_render
*render
)
539 struct vbuf_stage
*vbuf
= CALLOC_STRUCT(vbuf_stage
);
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
;
552 vbuf
->render
= render
;
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 );
559 vbuf_destroy(&vbuf
->stage
);
561 vbuf
->vertices
= NULL
;
562 vbuf
->vertex_ptr
= vbuf
->vertices
;
566 if(!GETENV("GALLIUM_NOVF"))
567 vbuf
->vf
= draw_vf_create();