1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
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.
34 * XXX: work in progress
36 * \author José Fonseca <jrfonseca@tungstengraphics.com>
37 * \author Keith Whitwell <keith@tungstengraphics.com>
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"
49 #include "i915_context.h"
51 #include "i915_batch.h"
52 #include "i915_state.h"
56 #undef VBUF_MAP_BUFFER
59 * Primitive renderer for i915.
61 struct i915_vbuf_render
{
62 struct vbuf_render base
;
64 struct i915_context
*i915
;
66 /** Vertex size in bytes */
69 /** Software primitive */
72 /** Hardware primitive */
75 /** Genereate a vertex list */
78 /* Stuff for the vbo */
79 struct i915_winsys_buffer
*vbo
;
80 size_t vbo_size
; /**< current size of allocated buffer */
81 size_t vbo_alloc_size
; /**< minimum buffer size to allocate */
86 #ifndef VBUF_MAP_BUFFER
87 size_t map_used_start
;
93 /* Stuff for the pool */
94 struct util_fifo
*pool_fifo
;
96 unsigned pool_buffer_size
;
97 boolean pool_not_used
;
103 * Basically a cast wrapper.
105 static INLINE
struct i915_vbuf_render
*
106 i915_vbuf_render(struct vbuf_render
*render
)
109 return (struct i915_vbuf_render
*)render
;
113 i915_vbuf_update_vbo_state(struct vbuf_render
*render
)
115 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
116 struct i915_context
*i915
= i915_render
->i915
;
118 if (i915
->vbo
!= i915_render
->vbo
||
119 i915
->vbo_offset
!= i915_render
->vbo_offset
) {
120 i915
->vbo
= i915_render
->vbo
;
121 i915
->vbo_offset
= i915_render
->vbo_offset
;
122 i915
->dirty
|= I915_NEW_VBO
;
126 static const struct vertex_info
*
127 i915_vbuf_render_get_vertex_info(struct vbuf_render
*render
)
129 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
130 struct i915_context
*i915
= i915_render
->i915
;
133 /* make sure we have up to date vertex layout */
134 i915_update_derived(i915
);
137 return &i915
->current
.vertex_info
;
141 i915_vbuf_render_reserve(struct i915_vbuf_render
*i915_render
, size_t size
)
143 struct i915_context
*i915
= i915_render
->i915
;
145 if (i915_render
->vbo_size
< size
+ i915_render
->vbo_offset
)
148 if (i915
->vbo_flushed
)
155 i915_vbuf_render_new_buf(struct i915_vbuf_render
*i915_render
, size_t size
)
157 struct i915_context
*i915
= i915_render
->i915
;
158 struct i915_winsys
*iws
= i915
->iws
;
160 if (i915_render
->vbo
) {
162 if (i915_render
->pool_not_used
)
163 iws
->buffer_destroy(iws
, i915_render
->vbo
);
165 u_fifo_add(i915_render
->pool_fifo
, i915_render
->vbo
);
166 i915_render
->vbo
= NULL
;
168 iws
->buffer_destroy(iws
, i915_render
->vbo
);
172 i915
->vbo_flushed
= 0;
174 i915_render
->vbo_size
= MAX2(size
, i915_render
->vbo_alloc_size
);
175 i915_render
->vbo_offset
= 0;
177 #ifndef VBUF_MAP_BUFFER
178 if (i915_render
->vbo_size
> i915_render
->map_size
) {
179 i915_render
->map_size
= i915_render
->vbo_size
;
180 FREE(i915_render
->vbo_ptr
);
181 i915_render
->vbo_ptr
= MALLOC(i915_render
->map_size
);
186 if (i915_render
->vbo_size
!= i915_render
->pool_buffer_size
) {
187 i915_render
->pool_not_used
= TRUE
;
188 i915_render
->vbo
= iws
->buffer_create(iws
, i915_render
->vbo_size
, 64,
191 i915_render
->pool_not_used
= FALSE
;
193 if (i915_render
->pool_used
>= 2) {
195 i915
->vbo_flushed
= 0;
196 i915_render
->pool_used
= 0;
198 u_fifo_pop(i915_render
->pool_fifo
, (void**)&i915_render
->vbo
);
201 i915_render
->vbo
= iws
->buffer_create(iws
, i915_render
->vbo_size
,
202 64, I915_NEW_VERTEX
);
207 i915_vbuf_render_allocate_vertices(struct vbuf_render
*render
,
211 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
212 size_t size
= (size_t)vertex_size
* (size_t)nr_vertices
;
214 if (!i915_vbuf_render_reserve(i915_render
, size
)) {
216 /* incase we flushed reset the number of pool buffers used */
217 if (i915
->vbo_flushed
)
218 i915_render
->pool_used
= 0;
220 i915_vbuf_render_new_buf(i915_render
, size
);
223 i915_render
->vertex_size
= vertex_size
;
225 i915_vbuf_update_vbo_state(render
);
227 if (!i915_render
->vbo
)
233 i915_vbuf_render_map_vertices(struct vbuf_render
*render
)
235 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
236 struct i915_context
*i915
= i915_render
->i915
;
237 struct i915_winsys
*iws
= i915
->iws
;
239 if (i915
->vbo_flushed
)
240 debug_printf("%s bad vbo flush occured stalling on hw\n", __FUNCTION__
);
242 #ifdef VBUF_MAP_BUFFER
243 i915_render
->vbo_ptr
= iws
->buffer_map(iws
, i915_render
->vbo
, TRUE
);
244 return (unsigned char *)i915_render
->vbo_ptr
+ i915_render
->vbo_offset
;
247 return (unsigned char *)i915_render
->vbo_ptr
;
252 i915_vbuf_render_unmap_vertices(struct vbuf_render
*render
,
256 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
257 struct i915_context
*i915
= i915_render
->i915
;
258 struct i915_winsys
*iws
= i915
->iws
;
260 i915_render
->vbo_max_used
= MAX2(i915_render
->vbo_max_used
, i915_render
->vertex_size
* (max_index
+ 1));
261 #ifdef VBUF_MAP_BUFFER
262 iws
->buffer_unmap(iws
, i915_render
->vbo
);
264 i915_render
->map_used_start
= i915_render
->vertex_size
* min_index
;
265 i915_render
->map_used_end
= i915_render
->vertex_size
* (max_index
+ 1);
266 iws
->buffer_write(iws
, i915_render
->vbo
,
267 i915_render
->map_used_start
+ i915_render
->vbo_offset
,
268 i915_render
->map_used_end
- i915_render
->map_used_start
,
269 (unsigned char *)i915_render
->vbo_ptr
+ i915_render
->map_used_start
);
275 i915_vbuf_render_set_primitive(struct vbuf_render
*render
,
278 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
279 i915_render
->prim
= prim
;
282 case PIPE_PRIM_POINTS
:
283 i915_render
->hwprim
= PRIM3D_POINTLIST
;
284 i915_render
->fallback
= 0;
286 case PIPE_PRIM_LINES
:
287 i915_render
->hwprim
= PRIM3D_LINELIST
;
288 i915_render
->fallback
= 0;
290 case PIPE_PRIM_LINE_LOOP
:
291 i915_render
->hwprim
= PRIM3D_LINELIST
;
292 i915_render
->fallback
= PIPE_PRIM_LINE_LOOP
;
294 case PIPE_PRIM_LINE_STRIP
:
295 i915_render
->hwprim
= PRIM3D_LINESTRIP
;
296 i915_render
->fallback
= 0;
298 case PIPE_PRIM_TRIANGLES
:
299 i915_render
->hwprim
= PRIM3D_TRILIST
;
300 i915_render
->fallback
= 0;
302 case PIPE_PRIM_TRIANGLE_STRIP
:
303 i915_render
->hwprim
= PRIM3D_TRISTRIP
;
304 i915_render
->fallback
= 0;
306 case PIPE_PRIM_TRIANGLE_FAN
:
307 i915_render
->hwprim
= PRIM3D_TRIFAN
;
308 i915_render
->fallback
= 0;
310 case PIPE_PRIM_QUADS
:
311 i915_render
->hwprim
= PRIM3D_TRILIST
;
312 i915_render
->fallback
= PIPE_PRIM_QUADS
;
314 case PIPE_PRIM_QUAD_STRIP
:
315 i915_render
->hwprim
= PRIM3D_TRILIST
;
316 i915_render
->fallback
= PIPE_PRIM_QUAD_STRIP
;
318 case PIPE_PRIM_POLYGON
:
319 i915_render
->hwprim
= PRIM3D_POLY
;
320 i915_render
->fallback
= 0;
323 /* FIXME: Actually, can handle a lot more just fine... */
329 * Used for fallbacks in draw_arrays
332 draw_arrays_generate_indices(struct vbuf_render
*render
,
333 unsigned start
, uint nr
,
336 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
337 struct i915_context
*i915
= i915_render
->i915
;
339 unsigned end
= start
+ nr
;
342 for (i
= start
; i
+1 < end
; i
+= 2)
343 OUT_BATCH((i
+0) | (i
+1) << 16);
347 case PIPE_PRIM_LINE_LOOP
:
349 for (i
= start
+ 1; i
< end
; i
++)
350 OUT_BATCH((i
-0) | (i
+0) << 16);
351 OUT_BATCH((i
-0) | ( start
) << 16);
354 case PIPE_PRIM_QUADS
:
355 for (i
= start
; i
+ 3 < end
; i
+= 4) {
356 OUT_BATCH((i
+0) | (i
+1) << 16);
357 OUT_BATCH((i
+3) | (i
+1) << 16);
358 OUT_BATCH((i
+2) | (i
+3) << 16);
361 case PIPE_PRIM_QUAD_STRIP
:
362 for (i
= start
; i
+ 3 < end
; i
+= 2) {
363 OUT_BATCH((i
+0) | (i
+1) << 16);
364 OUT_BATCH((i
+3) | (i
+2) << 16);
365 OUT_BATCH((i
+0) | (i
+3) << 16);
374 draw_arrays_calc_nr_indices(uint nr
, unsigned type
)
379 case PIPE_PRIM_LINE_LOOP
:
384 case PIPE_PRIM_QUADS
:
386 case PIPE_PRIM_QUAD_STRIP
:
387 return ((nr
- 2) / 2) * 6;
395 draw_arrays_fallback(struct vbuf_render
*render
,
399 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
400 struct i915_context
*i915
= i915_render
->i915
;
404 i915_update_derived(i915
);
406 if (i915
->hardware_dirty
)
407 i915_emit_hardware_state(i915
);
409 nr_indices
= draw_arrays_calc_nr_indices(nr
, i915_render
->fallback
);
413 if (!BEGIN_BATCH(1 + (nr_indices
+ 1)/2, 1)) {
416 /* Make sure state is re-emitted after a flush:
418 i915_update_derived(i915
);
419 i915_emit_hardware_state(i915
);
420 i915
->vbo_flushed
= 1;
422 if (!BEGIN_BATCH(1 + (nr_indices
+ 1)/2, 1)) {
428 OUT_BATCH(_3DPRIMITIVE
|
430 i915_render
->hwprim
|
434 draw_arrays_generate_indices(render
, start
, nr
, i915_render
->fallback
);
441 i915_vbuf_render_draw_arrays(struct vbuf_render
*render
,
445 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
446 struct i915_context
*i915
= i915_render
->i915
;
448 if (i915_render
->fallback
) {
449 draw_arrays_fallback(render
, start
, nr
);
454 i915_update_derived(i915
);
456 if (i915
->hardware_dirty
)
457 i915_emit_hardware_state(i915
);
459 if (!BEGIN_BATCH(2, 0)) {
462 /* Make sure state is re-emitted after a flush:
464 i915_update_derived(i915
);
465 i915_emit_hardware_state(i915
);
466 i915
->vbo_flushed
= 1;
468 if (!BEGIN_BATCH(2, 0)) {
474 OUT_BATCH(_3DPRIMITIVE
|
476 PRIM_INDIRECT_SEQUENTIAL
|
477 i915_render
->hwprim
|
479 OUT_BATCH(start
); /* Beginning vertex index */
486 * Used for normal and fallback emitting of indices
487 * If type is zero normal operation assumed.
490 draw_generate_indices(struct vbuf_render
*render
,
491 const ushort
*indices
,
495 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
496 struct i915_context
*i915
= i915_render
->i915
;
501 for (i
= 0; i
+ 1 < nr_indices
; i
+= 2) {
502 OUT_BATCH(indices
[i
] | indices
[i
+1] << 16);
504 if (i
< nr_indices
) {
505 OUT_BATCH(indices
[i
]);
508 case PIPE_PRIM_LINE_LOOP
:
509 if (nr_indices
>= 2) {
510 for (i
= 1; i
< nr_indices
; i
++)
511 OUT_BATCH(indices
[i
-1] | indices
[i
] << 16);
512 OUT_BATCH(indices
[i
-1] | indices
[0] << 16);
515 case PIPE_PRIM_QUADS
:
516 for (i
= 0; i
+ 3 < nr_indices
; i
+= 4) {
517 OUT_BATCH(indices
[i
+0] | indices
[i
+1] << 16);
518 OUT_BATCH(indices
[i
+3] | indices
[i
+1] << 16);
519 OUT_BATCH(indices
[i
+2] | indices
[i
+3] << 16);
522 case PIPE_PRIM_QUAD_STRIP
:
523 for (i
= 0; i
+ 3 < nr_indices
; i
+= 2) {
524 OUT_BATCH(indices
[i
+0] | indices
[i
+1] << 16);
525 OUT_BATCH(indices
[i
+3] | indices
[i
+2] << 16);
526 OUT_BATCH(indices
[i
+0] | indices
[i
+3] << 16);
536 draw_calc_nr_indices(uint nr_indices
, unsigned type
)
541 case PIPE_PRIM_LINE_LOOP
:
543 return nr_indices
* 2;
546 case PIPE_PRIM_QUADS
:
547 return (nr_indices
/ 4) * 6;
548 case PIPE_PRIM_QUAD_STRIP
:
549 return ((nr_indices
- 2) / 2) * 6;
557 i915_vbuf_render_draw_elements(struct vbuf_render
*render
,
558 const ushort
*indices
,
561 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
562 struct i915_context
*i915
= i915_render
->i915
;
563 unsigned save_nr_indices
;
565 save_nr_indices
= nr_indices
;
567 nr_indices
= draw_calc_nr_indices(nr_indices
, i915_render
->fallback
);
572 i915_update_derived(i915
);
574 if (i915
->hardware_dirty
)
575 i915_emit_hardware_state(i915
);
577 if (!BEGIN_BATCH(1 + (nr_indices
+ 1)/2, 1)) {
580 /* Make sure state is re-emitted after a flush:
582 i915_update_derived(i915
);
583 i915_emit_hardware_state(i915
);
584 i915
->vbo_flushed
= 1;
586 if (!BEGIN_BATCH(1 + (nr_indices
+ 1)/2, 1)) {
592 OUT_BATCH(_3DPRIMITIVE
|
594 i915_render
->hwprim
|
597 draw_generate_indices(render
,
600 i915_render
->fallback
);
607 i915_vbuf_render_release_vertices(struct vbuf_render
*render
)
609 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
611 i915_render
->vbo_offset
+= i915_render
->vbo_max_used
;
612 i915_render
->vbo_max_used
= 0;
615 * Micro optimization, by calling update here we the offset change
616 * will be picked up on the next pipe_context::draw_*.
618 i915_vbuf_update_vbo_state(render
);
622 i915_vbuf_render_destroy(struct vbuf_render
*render
)
624 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
629 * Create a new primitive render.
631 static struct vbuf_render
*
632 i915_vbuf_render_create(struct i915_context
*i915
)
634 struct i915_vbuf_render
*i915_render
= CALLOC_STRUCT(i915_vbuf_render
);
635 struct i915_winsys
*iws
= i915
->iws
;
638 i915_render
->i915
= i915
;
640 i915_render
->base
.max_vertex_buffer_bytes
= 16*4096;
642 /* NOTE: it must be such that state and vertices indices fit in a single
645 i915_render
->base
.max_indices
= 16*1024;
647 i915_render
->base
.get_vertex_info
= i915_vbuf_render_get_vertex_info
;
648 i915_render
->base
.allocate_vertices
= i915_vbuf_render_allocate_vertices
;
649 i915_render
->base
.map_vertices
= i915_vbuf_render_map_vertices
;
650 i915_render
->base
.unmap_vertices
= i915_vbuf_render_unmap_vertices
;
651 i915_render
->base
.set_primitive
= i915_vbuf_render_set_primitive
;
652 i915_render
->base
.draw_elements
= i915_vbuf_render_draw_elements
;
653 i915_render
->base
.draw_arrays
= i915_vbuf_render_draw_arrays
;
654 i915_render
->base
.release_vertices
= i915_vbuf_render_release_vertices
;
655 i915_render
->base
.destroy
= i915_vbuf_render_destroy
;
657 #ifndef VBUF_MAP_BUFFER
658 i915_render
->map_size
= 0;
659 i915_render
->map_used_start
= 0;
660 i915_render
->map_used_end
= 0;
663 i915_render
->vbo
= NULL
;
664 i915_render
->vbo_ptr
= NULL
;
665 i915_render
->vbo_size
= 0;
666 i915_render
->vbo_offset
= 0;
667 i915_render
->vbo_alloc_size
= i915_render
->base
.max_vertex_buffer_bytes
* 4;
670 i915_render
->pool_used
= FALSE
;
671 i915_render
->pool_buffer_size
= i915_render
->vbo_alloc_size
;
672 i915_render
->pool_fifo
= u_fifo_create(6);
673 for (i
= 0; i
< 6; i
++)
674 u_fifo_add(i915_render
->pool_fifo
,
675 iws
->buffer_create(iws
, i915_render
->pool_buffer_size
, 64,
682 return &i915_render
->base
;
686 * Create a new primitive vbuf/render stage.
688 struct draw_stage
*i915_draw_vbuf_stage(struct i915_context
*i915
)
690 struct vbuf_render
*render
;
691 struct draw_stage
*stage
;
693 render
= i915_vbuf_render_create(i915
);
697 stage
= draw_vbuf_stage(i915
->draw
, render
);
699 render
->destroy(render
);
702 /** TODO JB: this shouldn't be here */
703 draw_set_render(i915
->draw
, render
);