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_vbuf.h"
42 #include "pipe/p_debug.h"
43 #include "pipe/p_util.h"
44 #include "pipe/p_inlines.h"
45 #include "pipe/p_winsys.h"
47 #include "i915_context.h"
49 #include "i915_winsys.h"
50 #include "i915_batch.h"
51 #include "i915_state.h"
55 * Primitive renderer for i915.
57 struct i915_vbuf_render
{
58 struct vbuf_render base
;
60 struct i915_context
*i915
;
62 /** Vertex size in bytes */
65 /** Software primitive */
68 /** Hardware primitive */
71 /** Genereate a vertex list */
74 /* Stuff for the vbo */
75 struct pipe_buffer
*vbo
;
79 size_t vbo_alloc_size
;
84 * Basically a cast wrapper.
86 static INLINE
struct i915_vbuf_render
*
87 i915_vbuf_render( struct vbuf_render
*render
)
90 return (struct i915_vbuf_render
*)render
;
94 static const struct vertex_info
*
95 i915_vbuf_render_get_vertex_info( struct vbuf_render
*render
)
97 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
98 struct i915_context
*i915
= i915_render
->i915
;
101 /* make sure we have up to date vertex layout */
102 i915_update_derived( i915
);
105 return &i915
->current
.vertex_info
;
110 i915_vbuf_render_allocate_vertices( struct vbuf_render
*render
,
114 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
115 struct i915_context
*i915
= i915_render
->i915
;
116 struct pipe_winsys
*winsys
= i915
->pipe
.winsys
;
117 size_t size
= (size_t)vertex_size
* (size_t)nr_vertices
;
119 /* FIXME: handle failure */
122 if (i915_render
->vbo_size
> size
+ i915_render
->vbo_offset
&& !i915
->vbo_flushed
) {
124 i915
->vbo_flushed
= 0;
125 pipe_buffer_reference(winsys
, &i915_render
->vbo
, NULL
);
128 if (!i915_render
->vbo
) {
129 i915_render
->vbo_size
= MAX2(size
, i915_render
->vbo_alloc_size
);
130 i915_render
->vbo_offset
= 0;
131 i915_render
->vbo
= winsys
->buffer_create(winsys
,
133 I915_BUFFER_USAGE_LIT_VERTEX
,
134 i915_render
->vbo_size
);
135 i915_render
->vbo_ptr
= winsys
->buffer_map(winsys
,
137 PIPE_BUFFER_USAGE_CPU_WRITE
);
138 winsys
->buffer_unmap(winsys
, i915_render
->vbo
);
141 i915
->vbo
= i915_render
->vbo
;
142 i915
->vbo_offset
= i915_render
->vbo_offset
;
143 i915
->dirty
|= I915_NEW_VBO
;
145 return i915_render
->vbo_ptr
+ i915
->vbo_offset
;
150 i915_vbuf_render_set_primitive( struct vbuf_render
*render
,
153 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
154 i915_render
->prim
= prim
;
157 case PIPE_PRIM_POINTS
:
158 i915_render
->hwprim
= PRIM3D_POINTLIST
;
159 i915_render
->fallback
= 0;
161 case PIPE_PRIM_LINES
:
162 i915_render
->hwprim
= PRIM3D_LINELIST
;
163 i915_render
->fallback
= 0;
165 case PIPE_PRIM_LINE_STRIP
:
166 i915_render
->hwprim
= PRIM3D_LINESTRIP
;
167 i915_render
->fallback
= 0;
169 case PIPE_PRIM_TRIANGLES
:
170 i915_render
->hwprim
= PRIM3D_TRILIST
;
171 i915_render
->fallback
= 0;
173 case PIPE_PRIM_TRIANGLE_STRIP
:
174 i915_render
->hwprim
= PRIM3D_TRISTRIP
;
175 i915_render
->fallback
= 0;
177 case PIPE_PRIM_QUADS
:
178 i915_render
->hwprim
= PRIM3D_TRILIST
;
179 i915_render
->fallback
= PIPE_PRIM_QUADS
;
181 case PIPE_PRIM_QUAD_STRIP
:
182 i915_render
->hwprim
= PRIM3D_TRILIST
;
183 i915_render
->fallback
= PIPE_PRIM_QUAD_STRIP
;
186 /* Actually, can handle a lot more just fine... Fixme.
195 * Used for fallbacks in draw_arrays
198 draw_arrays_generate_indices( struct vbuf_render
*render
,
199 unsigned start
, uint nr
,
202 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
203 struct i915_context
*i915
= i915_render
->i915
;
205 unsigned end
= start
+ nr
;
208 for (i
= start
; i
+1 < end
; i
+= 2)
209 OUT_BATCH( (i
+0) | (i
+1) << 16 );
213 case PIPE_PRIM_QUADS
:
214 for (i
= start
; i
+ 3 < end
; i
+= 4) {
215 OUT_BATCH( (i
+0) | (i
+1) << 16 );
216 OUT_BATCH( (i
+3) | (i
+1) << 16 );
217 OUT_BATCH( (i
+2) | (i
+3) << 16 );
220 case PIPE_PRIM_QUAD_STRIP
:
221 for (i
= start
; i
+ 3 < end
; i
+= 2) {
222 OUT_BATCH( (i
+0) | (i
+1) << 16 );
223 OUT_BATCH( (i
+3) | (i
+2) << 16 );
224 OUT_BATCH( (i
+0) | (i
+3) << 16 );
233 draw_arrays_calc_nr_indices( uint nr
, unsigned type
)
238 case PIPE_PRIM_QUADS
:
240 case PIPE_PRIM_QUAD_STRIP
:
241 return ((nr
- 2) / 2) * 6;
249 draw_arrays_fallback( struct vbuf_render
*render
,
253 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
254 struct i915_context
*i915
= i915_render
->i915
;
255 struct pipe_winsys
*winsys
= i915
->pipe
.winsys
;
259 i915_update_derived( i915
);
261 if (i915
->hardware_dirty
)
262 i915_emit_hardware_state( i915
);
264 nr_indices
= draw_arrays_calc_nr_indices( nr
, i915_render
->fallback
);
266 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
269 /* Make sure state is re-emitted after a flush:
271 i915_update_derived( i915
);
272 i915_emit_hardware_state( i915
);
273 i915
->vbo_flushed
= 1;
275 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
280 OUT_BATCH( _3DPRIMITIVE
|
282 i915_render
->hwprim
|
286 draw_arrays_generate_indices( render
, start
, nr
, i915_render
->fallback
);
293 i915_vbuf_render_draw_arrays( struct vbuf_render
*render
,
297 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
299 if (i915_render
->fallback
) {
300 draw_arrays_fallback( render
, start
, nr
);
304 /* JB: TODO submit direct cmds */
305 draw_arrays_fallback( render
, start
, nr
);
309 * Used for normal and fallback emitting of indices
310 * If type is zero normal operation assumed.
313 draw_generate_indices( struct vbuf_render
*render
,
314 const ushort
*indices
,
318 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
319 struct i915_context
*i915
= i915_render
->i915
;
324 for (i
= 0; i
+ 1 < nr_indices
; i
+= 2) {
325 OUT_BATCH( indices
[i
] | indices
[i
+1] << 16 );
327 if (i
< nr_indices
) {
328 OUT_BATCH( indices
[i
] );
331 case PIPE_PRIM_QUADS
:
332 for (i
= 0; i
+ 3 < nr_indices
; i
+= 4) {
333 OUT_BATCH( indices
[i
+0] | indices
[i
+1] << 16 );
334 OUT_BATCH( indices
[i
+3] | indices
[i
+1] << 16 );
335 OUT_BATCH( indices
[i
+2] | indices
[i
+3] << 16 );
338 case PIPE_PRIM_QUAD_STRIP
:
339 for (i
= 0; i
+ 3 < nr_indices
; i
+= 2) {
340 OUT_BATCH( indices
[i
+0] | indices
[i
+1] << 16 );
341 OUT_BATCH( indices
[i
+3] | indices
[i
+2] << 16 );
342 OUT_BATCH( indices
[i
+0] | indices
[i
+3] << 16 );
352 draw_calc_nr_indices( uint nr_indices
, unsigned type
)
357 case PIPE_PRIM_QUADS
:
358 return (nr_indices
/ 4) * 6;
359 case PIPE_PRIM_QUAD_STRIP
:
360 return ((nr_indices
- 2) / 2) * 6;
368 i915_vbuf_render_draw( struct vbuf_render
*render
,
369 const ushort
*indices
,
372 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
373 struct i915_context
*i915
= i915_render
->i915
;
374 struct pipe_winsys
*winsys
= i915
->pipe
.winsys
;
375 unsigned save_nr_indices
;
377 save_nr_indices
= nr_indices
;
378 nr_indices
= draw_calc_nr_indices( nr_indices
, i915_render
->fallback
);
383 i915_update_derived( i915
);
385 if (i915
->hardware_dirty
)
386 i915_emit_hardware_state( i915
);
388 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
391 /* Make sure state is re-emitted after a flush:
393 i915_update_derived( i915
);
394 i915_emit_hardware_state( i915
);
395 i915
->vbo_flushed
= 1;
397 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
403 OUT_BATCH( _3DPRIMITIVE
|
405 i915_render
->hwprim
|
408 draw_generate_indices( render
,
411 i915_render
->fallback
);
419 i915_vbuf_render_release_vertices( struct vbuf_render
*render
,
421 unsigned vertex_size
,
422 unsigned vertices_used
)
424 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
425 struct i915_context
*i915
= i915_render
->i915
;
426 struct pipe_winsys
*winsys
= i915
->pipe
.winsys
;
427 size_t size
= (size_t)vertex_size
* (size_t)vertices_used
;
431 i915_render
->vbo_offset
+= size
;
433 i915
->dirty
|= I915_NEW_VBO
;
438 i915_vbuf_render_destroy( struct vbuf_render
*render
)
440 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
446 * Create a new primitive render.
448 static struct vbuf_render
*
449 i915_vbuf_render_create( struct i915_context
*i915
)
451 struct i915_vbuf_render
*i915_render
= CALLOC_STRUCT(i915_vbuf_render
);
452 struct pipe_winsys
*winsys
= i915
->pipe
.winsys
;
454 i915_render
->i915
= i915
;
456 i915_render
->base
.max_vertex_buffer_bytes
= 128*1024;
458 /* NOTE: it must be such that state and vertices indices fit in a single
461 i915_render
->base
.max_indices
= 16*1024;
463 i915_render
->base
.get_vertex_info
= i915_vbuf_render_get_vertex_info
;
464 i915_render
->base
.allocate_vertices
= i915_vbuf_render_allocate_vertices
;
465 i915_render
->base
.set_primitive
= i915_vbuf_render_set_primitive
;
466 i915_render
->base
.draw
= i915_vbuf_render_draw
;
467 i915_render
->base
.draw_arrays
= i915_vbuf_render_draw_arrays
;
468 i915_render
->base
.release_vertices
= i915_vbuf_render_release_vertices
;
469 i915_render
->base
.destroy
= i915_vbuf_render_destroy
;
471 i915_render
->vbo_alloc_size
= 128 * 4096;
472 i915_render
->vbo_size
= i915_render
->vbo_alloc_size
;
473 i915_render
->vbo_offset
= 0;
474 i915_render
->vbo
= winsys
->buffer_create(winsys
,
476 I915_BUFFER_USAGE_LIT_VERTEX
,
477 i915_render
->vbo_size
);
478 i915_render
->vbo_ptr
= winsys
->buffer_map(winsys
,
480 PIPE_BUFFER_USAGE_CPU_WRITE
);
481 winsys
->buffer_unmap(winsys
, i915_render
->vbo
);
483 return &i915_render
->base
;
488 * Create a new primitive vbuf/render stage.
490 struct draw_stage
*i915_draw_vbuf_stage( struct i915_context
*i915
)
492 struct vbuf_render
*render
;
493 struct draw_stage
*stage
;
495 render
= i915_vbuf_render_create(i915
);
499 stage
= draw_vbuf_stage( i915
->draw
, render
);
501 render
->destroy(render
);
504 draw_set_render(i915
->draw
, render
);