vbuf_flush_vertices() instead of vbuf_flush_indices() in vbuf_end()
[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 unsigned new_vertex_size );
88
89
90 static INLINE boolean
91 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
92 {
93 unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
94 return (used + bytes) > bufsz;
95 }
96
97
98 static INLINE void
99 check_space( struct vbuf_stage *vbuf, unsigned nr )
100 {
101 if (vbuf->nr_vertices + nr > vbuf->max_vertices )
102 vbuf_flush_vertices(&vbuf->stage, vbuf->vertex_size );
103
104 if (vbuf->nr_indices + nr > vbuf->max_indices )
105 vbuf_flush_indices(&vbuf->stage);
106 }
107
108
109 /**
110 * Extract the needed fields from vertex_header and emit i915 dwords.
111 * Recall that the vertices are constructed by the 'draw' module and
112 * have a couple of slots at the beginning (1-dword header, 4-dword
113 * clip pos) that we ignore here.
114 */
115 static INLINE void
116 emit_vertex( struct vbuf_stage *vbuf,
117 struct vertex_header *vertex )
118 {
119 const struct vertex_info *vinfo = vbuf->render->get_vertex_info(vbuf->render);
120
121 uint i;
122 uint count = 0; /* for debug/sanity */
123
124 // fprintf(stderr, "emit vertex %d to %p\n",
125 // vbuf->nr_vertices, vbuf->vertex_ptr);
126
127 if(vertex->vertex_id != UNDEFINED_VERTEX_ID) {
128 if(vertex->vertex_id < vbuf->nr_vertices)
129 return;
130 else
131 fprintf(stderr, "Bad vertex id 0x%04x (>= 0x%04x)\n",
132 vertex->vertex_id, vbuf->nr_vertices);
133 return;
134 }
135
136 vertex->vertex_id = vbuf->nr_vertices++;
137
138 for (i = 0; i < vinfo->num_attribs; i++) {
139 switch (vinfo->format[i]) {
140 case FORMAT_OMIT:
141 /* no-op */
142 break;
143 case FORMAT_1F:
144 *vbuf->vertex_ptr++ = fui(vertex->data[i][0]);
145 count++;
146 break;
147 case FORMAT_2F:
148 *vbuf->vertex_ptr++ = fui(vertex->data[i][0]);
149 *vbuf->vertex_ptr++ = fui(vertex->data[i][1]);
150 count += 2;
151 break;
152 case FORMAT_3F:
153 *vbuf->vertex_ptr++ = fui(vertex->data[i][0]);
154 *vbuf->vertex_ptr++ = fui(vertex->data[i][1]);
155 *vbuf->vertex_ptr++ = fui(vertex->data[i][2]);
156 count += 3;
157 break;
158 case FORMAT_4F:
159 *vbuf->vertex_ptr++ = fui(vertex->data[i][0]);
160 *vbuf->vertex_ptr++ = fui(vertex->data[i][1]);
161 *vbuf->vertex_ptr++ = fui(vertex->data[i][2]);
162 *vbuf->vertex_ptr++ = fui(vertex->data[i][3]);
163 count += 4;
164 break;
165 case FORMAT_4UB:
166 *vbuf->vertex_ptr++ = pack_ub4(float_to_ubyte( vertex->data[i][2] ),
167 float_to_ubyte( vertex->data[i][1] ),
168 float_to_ubyte( vertex->data[i][0] ),
169 float_to_ubyte( vertex->data[i][3] ));
170 count += 1;
171 break;
172 default:
173 assert(0);
174 }
175 }
176 assert(count == vinfo->size);
177 }
178
179
180 static void
181 vbuf_tri( struct draw_stage *stage,
182 struct prim_header *prim )
183 {
184 struct vbuf_stage *vbuf = vbuf_stage( stage );
185 unsigned i;
186
187 check_space( vbuf, 3 );
188
189 for (i = 0; i < 3; i++) {
190 emit_vertex( vbuf, prim->v[i] );
191
192 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
193 }
194 }
195
196
197 static void
198 vbuf_line( struct draw_stage *stage,
199 struct prim_header *prim )
200 {
201 struct vbuf_stage *vbuf = vbuf_stage( stage );
202 unsigned i;
203
204 check_space( vbuf, 2 );
205
206 for (i = 0; i < 2; i++) {
207 emit_vertex( vbuf, prim->v[i] );
208
209 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[i]->vertex_id;
210 }
211 }
212
213
214 static void
215 vbuf_point( struct draw_stage *stage,
216 struct prim_header *prim )
217 {
218 struct vbuf_stage *vbuf = vbuf_stage( stage );
219
220 check_space( vbuf, 1 );
221
222 emit_vertex( vbuf, prim->v[0] );
223
224 vbuf->indices[vbuf->nr_indices++] = (ushort) prim->v[0]->vertex_id;
225 }
226
227
228 static void
229 vbuf_first_tri( struct draw_stage *stage,
230 struct prim_header *prim )
231 {
232 struct vbuf_stage *vbuf = vbuf_stage( stage );
233
234 vbuf_flush_indices( stage );
235 stage->tri = vbuf_tri;
236 stage->tri( stage, prim );
237 vbuf->prim = PIPE_PRIM_TRIANGLES;
238 vbuf->render->set_primitive(vbuf->render, PIPE_PRIM_TRIANGLES);
239 }
240
241
242 static void
243 vbuf_first_line( struct draw_stage *stage,
244 struct prim_header *prim )
245 {
246 struct vbuf_stage *vbuf = vbuf_stage( stage );
247
248 vbuf_flush_indices( stage );
249 stage->line = vbuf_line;
250 stage->line( stage, prim );
251 vbuf->prim = PIPE_PRIM_LINES;
252 vbuf->render->set_primitive(vbuf->render, PIPE_PRIM_LINES);
253 }
254
255
256 static void
257 vbuf_first_point( struct draw_stage *stage,
258 struct prim_header *prim )
259 {
260 struct vbuf_stage *vbuf = vbuf_stage( stage );
261
262 vbuf_flush_indices( stage );
263 stage->point = vbuf_point;
264 stage->point( stage, prim );
265 vbuf->prim = PIPE_PRIM_POINTS;
266 vbuf->render->set_primitive(vbuf->render, PIPE_PRIM_POINTS);
267 }
268
269
270 static void
271 vbuf_flush_indices( struct draw_stage *stage )
272 {
273 struct vbuf_stage *vbuf = vbuf_stage( stage );
274
275 if(!vbuf->nr_indices)
276 return;
277
278 assert((uint) (vbuf->vertex_ptr - vbuf->vertices) ==
279 vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
280
281 switch(vbuf->prim) {
282 case PIPE_PRIM_POINTS:
283 break;
284 case PIPE_PRIM_LINES:
285 assert(vbuf->nr_indices % 2 == 0);
286 break;
287 case PIPE_PRIM_TRIANGLES:
288 assert(vbuf->nr_indices % 3 == 0);
289 break;
290 default:
291 assert(0);
292 }
293
294 vbuf->render->draw( vbuf->render,
295 vbuf->prim,
296 vbuf->indices,
297 vbuf->nr_indices,
298 vbuf->vertices,
299 vbuf->nr_vertices,
300 vbuf->vertex_size );
301
302 vbuf->nr_indices = 0;
303 }
304
305
306 /**
307 * Flush existing vertex buffer and allocate a new one.
308 *
309 * XXX: We separate flush-on-index-full and flush-on-vb-full, but may
310 * raise issues uploading vertices if the hardware wants to flush when
311 * we flush.
312 */
313 static void
314 vbuf_flush_vertices( struct draw_stage *stage,
315 unsigned new_vertex_size )
316 {
317 struct vbuf_stage *vbuf = vbuf_stage( stage );
318
319 if(vbuf->vertices) {
320 vbuf_flush_indices(stage);
321
322 /* Reset temporary vertices ids */
323 if(vbuf->nr_vertices)
324 draw_reset_vertex_ids( vbuf->stage.draw );
325
326 /* Free the vertex buffer */
327 vbuf->render->release_vertices(vbuf->render,
328 vbuf->vertices,
329 vbuf->vertex_size,
330 vbuf->nr_vertices);
331 vbuf->nr_vertices = 0;
332 vbuf->vertex_ptr = vbuf->vertices = NULL;
333
334 }
335
336 assert(!vbuf->nr_indices);
337
338 /* Allocate a new vertex buffer */
339 vbuf->vertex_size = new_vertex_size;
340 vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
341 vbuf->vertices = vbuf->render->allocate_vertices(vbuf->render,
342 vbuf->vertex_size,
343 vbuf->max_vertices) ;
344 vbuf->vertex_ptr = vbuf->vertices;
345 }
346
347
348 static void
349 vbuf_begin( struct draw_stage *stage )
350 {
351 struct vbuf_stage *vbuf = vbuf_stage(stage);
352 const struct vertex_info *vinfo = vbuf->render->get_vertex_info(vbuf->render);
353 unsigned vertex_size = vinfo->size * sizeof(float);
354
355 if(vbuf->vertex_size != vertex_size)
356 vbuf_flush_vertices(&vbuf->stage, vertex_size);
357 }
358
359
360 static void
361 vbuf_end( struct draw_stage *stage )
362 {
363 #if 0
364 /* XXX: Overkill */
365 vbuf_flush_indices( stage );
366 #else
367 /* By flushing vertices we avoid having the vertex buffer grow and grow */
368 struct vbuf_stage *vbuf = vbuf_stage(stage);
369 vbuf_flush_vertices( stage, vbuf->vertex_size );
370 #endif
371
372 stage->point = vbuf_first_point;
373 stage->line = vbuf_first_line;
374 stage->tri = vbuf_first_tri;
375 }
376
377
378 static void
379 vbuf_reset_stipple_counter( struct draw_stage *stage )
380 {
381 }
382
383
384 static void vbuf_destroy( struct draw_stage *stage )
385 {
386 struct vbuf_stage *vbuf = vbuf_stage( stage );
387
388 align_free( vbuf->indices );
389 FREE( stage );
390 }
391
392
393 /**
394 * Create a new primitive vbuf/render stage.
395 */
396 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
397 struct vbuf_render *render )
398 {
399 struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
400
401 vbuf->stage.draw = draw;
402 vbuf->stage.begin = vbuf_begin;
403 vbuf->stage.point = vbuf_first_point;
404 vbuf->stage.line = vbuf_first_line;
405 vbuf->stage.tri = vbuf_first_tri;
406 vbuf->stage.end = vbuf_end;
407 vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
408 vbuf->stage.destroy = vbuf_destroy;
409
410 vbuf->render = render;
411
412 assert(render->max_indices < UNDEFINED_VERTEX_ID);
413 vbuf->max_indices = render->max_indices;
414 vbuf->indices
415 = align_malloc( vbuf->max_indices * sizeof(vbuf->indices[0]), 16 );
416
417 vbuf->vertices = NULL;
418 vbuf->vertex_ptr = vbuf->vertices;
419
420 return &vbuf->stage;
421 }