1eb7c4bc38523449d6ca612721ac1e77d2049ee7
[mesa.git] / src / gallium / auxiliary / draw / draw_pipe_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 "pipe/p_debug.h"
38 #include "pipe/p_util.h"
39
40 #include "draw_vbuf.h"
41 #include "draw_private.h"
42 #include "draw_vertex.h"
43 #include "draw_pipe.h"
44 #include "translate/translate.h"
45
46
47 /**
48 * Vertex buffer emit stage.
49 */
50 struct vbuf_stage {
51 struct draw_stage stage; /**< This must be first (base class) */
52
53 struct vbuf_render *render;
54
55 const struct vertex_info *vinfo;
56
57 /** Vertex size in bytes */
58 unsigned vertex_size;
59
60 struct translate *translate;
61
62 /* FIXME: we have no guarantee that 'unsigned' is 32bit */
63
64 /** Vertices in hardware format */
65 unsigned *vertices;
66 unsigned *vertex_ptr;
67 unsigned max_vertices;
68 unsigned nr_vertices;
69
70 /** Indices */
71 ushort *indices;
72 unsigned max_indices;
73 unsigned nr_indices;
74
75 /* Cache point size somewhere it's address won't change:
76 */
77 float point_size;
78 };
79
80
81 /**
82 * Basically a cast wrapper.
83 */
84 static INLINE struct vbuf_stage *
85 vbuf_stage( struct draw_stage *stage )
86 {
87 assert(stage);
88 return (struct vbuf_stage *)stage;
89 }
90
91
92 static void vbuf_flush_indices( struct vbuf_stage *vbuf );
93 static void vbuf_flush_vertices( struct vbuf_stage *vbuf );
94 static void vbuf_alloc_vertices( struct vbuf_stage *vbuf );
95
96
97 static INLINE boolean
98 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
99 {
100 unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
101 return (used + bytes) > bufsz;
102 }
103
104
105 static INLINE void
106 check_space( struct vbuf_stage *vbuf, unsigned nr )
107 {
108 if (vbuf->nr_vertices + nr > vbuf->max_vertices ) {
109 vbuf_flush_vertices(vbuf);
110 vbuf_alloc_vertices(vbuf);
111 }
112
113 if (vbuf->nr_indices + nr > vbuf->max_indices )
114 vbuf_flush_indices(vbuf);
115 }
116
117
118
119
120 /**
121 * Extract the needed fields from post-transformed vertex and emit
122 * a hardware(driver) vertex.
123 * Recall that the vertices are constructed by the 'draw' module and
124 * have a couple of slots at the beginning (1-dword header, 4-dword
125 * clip pos) that we ignore here. We only use the vertex->data[] fields.
126 */
127 static INLINE ushort
128 emit_vertex( struct vbuf_stage *vbuf,
129 struct vertex_header *vertex )
130 {
131 if(vertex->vertex_id == UNDEFINED_VERTEX_ID) {
132 /* Hmm - vertices are emitted one at a time - better make sure
133 * set_buffer is efficient. Consider a special one-shot mode for
134 * translate.
135 */
136 vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0);
137 vbuf->translate->run(vbuf->translate, 0, 1, vbuf->vertex_ptr);
138
139 if (1) draw_dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
140
141 vbuf->vertex_ptr += vbuf->vertex_size/4;
142 vertex->vertex_id = vbuf->nr_vertices++;
143 }
144
145 return vertex->vertex_id;
146 }
147
148
149 static void
150 vbuf_tri( struct draw_stage *stage,
151 struct prim_header *prim )
152 {
153 struct vbuf_stage *vbuf = vbuf_stage( stage );
154 unsigned i;
155
156 check_space( vbuf, 3 );
157
158 for (i = 0; i < 3; i++) {
159 vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
160 }
161 }
162
163
164 static void
165 vbuf_line( struct draw_stage *stage,
166 struct prim_header *prim )
167 {
168 struct vbuf_stage *vbuf = vbuf_stage( stage );
169 unsigned i;
170
171 check_space( vbuf, 2 );
172
173 for (i = 0; i < 2; i++) {
174 vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
175 }
176 }
177
178
179 static void
180 vbuf_point( struct draw_stage *stage,
181 struct prim_header *prim )
182 {
183 struct vbuf_stage *vbuf = vbuf_stage( stage );
184
185 check_space( vbuf, 1 );
186
187 vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
188 }
189
190
191
192
193 /**
194 * Set the prim type for subsequent vertices.
195 * This may result in a new vertex size. The existing vbuffer (if any)
196 * will be flushed if needed and a new one allocated.
197 */
198 static void
199 vbuf_set_prim( struct vbuf_stage *vbuf, uint prim )
200 {
201 struct translate_key hw_key;
202 unsigned dst_offset;
203 unsigned i;
204
205 vbuf->render->set_primitive(vbuf->render, prim);
206
207 /* Must do this after set_primitive() above:
208 *
209 * XXX: need some state managment to track when this needs to be
210 * recalculated. The driver should tell us whether there was a
211 * state change.
212 */
213 vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
214
215 if (vbuf->vertex_size != vbuf->vinfo->size * sizeof(float)) {
216 vbuf_flush_vertices(vbuf);
217 vbuf->vertex_size = vbuf->vinfo->size * sizeof(float);
218 }
219
220 /* Translate from pipeline vertices to hw vertices.
221 */
222 dst_offset = 0;
223 memset(&hw_key, 0, sizeof(hw_key));
224
225 for (i = 0; i < vbuf->vinfo->num_attribs; i++) {
226 unsigned emit_sz = 0;
227 unsigned src_buffer = 0;
228 unsigned output_format;
229 unsigned src_offset = (vbuf->vinfo->src_index[i] * 4 * sizeof(float) );
230
231 switch (vbuf->vinfo->emit[i]) {
232 case EMIT_4F:
233 output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
234 emit_sz = 4 * sizeof(float);
235 break;
236 case EMIT_3F:
237 output_format = PIPE_FORMAT_R32G32B32_FLOAT;
238 emit_sz = 3 * sizeof(float);
239 break;
240 case EMIT_2F:
241 output_format = PIPE_FORMAT_R32G32_FLOAT;
242 emit_sz = 2 * sizeof(float);
243 break;
244 case EMIT_1F:
245 output_format = PIPE_FORMAT_R32_FLOAT;
246 emit_sz = 1 * sizeof(float);
247 break;
248 case EMIT_1F_PSIZE:
249 output_format = PIPE_FORMAT_R32_FLOAT;
250 emit_sz = 1 * sizeof(float);
251 src_buffer = 1;
252 src_offset = 0;
253 break;
254 case EMIT_4UB:
255 output_format = PIPE_FORMAT_B8G8R8A8_UNORM;
256 emit_sz = 4 * sizeof(ubyte);
257 break;
258 default:
259 assert(0);
260 output_format = PIPE_FORMAT_NONE;
261 emit_sz = 0;
262 break;
263 }
264
265 hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
266 hw_key.element[i].input_buffer = src_buffer;
267 hw_key.element[i].input_offset = src_offset;
268 hw_key.element[i].output_format = output_format;
269 hw_key.element[i].output_offset = dst_offset;
270
271 dst_offset += emit_sz;
272 }
273
274 hw_key.nr_elements = vbuf->vinfo->num_attribs;
275 hw_key.output_stride = vbuf->vinfo->size * 4;
276
277 /* Don't bother with caching at this stage:
278 */
279 if (!vbuf->translate ||
280 memcmp(&vbuf->translate->key, &hw_key, sizeof(hw_key)) != 0)
281 {
282 if (vbuf->translate)
283 vbuf->translate->release(vbuf->translate);
284
285 vbuf->translate = translate_create( &hw_key );
286
287 vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0);
288 }
289
290 vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
291
292 /* Allocate new buffer?
293 */
294 if (!vbuf->vertices)
295 vbuf_alloc_vertices(vbuf);
296 }
297
298
299 static void
300 vbuf_first_tri( struct draw_stage *stage,
301 struct prim_header *prim )
302 {
303 struct vbuf_stage *vbuf = vbuf_stage( stage );
304
305 vbuf_flush_indices( vbuf );
306 stage->tri = vbuf_tri;
307 vbuf_set_prim(vbuf, PIPE_PRIM_TRIANGLES);
308 stage->tri( stage, prim );
309 }
310
311
312 static void
313 vbuf_first_line( struct draw_stage *stage,
314 struct prim_header *prim )
315 {
316 struct vbuf_stage *vbuf = vbuf_stage( stage );
317
318 vbuf_flush_indices( vbuf );
319 stage->line = vbuf_line;
320 vbuf_set_prim(vbuf, PIPE_PRIM_LINES);
321 stage->line( stage, prim );
322 }
323
324
325 static void
326 vbuf_first_point( struct draw_stage *stage,
327 struct prim_header *prim )
328 {
329 struct vbuf_stage *vbuf = vbuf_stage( stage );
330
331 vbuf_flush_indices( vbuf );
332 stage->point = vbuf_point;
333 vbuf_set_prim(vbuf, PIPE_PRIM_POINTS);
334 stage->point( stage, prim );
335 }
336
337
338 static void
339 vbuf_flush_indices( struct vbuf_stage *vbuf )
340 {
341 if(!vbuf->nr_indices)
342 return;
343
344 assert((uint) (vbuf->vertex_ptr - vbuf->vertices) ==
345 vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
346
347 vbuf->render->draw(vbuf->render, vbuf->indices, vbuf->nr_indices);
348
349 vbuf->nr_indices = 0;
350 }
351
352
353 /**
354 * Flush existing vertex buffer and allocate a new one.
355 *
356 * XXX: We separate flush-on-index-full and flush-on-vb-full, but may
357 * raise issues uploading vertices if the hardware wants to flush when
358 * we flush.
359 */
360 static void
361 vbuf_flush_vertices( struct vbuf_stage *vbuf )
362 {
363 if(vbuf->vertices) {
364 vbuf_flush_indices(vbuf);
365
366 /* Reset temporary vertices ids */
367 if(vbuf->nr_vertices)
368 draw_reset_vertex_ids( vbuf->stage.draw );
369
370 /* Free the vertex buffer */
371 vbuf->render->release_vertices(vbuf->render,
372 vbuf->vertices,
373 vbuf->vertex_size,
374 vbuf->nr_vertices);
375 vbuf->max_vertices = vbuf->nr_vertices = 0;
376 vbuf->vertex_ptr = vbuf->vertices = NULL;
377
378 }
379 }
380
381
382 static void
383 vbuf_alloc_vertices( struct vbuf_stage *vbuf )
384 {
385 assert(!vbuf->nr_indices);
386 assert(!vbuf->vertices);
387
388 /* Allocate a new vertex buffer */
389 vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
390 vbuf->vertices = (uint *) vbuf->render->allocate_vertices(vbuf->render,
391 (ushort) vbuf->vertex_size,
392 (ushort) vbuf->max_vertices);
393 vbuf->vertex_ptr = vbuf->vertices;
394 }
395
396
397
398 static void
399 vbuf_flush( struct draw_stage *stage, unsigned flags )
400 {
401 struct vbuf_stage *vbuf = vbuf_stage( stage );
402
403 vbuf_flush_indices( vbuf );
404
405 stage->point = vbuf_first_point;
406 stage->line = vbuf_first_line;
407 stage->tri = vbuf_first_tri;
408
409 if (flags & DRAW_FLUSH_BACKEND)
410 vbuf_flush_vertices( vbuf );
411 }
412
413
414 static void
415 vbuf_reset_stipple_counter( struct draw_stage *stage )
416 {
417 /* XXX: Need to do something here for hardware with linestipple.
418 */
419 (void) stage;
420 }
421
422
423 static void vbuf_destroy( struct draw_stage *stage )
424 {
425 struct vbuf_stage *vbuf = vbuf_stage( stage );
426
427 if(vbuf->indices)
428 align_free( vbuf->indices );
429
430 if(vbuf->translate)
431 vbuf->translate->release( vbuf->translate );
432
433 if (vbuf->render)
434 vbuf->render->destroy( vbuf->render );
435
436 FREE( stage );
437 }
438
439
440 /**
441 * Create a new primitive vbuf/render stage.
442 */
443 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
444 struct vbuf_render *render )
445 {
446 struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
447 if (vbuf == NULL)
448 goto fail;
449
450 vbuf->stage.draw = draw;
451 vbuf->stage.point = vbuf_first_point;
452 vbuf->stage.line = vbuf_first_line;
453 vbuf->stage.tri = vbuf_first_tri;
454 vbuf->stage.flush = vbuf_flush;
455 vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
456 vbuf->stage.destroy = vbuf_destroy;
457
458 vbuf->render = render;
459 vbuf->max_indices = MAX2(render->max_indices, UNDEFINED_VERTEX_ID-1);
460
461 vbuf->indices = (ushort *) align_malloc( vbuf->max_indices *
462 sizeof(vbuf->indices[0]),
463 16 );
464 if (!vbuf->indices)
465 goto fail;
466
467 vbuf->vertices = NULL;
468 vbuf->vertex_ptr = vbuf->vertices;
469
470 return &vbuf->stage;
471
472 fail:
473 if (vbuf)
474 vbuf_destroy(&vbuf->stage);
475
476 return NULL;
477 }