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 "pipe/p_inlines.h"
45 #include "pipe/internal/p_winsys_screen.h"
46 #include "util/u_math.h"
47 #include "util/u_memory.h"
49 #include "i915_context.h"
51 #include "i915_winsys.h"
52 #include "i915_batch.h"
53 #include "i915_state.h"
57 * Primitive renderer for i915.
59 struct i915_vbuf_render
{
60 struct vbuf_render base
;
62 struct i915_context
*i915
;
64 /** Vertex size in bytes */
67 /** Software primitive */
70 /** Hardware primitive */
73 /** Genereate a vertex list */
76 /* Stuff for the vbo */
77 struct pipe_buffer
*vbo
;
81 size_t vbo_alloc_size
;
87 * Basically a cast wrapper.
89 static INLINE
struct i915_vbuf_render
*
90 i915_vbuf_render( struct vbuf_render
*render
)
93 return (struct i915_vbuf_render
*)render
;
97 static const struct vertex_info
*
98 i915_vbuf_render_get_vertex_info( struct vbuf_render
*render
)
100 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
101 struct i915_context
*i915
= i915_render
->i915
;
104 /* make sure we have up to date vertex layout */
105 i915_update_derived( i915
);
108 return &i915
->current
.vertex_info
;
113 i915_vbuf_render_allocate_vertices( struct vbuf_render
*render
,
117 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
118 struct i915_context
*i915
= i915_render
->i915
;
119 struct pipe_screen
*screen
= i915
->pipe
.screen
;
120 size_t size
= (size_t)vertex_size
* (size_t)nr_vertices
;
122 /* FIXME: handle failure */
125 if (i915_render
->vbo_size
> size
+ i915_render
->vbo_offset
&& !i915
->vbo_flushed
) {
127 i915
->vbo_flushed
= 0;
128 if (i915_render
->vbo
)
129 pipe_buffer_reference(&i915_render
->vbo
, NULL
);
132 if (!i915_render
->vbo
) {
133 i915_render
->vbo_size
= MAX2(size
, i915_render
->vbo_alloc_size
);
134 i915_render
->vbo_offset
= 0;
135 i915_render
->vbo
= pipe_buffer_create(screen
,
137 I915_BUFFER_USAGE_LIT_VERTEX
,
138 i915_render
->vbo_size
);
142 i915_render
->vertex_size
= vertex_size
;
143 i915
->vbo
= i915_render
->vbo
;
144 i915
->vbo_offset
= i915_render
->vbo_offset
;
145 i915
->dirty
|= I915_NEW_VBO
;
147 if (!i915_render
->vbo
)
154 i915_vbuf_render_map_vertices( struct vbuf_render
*render
)
156 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
157 struct i915_context
*i915
= i915_render
->i915
;
158 struct pipe_screen
*screen
= i915
->pipe
.screen
;
160 if (i915
->vbo_flushed
)
161 debug_printf("%s bad vbo flush occured stalling on hw\n");
163 i915_render
->vbo_ptr
= pipe_buffer_map(screen
,
165 PIPE_BUFFER_USAGE_CPU_WRITE
);
167 return (unsigned char *)i915_render
->vbo_ptr
+ i915
->vbo_offset
;
171 i915_vbuf_render_unmap_vertices( struct vbuf_render
*render
,
175 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
176 struct i915_context
*i915
= i915_render
->i915
;
177 struct pipe_screen
*screen
= i915
->pipe
.screen
;
179 i915_render
->vbo_max_used
= MAX2(i915_render
->vbo_max_used
, i915_render
->vertex_size
* (max_index
+ 1));
180 pipe_buffer_unmap(screen
, i915_render
->vbo
);
184 i915_vbuf_render_set_primitive( struct vbuf_render
*render
,
187 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
188 i915_render
->prim
= prim
;
191 case PIPE_PRIM_POINTS
:
192 i915_render
->hwprim
= PRIM3D_POINTLIST
;
193 i915_render
->fallback
= 0;
195 case PIPE_PRIM_LINES
:
196 i915_render
->hwprim
= PRIM3D_LINELIST
;
197 i915_render
->fallback
= 0;
199 case PIPE_PRIM_LINE_LOOP
:
200 i915_render
->hwprim
= PRIM3D_LINELIST
;
201 i915_render
->fallback
= PIPE_PRIM_LINE_LOOP
;
203 case PIPE_PRIM_LINE_STRIP
:
204 i915_render
->hwprim
= PRIM3D_LINESTRIP
;
205 i915_render
->fallback
= 0;
207 case PIPE_PRIM_TRIANGLES
:
208 i915_render
->hwprim
= PRIM3D_TRILIST
;
209 i915_render
->fallback
= 0;
211 case PIPE_PRIM_TRIANGLE_STRIP
:
212 i915_render
->hwprim
= PRIM3D_TRISTRIP
;
213 i915_render
->fallback
= 0;
215 case PIPE_PRIM_TRIANGLE_FAN
:
216 i915_render
->hwprim
= PRIM3D_TRIFAN
;
217 i915_render
->fallback
= 0;
219 case PIPE_PRIM_QUADS
:
220 i915_render
->hwprim
= PRIM3D_TRILIST
;
221 i915_render
->fallback
= PIPE_PRIM_QUADS
;
223 case PIPE_PRIM_QUAD_STRIP
:
224 i915_render
->hwprim
= PRIM3D_TRILIST
;
225 i915_render
->fallback
= PIPE_PRIM_QUAD_STRIP
;
227 case PIPE_PRIM_POLYGON
:
228 i915_render
->hwprim
= PRIM3D_POLY
;
229 i915_render
->fallback
= 0;
232 /* FIXME: Actually, can handle a lot more just fine... */
240 * Used for fallbacks in draw_arrays
243 draw_arrays_generate_indices( struct vbuf_render
*render
,
244 unsigned start
, uint nr
,
247 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
248 struct i915_context
*i915
= i915_render
->i915
;
250 unsigned end
= start
+ nr
;
253 for (i
= start
; i
+1 < end
; i
+= 2)
254 OUT_BATCH( (i
+0) | (i
+1) << 16 );
258 case PIPE_PRIM_LINE_LOOP
:
260 for (i
= start
+ 1; i
< end
; i
++)
261 OUT_BATCH( (i
-0) | (i
+0) << 16 );
262 OUT_BATCH( (i
-0) | ( start
) << 16 );
265 case PIPE_PRIM_QUADS
:
266 for (i
= start
; i
+ 3 < end
; i
+= 4) {
267 OUT_BATCH( (i
+0) | (i
+1) << 16 );
268 OUT_BATCH( (i
+3) | (i
+1) << 16 );
269 OUT_BATCH( (i
+2) | (i
+3) << 16 );
272 case PIPE_PRIM_QUAD_STRIP
:
273 for (i
= start
; i
+ 3 < end
; i
+= 2) {
274 OUT_BATCH( (i
+0) | (i
+1) << 16 );
275 OUT_BATCH( (i
+3) | (i
+2) << 16 );
276 OUT_BATCH( (i
+0) | (i
+3) << 16 );
285 draw_arrays_calc_nr_indices( uint nr
, unsigned type
)
290 case PIPE_PRIM_LINE_LOOP
:
295 case PIPE_PRIM_QUADS
:
297 case PIPE_PRIM_QUAD_STRIP
:
298 return ((nr
- 2) / 2) * 6;
306 draw_arrays_fallback( struct vbuf_render
*render
,
310 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
311 struct i915_context
*i915
= i915_render
->i915
;
315 i915_update_derived( i915
);
317 if (i915
->hardware_dirty
)
318 i915_emit_hardware_state( i915
);
320 nr_indices
= draw_arrays_calc_nr_indices( nr
, i915_render
->fallback
);
324 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
327 /* Make sure state is re-emitted after a flush:
329 i915_update_derived( i915
);
330 i915_emit_hardware_state( i915
);
331 i915
->vbo_flushed
= 1;
333 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
338 OUT_BATCH( _3DPRIMITIVE
|
340 i915_render
->hwprim
|
344 draw_arrays_generate_indices( render
, start
, nr
, i915_render
->fallback
);
351 i915_vbuf_render_draw_arrays( struct vbuf_render
*render
,
355 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
357 if (i915_render
->fallback
) {
358 draw_arrays_fallback( render
, start
, nr
);
362 /* JB: TODO submit direct cmds */
363 draw_arrays_fallback( render
, start
, nr
);
367 * Used for normal and fallback emitting of indices
368 * If type is zero normal operation assumed.
371 draw_generate_indices( struct vbuf_render
*render
,
372 const ushort
*indices
,
376 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
377 struct i915_context
*i915
= i915_render
->i915
;
382 for (i
= 0; i
+ 1 < nr_indices
; i
+= 2) {
383 OUT_BATCH( indices
[i
] | indices
[i
+1] << 16 );
385 if (i
< nr_indices
) {
386 OUT_BATCH( indices
[i
] );
389 case PIPE_PRIM_LINE_LOOP
:
390 if (nr_indices
>= 2) {
391 for (i
= 1; i
< nr_indices
; i
++)
392 OUT_BATCH( indices
[i
-1] | indices
[i
] << 16 );
393 OUT_BATCH( indices
[i
-1] | indices
[0] << 16 );
396 case PIPE_PRIM_QUADS
:
397 for (i
= 0; i
+ 3 < nr_indices
; i
+= 4) {
398 OUT_BATCH( indices
[i
+0] | indices
[i
+1] << 16 );
399 OUT_BATCH( indices
[i
+3] | indices
[i
+1] << 16 );
400 OUT_BATCH( indices
[i
+2] | indices
[i
+3] << 16 );
403 case PIPE_PRIM_QUAD_STRIP
:
404 for (i
= 0; i
+ 3 < nr_indices
; i
+= 2) {
405 OUT_BATCH( indices
[i
+0] | indices
[i
+1] << 16 );
406 OUT_BATCH( indices
[i
+3] | indices
[i
+2] << 16 );
407 OUT_BATCH( indices
[i
+0] | indices
[i
+3] << 16 );
417 draw_calc_nr_indices( uint nr_indices
, unsigned type
)
422 case PIPE_PRIM_LINE_LOOP
:
424 return nr_indices
* 2;
427 case PIPE_PRIM_QUADS
:
428 return (nr_indices
/ 4) * 6;
429 case PIPE_PRIM_QUAD_STRIP
:
430 return ((nr_indices
- 2) / 2) * 6;
438 i915_vbuf_render_draw( struct vbuf_render
*render
,
439 const ushort
*indices
,
442 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
443 struct i915_context
*i915
= i915_render
->i915
;
444 unsigned save_nr_indices
;
446 save_nr_indices
= nr_indices
;
448 nr_indices
= draw_calc_nr_indices( nr_indices
, i915_render
->fallback
);
453 i915_update_derived( i915
);
455 if (i915
->hardware_dirty
)
456 i915_emit_hardware_state( i915
);
458 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
461 /* Make sure state is re-emitted after a flush:
463 i915_update_derived( i915
);
464 i915_emit_hardware_state( i915
);
465 i915
->vbo_flushed
= 1;
467 if (!BEGIN_BATCH( 1 + (nr_indices
+ 1)/2, 1 )) {
473 OUT_BATCH( _3DPRIMITIVE
|
475 i915_render
->hwprim
|
478 draw_generate_indices( render
,
481 i915_render
->fallback
);
489 i915_vbuf_render_release_vertices( struct vbuf_render
*render
)
491 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
492 struct i915_context
*i915
= i915_render
->i915
;
496 i915_render
->vbo_offset
+= i915_render
->vbo_max_used
;
497 i915_render
->vbo_max_used
= 0;
499 i915
->dirty
|= I915_NEW_VBO
;
504 i915_vbuf_render_destroy( struct vbuf_render
*render
)
506 struct i915_vbuf_render
*i915_render
= i915_vbuf_render(render
);
512 * Create a new primitive render.
514 static struct vbuf_render
*
515 i915_vbuf_render_create( struct i915_context
*i915
)
517 struct i915_vbuf_render
*i915_render
= CALLOC_STRUCT(i915_vbuf_render
);
518 struct pipe_screen
*screen
= i915
->pipe
.screen
;
520 i915_render
->i915
= i915
;
522 i915_render
->base
.max_vertex_buffer_bytes
= 128*1024;
524 /* NOTE: it must be such that state and vertices indices fit in a single
527 i915_render
->base
.max_indices
= 16*1024;
529 i915_render
->base
.get_vertex_info
= i915_vbuf_render_get_vertex_info
;
530 i915_render
->base
.allocate_vertices
= i915_vbuf_render_allocate_vertices
;
531 i915_render
->base
.map_vertices
= i915_vbuf_render_map_vertices
;
532 i915_render
->base
.unmap_vertices
= i915_vbuf_render_unmap_vertices
;
533 i915_render
->base
.set_primitive
= i915_vbuf_render_set_primitive
;
534 i915_render
->base
.draw
= i915_vbuf_render_draw
;
535 i915_render
->base
.draw_arrays
= i915_vbuf_render_draw_arrays
;
536 i915_render
->base
.release_vertices
= i915_vbuf_render_release_vertices
;
537 i915_render
->base
.destroy
= i915_vbuf_render_destroy
;
539 i915_render
->vbo_alloc_size
= 128 * 4096;
540 i915_render
->vbo_size
= i915_render
->vbo_alloc_size
;
541 i915_render
->vbo_offset
= 0;
542 i915_render
->vbo
= pipe_buffer_create(screen
,
544 I915_BUFFER_USAGE_LIT_VERTEX
,
545 i915_render
->vbo_size
);
546 i915_render
->vbo_ptr
= pipe_buffer_map(screen
,
548 PIPE_BUFFER_USAGE_CPU_WRITE
);
549 pipe_buffer_unmap(screen
, i915_render
->vbo
);
551 return &i915_render
->base
;
556 * Create a new primitive vbuf/render stage.
558 struct draw_stage
*i915_draw_vbuf_stage( struct i915_context
*i915
)
560 struct vbuf_render
*render
;
561 struct draw_stage
*stage
;
563 render
= i915_vbuf_render_create(i915
);
567 stage
= draw_vbuf_stage( i915
->draw
, render
);
569 render
->destroy(render
);
572 /** TODO JB: this shouldn't be here */
573 draw_set_render(i915
->draw
, render
);