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