gallium: pipe/p_inlines.h -> util/u_inlines.h
[mesa.git] / src / gallium / drivers / i915 / i915_prim_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 * Build post-transformation, post-clipping vertex buffers and element
31 * lists by hooking into the end of the primitive pipeline and
32 * manipulating the vertex_id field in the vertex headers.
33 *
34 * XXX: work in progress
35 *
36 * \author José Fonseca <jrfonseca@tungstengraphics.com>
37 * \author Keith Whitwell <keith@tungstengraphics.com>
38 */
39
40
41 #include "draw/draw_context.h"
42 #include "draw/draw_vbuf.h"
43 #include "util/u_debug.h"
44 #include "util/u_inlines.h"
45 #include "util/u_math.h"
46 #include "util/u_memory.h"
47 #include "util/u_fifo.h"
48
49 #include "i915_context.h"
50 #include "i915_reg.h"
51 #include "i915_batch.h"
52 #include "i915_state.h"
53
54
55 #undef VBUF_USE_FIFO
56 #undef VBUF_MAP_BUFFER
57
58 /**
59 * Primitive renderer for i915.
60 */
61 struct i915_vbuf_render {
62 struct vbuf_render base;
63
64 struct i915_context *i915;
65
66 /** Vertex size in bytes */
67 size_t vertex_size;
68
69 /** Software primitive */
70 unsigned prim;
71
72 /** Hardware primitive */
73 unsigned hwprim;
74
75 /** Genereate a vertex list */
76 unsigned fallback;
77
78 /* Stuff for the vbo */
79 struct intel_buffer *vbo;
80 size_t vbo_size; /**< current size of allocated buffer */
81 size_t vbo_alloc_size; /**< minimum buffer size to allocate */
82 size_t vbo_offset;
83 void *vbo_ptr;
84 size_t vbo_max_used;
85
86 #ifndef VBUF_MAP_BUFFER
87 size_t map_used_start;
88 size_t map_used_end;
89 size_t map_size;
90 #endif
91
92 #ifdef VBUF_USE_FIFO
93 /* Stuff for the pool */
94 struct util_fifo *pool_fifo;
95 unsigned pool_used;
96 unsigned pool_buffer_size;
97 boolean pool_not_used;
98 #endif
99 };
100
101
102 /**
103 * Basically a cast wrapper.
104 */
105 static INLINE struct i915_vbuf_render *
106 i915_vbuf_render(struct vbuf_render *render)
107 {
108 assert(render);
109 return (struct i915_vbuf_render *)render;
110 }
111
112 static const struct vertex_info *
113 i915_vbuf_render_get_vertex_info(struct vbuf_render *render)
114 {
115 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
116 struct i915_context *i915 = i915_render->i915;
117
118 if (i915->dirty) {
119 /* make sure we have up to date vertex layout */
120 i915_update_derived(i915);
121 }
122
123 return &i915->current.vertex_info;
124 }
125
126 static boolean
127 i915_vbuf_render_reserve(struct i915_vbuf_render *i915_render, size_t size)
128 {
129 struct i915_context *i915 = i915_render->i915;
130
131 if (i915_render->vbo_size < size + i915_render->vbo_offset)
132 return FALSE;
133
134 if (i915->vbo_flushed)
135 return FALSE;
136
137 return TRUE;
138 }
139
140 static void
141 i915_vbuf_render_new_buf(struct i915_vbuf_render *i915_render, size_t size)
142 {
143 struct i915_context *i915 = i915_render->i915;
144 struct intel_winsys *iws = i915->iws;
145
146 if (i915_render->vbo) {
147 #ifdef VBUF_USE_FIFO
148 if (i915_render->pool_not_used)
149 iws->buffer_destroy(iws, i915_render->vbo);
150 else
151 u_fifo_add(i915_render->pool_fifo, i915_render->vbo);
152 i915_render->vbo = NULL;
153 #else
154 iws->buffer_destroy(iws, i915_render->vbo);
155 #endif
156 }
157
158 i915->vbo_flushed = 0;
159
160 i915_render->vbo_size = MAX2(size, i915_render->vbo_alloc_size);
161 i915_render->vbo_offset = 0;
162
163 #ifndef VBUF_MAP_BUFFER
164 if (i915_render->vbo_size > i915_render->map_size) {
165 i915_render->map_size = i915_render->vbo_size;
166 FREE(i915_render->vbo_ptr);
167 i915_render->vbo_ptr = MALLOC(i915_render->map_size);
168 }
169 #endif
170
171 #ifdef VBUF_USE_FIFO
172 if (i915_render->vbo_size != i915_render->pool_buffer_size) {
173 i915_render->pool_not_used = TRUE;
174 i915_render->vbo = iws->buffer_create(iws, i915_render->vbo_size, 64,
175 INTEL_NEW_VERTEX);
176 } else {
177 i915_render->pool_not_used = FALSE;
178
179 if (i915_render->pool_used >= 2) {
180 FLUSH_BATCH(NULL);
181 i915->vbo_flushed = 0;
182 i915_render->pool_used = 0;
183 }
184 u_fifo_pop(i915_render->pool_fifo, (void**)&i915_render->vbo);
185 }
186 #else
187 i915_render->vbo = iws->buffer_create(iws, i915_render->vbo_size,
188 64, INTEL_NEW_VERTEX);
189 #endif
190 }
191
192 static boolean
193 i915_vbuf_render_allocate_vertices(struct vbuf_render *render,
194 ushort vertex_size,
195 ushort nr_vertices)
196 {
197 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
198 struct i915_context *i915 = i915_render->i915;
199 size_t size = (size_t)vertex_size * (size_t)nr_vertices;
200
201 /* FIXME: handle failure */
202 assert(!i915->vbo);
203
204 if (!i915_vbuf_render_reserve(i915_render, size)) {
205 #ifdef VBUF_USE_FIFO
206 /* incase we flushed reset the number of pool buffers used */
207 if (i915->vbo_flushed)
208 i915_render->pool_used = 0;
209 #endif
210 i915_vbuf_render_new_buf(i915_render, size);
211 }
212
213 i915_render->vertex_size = vertex_size;
214 i915->vbo = i915_render->vbo;
215 i915->vbo_offset = i915_render->vbo_offset;
216 i915->dirty |= I915_NEW_VBO;
217
218 if (!i915_render->vbo)
219 return FALSE;
220 return TRUE;
221 }
222
223 static void *
224 i915_vbuf_render_map_vertices(struct vbuf_render *render)
225 {
226 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
227 struct i915_context *i915 = i915_render->i915;
228 struct intel_winsys *iws = i915->iws;
229
230 if (i915->vbo_flushed)
231 debug_printf("%s bad vbo flush occured stalling on hw\n", __FUNCTION__);
232
233 #ifdef VBUF_MAP_BUFFER
234 i915_render->vbo_ptr = iws->buffer_map(iws, i915_render->vbo, TRUE);
235 return (unsigned char *)i915_render->vbo_ptr + i915_render->vbo_offset;
236 #else
237 (void)iws;
238 return (unsigned char *)i915_render->vbo_ptr;
239 #endif
240 }
241
242 static void
243 i915_vbuf_render_unmap_vertices(struct vbuf_render *render,
244 ushort min_index,
245 ushort max_index)
246 {
247 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
248 struct i915_context *i915 = i915_render->i915;
249 struct intel_winsys *iws = i915->iws;
250
251 i915_render->vbo_max_used = MAX2(i915_render->vbo_max_used, i915_render->vertex_size * (max_index + 1));
252 #ifdef VBUF_MAP_BUFFER
253 iws->buffer_unmap(iws, i915_render->vbo);
254 #else
255 i915_render->map_used_start = i915_render->vertex_size * min_index;
256 i915_render->map_used_end = i915_render->vertex_size * (max_index + 1);
257 iws->buffer_write(iws, i915_render->vbo,
258 i915_render->map_used_start + i915_render->vbo_offset,
259 i915_render->map_used_end - i915_render->map_used_start,
260 (unsigned char *)i915_render->vbo_ptr + i915_render->map_used_start);
261
262 #endif
263 }
264
265 static boolean
266 i915_vbuf_render_set_primitive(struct vbuf_render *render,
267 unsigned prim)
268 {
269 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
270 i915_render->prim = prim;
271
272 switch(prim) {
273 case PIPE_PRIM_POINTS:
274 i915_render->hwprim = PRIM3D_POINTLIST;
275 i915_render->fallback = 0;
276 return TRUE;
277 case PIPE_PRIM_LINES:
278 i915_render->hwprim = PRIM3D_LINELIST;
279 i915_render->fallback = 0;
280 return TRUE;
281 case PIPE_PRIM_LINE_LOOP:
282 i915_render->hwprim = PRIM3D_LINELIST;
283 i915_render->fallback = PIPE_PRIM_LINE_LOOP;
284 return TRUE;
285 case PIPE_PRIM_LINE_STRIP:
286 i915_render->hwprim = PRIM3D_LINESTRIP;
287 i915_render->fallback = 0;
288 return TRUE;
289 case PIPE_PRIM_TRIANGLES:
290 i915_render->hwprim = PRIM3D_TRILIST;
291 i915_render->fallback = 0;
292 return TRUE;
293 case PIPE_PRIM_TRIANGLE_STRIP:
294 i915_render->hwprim = PRIM3D_TRISTRIP;
295 i915_render->fallback = 0;
296 return TRUE;
297 case PIPE_PRIM_TRIANGLE_FAN:
298 i915_render->hwprim = PRIM3D_TRIFAN;
299 i915_render->fallback = 0;
300 return TRUE;
301 case PIPE_PRIM_QUADS:
302 i915_render->hwprim = PRIM3D_TRILIST;
303 i915_render->fallback = PIPE_PRIM_QUADS;
304 return TRUE;
305 case PIPE_PRIM_QUAD_STRIP:
306 i915_render->hwprim = PRIM3D_TRILIST;
307 i915_render->fallback = PIPE_PRIM_QUAD_STRIP;
308 return TRUE;
309 case PIPE_PRIM_POLYGON:
310 i915_render->hwprim = PRIM3D_POLY;
311 i915_render->fallback = 0;
312 return TRUE;
313 default:
314 /* FIXME: Actually, can handle a lot more just fine... */
315 return FALSE;
316 }
317 }
318
319 /**
320 * Used for fallbacks in draw_arrays
321 */
322 static void
323 draw_arrays_generate_indices(struct vbuf_render *render,
324 unsigned start, uint nr,
325 unsigned type)
326 {
327 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
328 struct i915_context *i915 = i915_render->i915;
329 unsigned i;
330 unsigned end = start + nr;
331 switch(type) {
332 case 0:
333 for (i = start; i+1 < end; i += 2)
334 OUT_BATCH((i+0) | (i+1) << 16);
335 if (i < end)
336 OUT_BATCH(i);
337 break;
338 case PIPE_PRIM_LINE_LOOP:
339 if (nr >= 2) {
340 for (i = start + 1; i < end; i++)
341 OUT_BATCH((i-0) | (i+0) << 16);
342 OUT_BATCH((i-0) | ( start) << 16);
343 }
344 break;
345 case PIPE_PRIM_QUADS:
346 for (i = start; i + 3 < end; i += 4) {
347 OUT_BATCH((i+0) | (i+1) << 16);
348 OUT_BATCH((i+3) | (i+1) << 16);
349 OUT_BATCH((i+2) | (i+3) << 16);
350 }
351 break;
352 case PIPE_PRIM_QUAD_STRIP:
353 for (i = start; i + 3 < end; i += 2) {
354 OUT_BATCH((i+0) | (i+1) << 16);
355 OUT_BATCH((i+3) | (i+2) << 16);
356 OUT_BATCH((i+0) | (i+3) << 16);
357 }
358 break;
359 default:
360 assert(0);
361 }
362 }
363
364 static unsigned
365 draw_arrays_calc_nr_indices(uint nr, unsigned type)
366 {
367 switch (type) {
368 case 0:
369 return nr;
370 case PIPE_PRIM_LINE_LOOP:
371 if (nr >= 2)
372 return nr * 2;
373 else
374 return 0;
375 case PIPE_PRIM_QUADS:
376 return (nr / 4) * 6;
377 case PIPE_PRIM_QUAD_STRIP:
378 return ((nr - 2) / 2) * 6;
379 default:
380 assert(0);
381 return 0;
382 }
383 }
384
385 static void
386 draw_arrays_fallback(struct vbuf_render *render,
387 unsigned start,
388 uint nr)
389 {
390 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
391 struct i915_context *i915 = i915_render->i915;
392 unsigned nr_indices;
393
394 if (i915->dirty)
395 i915_update_derived(i915);
396
397 if (i915->hardware_dirty)
398 i915_emit_hardware_state(i915);
399
400 nr_indices = draw_arrays_calc_nr_indices(nr, i915_render->fallback);
401 if (!nr_indices)
402 return;
403
404 if (!BEGIN_BATCH(1 + (nr_indices + 1)/2, 1)) {
405 FLUSH_BATCH(NULL);
406
407 /* Make sure state is re-emitted after a flush:
408 */
409 i915_update_derived(i915);
410 i915_emit_hardware_state(i915);
411 i915->vbo_flushed = 1;
412
413 if (!BEGIN_BATCH(1 + (nr_indices + 1)/2, 1)) {
414 assert(0);
415 goto out;
416 }
417 }
418 OUT_BATCH(_3DPRIMITIVE |
419 PRIM_INDIRECT |
420 i915_render->hwprim |
421 PRIM_INDIRECT_ELTS |
422 nr_indices);
423
424 draw_arrays_generate_indices(render, start, nr, i915_render->fallback);
425
426 out:
427 return;
428 }
429
430 static void
431 i915_vbuf_render_draw_arrays(struct vbuf_render *render,
432 unsigned start,
433 uint nr)
434 {
435 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
436 struct i915_context *i915 = i915_render->i915;
437
438 if (i915_render->fallback) {
439 draw_arrays_fallback(render, start, nr);
440 return;
441 }
442
443 if (i915->dirty)
444 i915_update_derived(i915);
445
446 if (i915->hardware_dirty)
447 i915_emit_hardware_state(i915);
448
449 if (!BEGIN_BATCH(2, 0)) {
450 FLUSH_BATCH(NULL);
451
452 /* Make sure state is re-emitted after a flush:
453 */
454 i915_update_derived(i915);
455 i915_emit_hardware_state(i915);
456 i915->vbo_flushed = 1;
457
458 if (!BEGIN_BATCH(2, 0)) {
459 assert(0);
460 goto out;
461 }
462 }
463
464 OUT_BATCH(_3DPRIMITIVE |
465 PRIM_INDIRECT |
466 PRIM_INDIRECT_SEQUENTIAL |
467 i915_render->hwprim |
468 nr);
469 OUT_BATCH(start); /* Beginning vertex index */
470
471 out:
472 return;
473 }
474
475 /**
476 * Used for normal and fallback emitting of indices
477 * If type is zero normal operation assumed.
478 */
479 static void
480 draw_generate_indices(struct vbuf_render *render,
481 const ushort *indices,
482 uint nr_indices,
483 unsigned type)
484 {
485 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
486 struct i915_context *i915 = i915_render->i915;
487 unsigned i;
488
489 switch(type) {
490 case 0:
491 for (i = 0; i + 1 < nr_indices; i += 2) {
492 OUT_BATCH(indices[i] | indices[i+1] << 16);
493 }
494 if (i < nr_indices) {
495 OUT_BATCH(indices[i]);
496 }
497 break;
498 case PIPE_PRIM_LINE_LOOP:
499 if (nr_indices >= 2) {
500 for (i = 1; i < nr_indices; i++)
501 OUT_BATCH(indices[i-1] | indices[i] << 16);
502 OUT_BATCH(indices[i-1] | indices[0] << 16);
503 }
504 break;
505 case PIPE_PRIM_QUADS:
506 for (i = 0; i + 3 < nr_indices; i += 4) {
507 OUT_BATCH(indices[i+0] | indices[i+1] << 16);
508 OUT_BATCH(indices[i+3] | indices[i+1] << 16);
509 OUT_BATCH(indices[i+2] | indices[i+3] << 16);
510 }
511 break;
512 case PIPE_PRIM_QUAD_STRIP:
513 for (i = 0; i + 3 < nr_indices; i += 2) {
514 OUT_BATCH(indices[i+0] | indices[i+1] << 16);
515 OUT_BATCH(indices[i+3] | indices[i+2] << 16);
516 OUT_BATCH(indices[i+0] | indices[i+3] << 16);
517 }
518 break;
519 default:
520 assert(0);
521 break;
522 }
523 }
524
525 static unsigned
526 draw_calc_nr_indices(uint nr_indices, unsigned type)
527 {
528 switch (type) {
529 case 0:
530 return nr_indices;
531 case PIPE_PRIM_LINE_LOOP:
532 if (nr_indices >= 2)
533 return nr_indices * 2;
534 else
535 return 0;
536 case PIPE_PRIM_QUADS:
537 return (nr_indices / 4) * 6;
538 case PIPE_PRIM_QUAD_STRIP:
539 return ((nr_indices - 2) / 2) * 6;
540 default:
541 assert(0);
542 return 0;
543 }
544 }
545
546 static void
547 i915_vbuf_render_draw(struct vbuf_render *render,
548 const ushort *indices,
549 uint nr_indices)
550 {
551 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
552 struct i915_context *i915 = i915_render->i915;
553 unsigned save_nr_indices;
554
555 save_nr_indices = nr_indices;
556
557 nr_indices = draw_calc_nr_indices(nr_indices, i915_render->fallback);
558 if (!nr_indices)
559 return;
560
561 if (i915->dirty)
562 i915_update_derived(i915);
563
564 if (i915->hardware_dirty)
565 i915_emit_hardware_state(i915);
566
567 if (!BEGIN_BATCH(1 + (nr_indices + 1)/2, 1)) {
568 FLUSH_BATCH(NULL);
569
570 /* Make sure state is re-emitted after a flush:
571 */
572 i915_update_derived(i915);
573 i915_emit_hardware_state(i915);
574 i915->vbo_flushed = 1;
575
576 if (!BEGIN_BATCH(1 + (nr_indices + 1)/2, 1)) {
577 assert(0);
578 goto out;
579 }
580 }
581
582 OUT_BATCH(_3DPRIMITIVE |
583 PRIM_INDIRECT |
584 i915_render->hwprim |
585 PRIM_INDIRECT_ELTS |
586 nr_indices);
587 draw_generate_indices(render,
588 indices,
589 save_nr_indices,
590 i915_render->fallback);
591
592 out:
593 return;
594 }
595
596 static void
597 i915_vbuf_render_release_vertices(struct vbuf_render *render)
598 {
599 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
600 struct i915_context *i915 = i915_render->i915;
601
602 assert(i915->vbo);
603
604 i915_render->vbo_offset += i915_render->vbo_max_used;
605 i915_render->vbo_max_used = 0;
606 i915->vbo = NULL;
607 i915->dirty |= I915_NEW_VBO;
608 }
609
610 static void
611 i915_vbuf_render_destroy(struct vbuf_render *render)
612 {
613 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
614 FREE(i915_render);
615 }
616
617 /**
618 * Create a new primitive render.
619 */
620 static struct vbuf_render *
621 i915_vbuf_render_create(struct i915_context *i915)
622 {
623 struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
624 struct intel_winsys *iws = i915->iws;
625 int i;
626
627 i915_render->i915 = i915;
628
629 i915_render->base.max_vertex_buffer_bytes = 16*4096;
630
631 /* NOTE: it must be such that state and vertices indices fit in a single
632 * batch buffer.
633 */
634 i915_render->base.max_indices = 16*1024;
635
636 i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
637 i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
638 i915_render->base.map_vertices = i915_vbuf_render_map_vertices;
639 i915_render->base.unmap_vertices = i915_vbuf_render_unmap_vertices;
640 i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
641 i915_render->base.draw = i915_vbuf_render_draw;
642 i915_render->base.draw_arrays = i915_vbuf_render_draw_arrays;
643 i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
644 i915_render->base.destroy = i915_vbuf_render_destroy;
645
646 #ifndef VBUF_MAP_BUFFER
647 i915_render->map_size = 0;
648 i915_render->map_used_start = 0;
649 i915_render->map_used_end = 0;
650 #endif
651
652 i915_render->vbo = NULL;
653 i915_render->vbo_ptr = NULL;
654 i915_render->vbo_size = 0;
655 i915_render->vbo_offset = 0;
656 i915_render->vbo_alloc_size = i915_render->base.max_vertex_buffer_bytes * 4;
657
658 #ifdef VBUF_USE_POOL
659 i915_render->pool_used = FALSE;
660 i915_render->pool_buffer_size = i915_render->vbo_alloc_size;
661 i915_render->pool_fifo = u_fifo_create(6);
662 for (i = 0; i < 6; i++)
663 u_fifo_add(i915_render->pool_fifo,
664 iws->buffer_create(iws, i915_render->pool_buffer_size, 64,
665 INTEL_NEW_VERTEX));
666 #else
667 (void)i;
668 (void)iws;
669 #endif
670
671 return &i915_render->base;
672 }
673
674 /**
675 * Create a new primitive vbuf/render stage.
676 */
677 struct draw_stage *i915_draw_vbuf_stage(struct i915_context *i915)
678 {
679 struct vbuf_render *render;
680 struct draw_stage *stage;
681
682 render = i915_vbuf_render_create(i915);
683 if(!render)
684 return NULL;
685
686 stage = draw_vbuf_stage(i915->draw, render);
687 if(!stage) {
688 render->destroy(render);
689 return NULL;
690 }
691 /** TODO JB: this shouldn't be here */
692 draw_set_render(i915->draw, render);
693
694 return stage;
695 }