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>
39 #include "pipe/draw/draw_vbuf.h"
40 #include "pipe/draw/draw_private.h"
41 #include "pipe/draw/draw_vertex.h"
42 #include "pipe/p_util.h"
46 * Vertex buffer emit stage.
49 struct draw_stage stage
; /**< This must be first (base class) */
51 struct vbuf_render
*render
;
53 /** Vertex size in bytes */
56 /* FIXME: we have no guarantee that 'unsigned' is 32bit */
58 /** Vertices in hardware format */
61 unsigned max_vertices
;
75 * Basically a cast wrapper.
77 static INLINE
struct vbuf_stage
*
78 vbuf_stage( struct draw_stage
*stage
)
81 return (struct vbuf_stage
*)stage
;
85 static void vbuf_flush_indices( struct draw_stage
*stage
);
86 static void vbuf_flush_vertices( struct draw_stage
*stage
);
87 static void vbuf_alloc_vertices( struct draw_stage
*stage
,
88 unsigned new_vertex_size
);
92 overflow( void *map
, void *ptr
, unsigned bytes
, unsigned bufsz
)
94 unsigned long used
= (unsigned long) ((char *)ptr
- (char *)map
);
95 return (used
+ bytes
) > bufsz
;
100 check_space( struct vbuf_stage
*vbuf
, unsigned nr
)
102 if (vbuf
->nr_vertices
+ nr
> vbuf
->max_vertices
) {
103 vbuf_flush_vertices(&vbuf
->stage
);
104 vbuf_alloc_vertices(&vbuf
->stage
, vbuf
->vertex_size
);
107 if (vbuf
->nr_indices
+ nr
> vbuf
->max_indices
)
108 vbuf_flush_indices(&vbuf
->stage
);
113 * Extract the needed fields from post-transformed vertex and emit
114 * a hardware(driver) vertex.
115 * Recall that the vertices are constructed by the 'draw' module and
116 * have a couple of slots at the beginning (1-dword header, 4-dword
117 * clip pos) that we ignore here. We only use the vertex->data[] fields.
120 emit_vertex( struct vbuf_stage
*vbuf
,
121 struct vertex_header
*vertex
)
123 const struct vertex_info
*vinfo
= vbuf
->render
->get_vertex_info(vbuf
->render
);
126 uint count
= 0; /* for debug/sanity */
128 // fprintf(stderr, "emit vertex %d to %p\n",
129 // vbuf->nr_vertices, vbuf->vertex_ptr);
131 if(vertex
->vertex_id
!= UNDEFINED_VERTEX_ID
) {
132 if(vertex
->vertex_id
< vbuf
->nr_vertices
)
135 fprintf(stderr
, "Bad vertex id 0x%04x (>= 0x%04x)\n",
136 vertex
->vertex_id
, vbuf
->nr_vertices
);
140 vertex
->vertex_id
= vbuf
->nr_vertices
++;
142 for (i
= 0; i
< vinfo
->num_attribs
; i
++) {
143 uint j
= vinfo
->src_index
[i
];
144 switch (vinfo
->emit
[i
]) {
149 /* just copy the whole vertex as-is to the vbuf */
151 memcpy(vbuf
->vertex_ptr
, vertex
, vinfo
->size
* 4);
152 vbuf
->vertex_ptr
+= vinfo
->size
;
155 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][0]);
159 *vbuf
->vertex_ptr
++ = fui(vbuf
->stage
.draw
->rasterizer
->point_size
);
163 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][0]);
164 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][1]);
168 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][0]);
169 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][1]);
170 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][2]);
174 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][0]);
175 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][1]);
176 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][2]);
177 *vbuf
->vertex_ptr
++ = fui(vertex
->data
[j
][3]);
181 *vbuf
->vertex_ptr
++ = pack_ub4(float_to_ubyte( vertex
->data
[j
][2] ),
182 float_to_ubyte( vertex
->data
[j
][1] ),
183 float_to_ubyte( vertex
->data
[j
][0] ),
184 float_to_ubyte( vertex
->data
[j
][3] ));
191 assert(count
== vinfo
->size
);
196 vbuf_tri( struct draw_stage
*stage
,
197 struct prim_header
*prim
)
199 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
202 check_space( vbuf
, 3 );
204 for (i
= 0; i
< 3; i
++) {
205 emit_vertex( vbuf
, prim
->v
[i
] );
207 vbuf
->indices
[vbuf
->nr_indices
++] = (ushort
) prim
->v
[i
]->vertex_id
;
213 vbuf_line( struct draw_stage
*stage
,
214 struct prim_header
*prim
)
216 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
219 check_space( vbuf
, 2 );
221 for (i
= 0; i
< 2; i
++) {
222 emit_vertex( vbuf
, prim
->v
[i
] );
224 vbuf
->indices
[vbuf
->nr_indices
++] = (ushort
) prim
->v
[i
]->vertex_id
;
230 vbuf_point( struct draw_stage
*stage
,
231 struct prim_header
*prim
)
233 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
235 check_space( vbuf
, 1 );
237 emit_vertex( vbuf
, prim
->v
[0] );
239 vbuf
->indices
[vbuf
->nr_indices
++] = (ushort
) prim
->v
[0]->vertex_id
;
244 * Set the prim type for subsequent vertices.
245 * This may result in a new vertex size. The existing vbuffer (if any)
246 * will be flushed if needed and a new one allocated.
249 vbuf_set_prim( struct draw_stage
*stage
, uint newprim
)
251 struct vbuf_stage
*vbuf
= vbuf_stage(stage
);
252 const struct vertex_info
*vinfo
;
253 unsigned vertex_size
;
255 assert(newprim
== PIPE_PRIM_POINTS
||
256 newprim
== PIPE_PRIM_LINES
||
257 newprim
== PIPE_PRIM_TRIANGLES
);
259 vbuf
->prim
= newprim
;
260 vbuf
->render
->set_primitive(vbuf
->render
, newprim
);
262 vinfo
= vbuf
->render
->get_vertex_info(vbuf
->render
);
263 vertex_size
= vinfo
->size
* sizeof(float);
265 if (vertex_size
!= vbuf
->vertex_size
)
266 vbuf_flush_vertices(stage
);
269 vbuf_alloc_vertices(stage
, vertex_size
);
274 vbuf_first_tri( struct draw_stage
*stage
,
275 struct prim_header
*prim
)
277 vbuf_flush_indices( stage
);
278 stage
->tri
= vbuf_tri
;
279 vbuf_set_prim(stage
, PIPE_PRIM_TRIANGLES
);
280 stage
->tri( stage
, prim
);
285 vbuf_first_line( struct draw_stage
*stage
,
286 struct prim_header
*prim
)
288 vbuf_flush_indices( stage
);
289 stage
->line
= vbuf_line
;
290 vbuf_set_prim(stage
, PIPE_PRIM_LINES
);
291 stage
->line( stage
, prim
);
296 vbuf_first_point( struct draw_stage
*stage
,
297 struct prim_header
*prim
)
299 vbuf_flush_indices( stage
);
300 stage
->point
= vbuf_point
;
301 vbuf_set_prim(stage
, PIPE_PRIM_POINTS
);
302 stage
->point( stage
, prim
);
307 vbuf_flush_indices( struct draw_stage
*stage
)
309 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
311 if(!vbuf
->nr_indices
)
314 assert((uint
) (vbuf
->vertex_ptr
- vbuf
->vertices
) ==
315 vbuf
->nr_vertices
* vbuf
->vertex_size
/ sizeof(unsigned));
318 case PIPE_PRIM_POINTS
:
320 case PIPE_PRIM_LINES
:
321 assert(vbuf
->nr_indices
% 2 == 0);
323 case PIPE_PRIM_TRIANGLES
:
324 assert(vbuf
->nr_indices
% 3 == 0);
330 vbuf
->render
->draw(vbuf
->render
, vbuf
->indices
, vbuf
->nr_indices
);
332 vbuf
->nr_indices
= 0;
334 stage
->point
= vbuf_first_point
;
335 stage
->line
= vbuf_first_line
;
336 stage
->tri
= vbuf_first_tri
;
341 * Flush existing vertex buffer and allocate a new one.
343 * XXX: We separate flush-on-index-full and flush-on-vb-full, but may
344 * raise issues uploading vertices if the hardware wants to flush when
348 vbuf_flush_vertices( struct draw_stage
*stage
)
350 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
353 vbuf_flush_indices(stage
);
355 /* Reset temporary vertices ids */
356 if(vbuf
->nr_vertices
)
357 draw_reset_vertex_ids( vbuf
->stage
.draw
);
359 /* Free the vertex buffer */
360 vbuf
->render
->release_vertices(vbuf
->render
,
364 vbuf
->nr_vertices
= 0;
365 vbuf
->vertex_ptr
= vbuf
->vertices
= NULL
;
372 vbuf_alloc_vertices( struct draw_stage
*stage
,
373 unsigned new_vertex_size
)
375 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
377 assert(!vbuf
->nr_indices
);
378 assert(!vbuf
->vertices
);
380 /* Allocate a new vertex buffer */
381 vbuf
->vertex_size
= new_vertex_size
;
382 vbuf
->max_vertices
= vbuf
->render
->max_vertex_buffer_bytes
/ vbuf
->vertex_size
;
383 vbuf
->vertices
= (uint
*) vbuf
->render
->allocate_vertices(vbuf
->render
,
384 (ushort
) vbuf
->vertex_size
,
385 (ushort
) vbuf
->max_vertices
);
386 vbuf
->vertex_ptr
= vbuf
->vertices
;
392 vbuf_flush( struct draw_stage
*stage
, unsigned flags
)
394 vbuf_flush_indices( stage
);
396 stage
->point
= vbuf_first_point
;
397 stage
->line
= vbuf_first_line
;
398 stage
->tri
= vbuf_first_tri
;
400 if (flags
& DRAW_FLUSH_BACKEND
)
401 vbuf_flush_vertices( stage
);
406 vbuf_reset_stipple_counter( struct draw_stage
*stage
)
408 /* XXX: Need to do something here for hardware with linestipple.
414 static void vbuf_destroy( struct draw_stage
*stage
)
416 struct vbuf_stage
*vbuf
= vbuf_stage( stage
);
418 align_free( vbuf
->indices
);
424 * Create a new primitive vbuf/render stage.
426 struct draw_stage
*draw_vbuf_stage( struct draw_context
*draw
,
427 struct vbuf_render
*render
)
429 struct vbuf_stage
*vbuf
= CALLOC_STRUCT(vbuf_stage
);
431 vbuf
->stage
.draw
= draw
;
432 vbuf
->stage
.point
= vbuf_first_point
;
433 vbuf
->stage
.line
= vbuf_first_line
;
434 vbuf
->stage
.tri
= vbuf_first_tri
;
435 vbuf
->stage
.flush
= vbuf_flush
;
436 vbuf
->stage
.reset_stipple_counter
= vbuf_reset_stipple_counter
;
437 vbuf
->stage
.destroy
= vbuf_destroy
;
439 vbuf
->render
= render
;
441 assert(render
->max_indices
< UNDEFINED_VERTEX_ID
);
442 vbuf
->max_indices
= render
->max_indices
;
443 vbuf
->indices
= (ushort
*)
444 align_malloc( vbuf
->max_indices
* sizeof(vbuf
->indices
[0]), 16 );
446 vbuf
->vertices
= NULL
;
447 vbuf
->vertex_ptr
= vbuf
->vertices
;