gallium: better flush logic in draw module
[mesa.git] / src / mesa / pipe / 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 <assert.h>
38
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"
43
44
45 /**
46 * Vertex buffer emit stage.
47 */
48 struct vbuf_stage {
49 struct draw_stage stage; /**< This must be first (base class) */
50
51 struct vbuf_render *render;
52
53 /** Vertex size in bytes */
54 unsigned vertex_size;
55
56 /* FIXME: we have no guarantee that 'unsigned' is 32bit */
57
58 /** Vertices in hardware format */
59 unsigned *vertices;
60 unsigned *vertex_ptr;
61 unsigned max_vertices;
62 unsigned nr_vertices;
63
64 /** Indices */
65 ushort *indices;
66 unsigned max_indices;
67 unsigned nr_indices;
68
69 /** Pipe primitive */
70 unsigned prim;
71 };
72
73
74 /**
75 * Basically a cast wrapper.
76 */
77 static INLINE struct vbuf_stage *
78 vbuf_stage( struct draw_stage *stage )
79 {
80 assert(stage);
81 return (struct vbuf_stage *)stage;
82 }
83
84
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 );
89
90
91 static INLINE boolean
92 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
93 {
94 unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
95 return (used + bytes) > bufsz;
96 }
97
98
99 static INLINE void
100 check_space( struct vbuf_stage *vbuf, unsigned nr )
101 {
102 if (vbuf->nr_vertices + nr > vbuf->max_vertices ) {
103 vbuf_flush_vertices(&vbuf->stage);
104 vbuf_alloc_vertices(&vbuf->stage, vbuf->vertex_size);
105 }
106
107 if (vbuf->nr_indices + nr > vbuf->max_indices )
108 vbuf_flush_indices(&vbuf->stage);
109 }
110
111
112 /**
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.
118 */
119 static INLINE void
120 emit_vertex( struct vbuf_stage *vbuf,
121 struct vertex_header *vertex )
122 {
123 const struct vertex_info *vinfo = vbuf->render->get_vertex_info(vbuf->render);
124
125 uint i;
126 uint count = 0; /* for debug/sanity */
127
128 // fprintf(stderr, "emit vertex %d to %p\n",
129 // vbuf->nr_vertices, vbuf->vertex_ptr);
130
131 if(vertex->vertex_id != UNDEFINED_VERTEX_ID) {
132 if(vertex->vertex_id < vbuf->nr_vertices)
133 return;
134 else
135 fprintf(stderr, "Bad vertex id 0x%04x (>= 0x%04x)\n",
136 vertex->vertex_id, vbuf->nr_vertices);
137 return;
138 }
139
140 vertex->vertex_id = vbuf->nr_vertices++;
141
142 for (i = 0; i < vinfo->num_attribs; i++) {
143 uint j = vinfo->src_index[i];
144 switch (vinfo->emit[i]) {
145 case EMIT_OMIT:
146 /* no-op */
147 break;
148 case EMIT_ALL:
149 /* just copy the whole vertex as-is to the vbuf */
150 assert(i == 0);
151 memcpy(vbuf->vertex_ptr, vertex, vinfo->size * 4);
152 vbuf->vertex_ptr += vinfo->size;
153 return;
154 case EMIT_1F:
155 *vbuf->vertex_ptr++ = fui(vertex->data[j][0]);
156 count++;
157 break;
158 case EMIT_1F_PSIZE:
159 *vbuf->vertex_ptr++ = fui(vbuf->stage.draw->rasterizer->point_size);
160 count++;
161 break;
162 case EMIT_2F:
163 *vbuf->vertex_ptr++ = fui(vertex->data[j][0]);
164 *vbuf->vertex_ptr++ = fui(vertex->data[j][1]);
165 count += 2;
166 break;
167 case EMIT_3F:
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]);
171 count += 3;
172 break;
173 case EMIT_4F:
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]);
178 count += 4;
179 break;
180 case EMIT_4UB:
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] ));
185 count += 1;
186 break;
187 default:
188 assert(0);
189 }
190 }
191 assert(count == vinfo->size);
192 }
193
194
195 static void
196 vbuf_tri( struct draw_stage *stage,
197 struct prim_header *prim )
198 {
199 struct vbuf_stage *vbuf = vbuf_stage( stage );
200 unsigned i;
201
202 check_space( vbuf, 3 );
203
204 for (i = 0; i < 3; i++) {
205 emit_vertex( vbuf, prim->v[i] );
206
207 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
208 }
209 }
210
211
212 static void
213 vbuf_line( struct draw_stage *stage,
214 struct prim_header *prim )
215 {
216 struct vbuf_stage *vbuf = vbuf_stage( stage );
217 unsigned i;
218
219 check_space( vbuf, 2 );
220
221 for (i = 0; i < 2; i++) {
222 emit_vertex( vbuf, prim->v[i] );
223
224 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
225 }
226 }
227
228
229 static void
230 vbuf_point( struct draw_stage *stage,
231 struct prim_header *prim )
232 {
233 struct vbuf_stage *vbuf = vbuf_stage( stage );
234
235 check_space( vbuf, 1 );
236
237 emit_vertex( vbuf, prim->v[0] );
238
239 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[0]->vertex_id;
240 }
241
242
243 /**
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.
247 */
248 static void
249 vbuf_set_prim( struct draw_stage *stage, uint newprim )
250 {
251 struct vbuf_stage *vbuf = vbuf_stage(stage);
252 const struct vertex_info *vinfo;
253 unsigned vertex_size;
254
255 assert(newprim == PIPE_PRIM_POINTS ||
256 newprim == PIPE_PRIM_LINES ||
257 newprim == PIPE_PRIM_TRIANGLES);
258
259 vbuf->prim = newprim;
260 vbuf->render->set_primitive(vbuf->render, newprim);
261
262 vinfo = vbuf->render->get_vertex_info(vbuf->render);
263 vertex_size = vinfo->size * sizeof(float);
264
265 if (vertex_size != vbuf->vertex_size)
266 vbuf_flush_vertices(stage);
267
268 if (!vbuf->vertices)
269 vbuf_alloc_vertices(stage, vertex_size);
270 }
271
272
273 static void
274 vbuf_first_tri( struct draw_stage *stage,
275 struct prim_header *prim )
276 {
277 vbuf_flush_indices( stage );
278 stage->tri = vbuf_tri;
279 vbuf_set_prim(stage, PIPE_PRIM_TRIANGLES);
280 stage->tri( stage, prim );
281 }
282
283
284 static void
285 vbuf_first_line( struct draw_stage *stage,
286 struct prim_header *prim )
287 {
288 vbuf_flush_indices( stage );
289 stage->line = vbuf_line;
290 vbuf_set_prim(stage, PIPE_PRIM_LINES);
291 stage->line( stage, prim );
292 }
293
294
295 static void
296 vbuf_first_point( struct draw_stage *stage,
297 struct prim_header *prim )
298 {
299 vbuf_flush_indices( stage );
300 stage->point = vbuf_point;
301 vbuf_set_prim(stage, PIPE_PRIM_POINTS);
302 stage->point( stage, prim );
303 }
304
305
306 static void
307 vbuf_flush_indices( struct draw_stage *stage )
308 {
309 struct vbuf_stage *vbuf = vbuf_stage( stage );
310
311 if(!vbuf->nr_indices)
312 return;
313
314 assert((uint) (vbuf->vertex_ptr - vbuf->vertices) ==
315 vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
316
317 switch(vbuf->prim) {
318 case PIPE_PRIM_POINTS:
319 break;
320 case PIPE_PRIM_LINES:
321 assert(vbuf->nr_indices % 2 == 0);
322 break;
323 case PIPE_PRIM_TRIANGLES:
324 assert(vbuf->nr_indices % 3 == 0);
325 break;
326 default:
327 assert(0);
328 }
329
330 vbuf->render->draw(vbuf->render, vbuf->indices, vbuf->nr_indices);
331
332 vbuf->nr_indices = 0;
333
334 stage->point = vbuf_first_point;
335 stage->line = vbuf_first_line;
336 stage->tri = vbuf_first_tri;
337 }
338
339
340 /**
341 * Flush existing vertex buffer and allocate a new one.
342 *
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
345 * we flush.
346 */
347 static void
348 vbuf_flush_vertices( struct draw_stage *stage )
349 {
350 struct vbuf_stage *vbuf = vbuf_stage( stage );
351
352 if(vbuf->vertices) {
353 vbuf_flush_indices(stage);
354
355 /* Reset temporary vertices ids */
356 if(vbuf->nr_vertices)
357 draw_reset_vertex_ids( vbuf->stage.draw );
358
359 /* Free the vertex buffer */
360 vbuf->render->release_vertices(vbuf->render,
361 vbuf->vertices,
362 vbuf->vertex_size,
363 vbuf->nr_vertices);
364 vbuf->nr_vertices = 0;
365 vbuf->vertex_ptr = vbuf->vertices = NULL;
366
367 }
368 }
369
370
371 static void
372 vbuf_alloc_vertices( struct draw_stage *stage,
373 unsigned new_vertex_size )
374 {
375 struct vbuf_stage *vbuf = vbuf_stage( stage );
376
377 assert(!vbuf->nr_indices);
378 assert(!vbuf->vertices);
379
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;
387 }
388
389
390
391 static void
392 vbuf_flush( struct draw_stage *stage, unsigned flags )
393 {
394 vbuf_flush_indices( stage );
395
396 stage->point = vbuf_first_point;
397 stage->line = vbuf_first_line;
398 stage->tri = vbuf_first_tri;
399
400 if (flags & DRAW_FLUSH_BACKEND)
401 vbuf_flush_vertices( stage );
402 }
403
404
405 static void
406 vbuf_reset_stipple_counter( struct draw_stage *stage )
407 {
408 /* XXX: Need to do something here for hardware with linestipple.
409 */
410 (void) stage;
411 }
412
413
414 static void vbuf_destroy( struct draw_stage *stage )
415 {
416 struct vbuf_stage *vbuf = vbuf_stage( stage );
417
418 align_free( vbuf->indices );
419 FREE( stage );
420 }
421
422
423 /**
424 * Create a new primitive vbuf/render stage.
425 */
426 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
427 struct vbuf_render *render )
428 {
429 struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
430
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;
438
439 vbuf->render = render;
440
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 );
445
446 vbuf->vertices = NULL;
447 vbuf->vertex_ptr = vbuf->vertices;
448
449 vbuf->prim = ~0;
450
451 return &vbuf->stage;
452 }