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 **************************************************************************/
31 * Builds per-tile display lists and executes them on calls to
35 #include "lp_setup_context.h"
36 #include "util/u_math.h"
37 #include "util/u_memory.h"
38 #include "util/u_pack_color.h"
39 #include "pipe/p_defines.h"
41 static void set_state( struct setup_context
*, unsigned );
43 void lp_setup_new_cmd_block( struct cmd_block_list
*list
)
45 struct cmd_block
*block
= MALLOC_STRUCT(cmd_block
);
46 list
->tail
->next
= block
;
52 void lp_setup_new_data_block( struct data_block_list
*list
)
54 struct data_block
*block
= MALLOC_STRUCT(data_block
);
55 list
->tail
->next
= block
;
63 first_triangle( struct setup_context
*setup
,
68 set_state( setup
, SETUP_ACTIVE
);
69 lp_setup_choose_triangle( setup
);
70 setup
->triangle( setup
, v0
, v1
, v2
);
74 first_line( struct setup_context
*setup
,
78 set_state( setup
, SETUP_ACTIVE
);
79 lp_setup_choose_line( setup
);
80 setup
->line( setup
, v0
, v1
);
84 first_point( struct setup_context
*setup
,
87 set_state( setup
, SETUP_ACTIVE
);
88 lp_setup_choose_point( setup
);
89 setup
->point( setup
, v0
);
92 static void reset_context( struct setup_context
*setup
)
96 /* Free binner command lists:
98 for (i
= 0; i
< setup
->tiles_x
; i
++) {
99 for (j
= 0; j
< setup
->tiles_y
; j
++) {
100 struct cmd_block_list
*list
= &setup
->tile
[i
][j
];
101 struct cmd_block
*block
;
102 struct cmd_block
*tmp
;
104 for (block
= list
->head
; block
!= list
->tail
; block
= tmp
) {
109 list
->head
= list
->tail
;
116 struct data_block_list
*list
= &setup
->data
;
117 struct data_block
*block
, *tmp
;
119 for (block
= list
->head
; block
!= list
->tail
; block
= tmp
) {
124 list
->head
= list
->tail
;
129 setup
->clear
.flags
= 0;
131 /* Have an explicit "start-binning" call and get rid of this
134 setup
->line
= first_line
;
135 setup
->point
= first_point
;
136 setup
->triangle
= first_triangle
;
142 /* Add a command to all active bins.
144 static void bin_everywhere( struct setup_context
*setup
,
146 const union lp_rast_cmd_arg
*arg
)
149 for (i
= 0; i
< setup
->tiles_x
; i
++)
150 for (j
= 0; j
< setup
->tiles_y
; j
++)
151 bin_command( &setup
->tile
[i
][j
], cmd
, arg
);
156 rasterize_bins( struct setup_context
*setup
,
157 boolean write_depth
)
159 struct lp_rasterizer
*rast
= setup
->rast
;
160 struct cmd_block
*block
;
163 if (setup
->state
!= SETUP_ACTIVE
) {
164 /* this can happen, not a big deal */
165 debug_printf("%s called when not binning\n", __FUNCTION__
);
173 lp_rast_bind_color( rast
,
175 setup
->fb
.cbuf
!= NULL
);
177 lp_rast_bind_zstencil( rast
,
179 setup
->fb
.zsbuf
!= NULL
&& write_depth
);
181 for (i
= 0; i
< setup
->tiles_x
; i
++) {
182 for (j
= 0; j
< setup
->tiles_y
; j
++) {
184 lp_rast_start_tile( rast
,
188 for (block
= setup
->tile
[i
][j
].head
; block
; block
= block
->next
) {
189 for (k
= 0; k
< block
->count
; k
++) {
190 block
->cmd
[k
]( rast
, block
->arg
[k
] );
194 lp_rast_end_tile( rast
);
198 reset_context( setup
);
204 begin_binning( struct setup_context
*setup
)
206 if (!setup
->fb
.cbuf
&& !setup
->fb
.zsbuf
) {
208 setup
->fb
.height
= 0;
210 else if (!setup
->fb
.zsbuf
) {
211 setup
->fb
.width
= setup
->fb
.cbuf
->width
;
212 setup
->fb
.height
= setup
->fb
.cbuf
->height
;
214 else if (!setup
->fb
.cbuf
) {
215 setup
->fb
.width
= setup
->fb
.zsbuf
->width
;
216 setup
->fb
.height
= setup
->fb
.zsbuf
->height
;
219 /* XXX: not sure what we're really supposed to do for
220 * mis-matched color & depth buffer sizes.
222 setup
->fb
.width
= MIN2(setup
->fb
.cbuf
->width
,
223 setup
->fb
.zsbuf
->width
);
224 setup
->fb
.height
= MIN2(setup
->fb
.cbuf
->height
,
225 setup
->fb
.zsbuf
->height
);
228 setup
->tiles_x
= align(setup
->fb
.width
, TILESIZE
);
229 setup
->tiles_y
= align(setup
->fb
.height
, TILESIZE
);
231 if (setup
->fb
.cbuf
) {
232 if (setup
->clear
.flags
& PIPE_CLEAR_COLOR
)
233 bin_everywhere( setup
,
235 &setup
->clear
.color
);
237 bin_everywhere( setup
, lp_rast_load_color
, NULL
);
240 if (setup
->fb
.zsbuf
) {
241 if (setup
->clear
.flags
& PIPE_CLEAR_DEPTHSTENCIL
)
242 bin_everywhere( setup
,
243 lp_rast_clear_zstencil
,
244 &setup
->clear
.zstencil
);
246 bin_everywhere( setup
, lp_rast_load_zstencil
, NULL
);
251 /* This basically bins and then flushes any outstanding full-screen
254 * TODO: fast path for fullscreen clears and no triangles.
257 execute_clears( struct setup_context
*setup
)
259 begin_binning( setup
);
260 rasterize_bins( setup
, TRUE
);
265 set_state( struct setup_context
*setup
,
268 unsigned old_state
= setup
->state
;
270 if (old_state
== new_state
)
275 if (old_state
== SETUP_FLUSHED
)
276 begin_binning( setup
);
280 if (old_state
== SETUP_ACTIVE
) {
287 if (old_state
== SETUP_CLEARED
)
288 execute_clears( setup
);
290 rasterize_bins( setup
, TRUE
);
294 setup
->state
= new_state
;
299 lp_setup_flush( struct setup_context
*setup
,
302 set_state( setup
, SETUP_FLUSHED
);
307 lp_setup_bind_framebuffer( struct setup_context
*setup
,
308 struct pipe_surface
*color
,
309 struct pipe_surface
*zstencil
)
311 unsigned width
, height
;
313 set_state( setup
, SETUP_FLUSHED
);
315 pipe_surface_reference( &setup
->fb
.cbuf
, color
);
316 pipe_surface_reference( &setup
->fb
.zsbuf
, zstencil
);
318 width
= MAX2( color
->width
, zstencil
->width
);
319 height
= MAX2( color
->height
, zstencil
->height
);
321 setup
->tiles_x
= align( width
, TILESIZE
) / TILESIZE
;
322 setup
->tiles_y
= align( height
, TILESIZE
) / TILESIZE
;
326 lp_setup_clear( struct setup_context
*setup
,
332 if (setup
->state
== SETUP_ACTIVE
) {
333 /* Add the clear to existing bins. In the unusual case where
334 * both color and depth-stencilare being cleared, we could
335 * discard the currently binned scene and start again, but I
336 * don't see that as being a common usage.
338 if (flags
& PIPE_CLEAR_COLOR
) {
339 union lp_rast_cmd_arg
*arg
= get_data( &setup
->data
, sizeof *arg
);
341 util_pack_color(color
,
342 setup
->fb
.cbuf
->format
,
345 bin_everywhere(setup
, lp_rast_clear_color
, arg
);
348 if (flags
& PIPE_CLEAR_DEPTHSTENCIL
) {
349 union lp_rast_cmd_arg
*arg
= get_data( &setup
->data
, sizeof *arg
);
351 arg
->clear_zstencil
=
352 util_pack_z_stencil(setup
->fb
.zsbuf
->format
,
356 bin_everywhere(setup
, lp_rast_clear_zstencil
, arg
);
360 /* Put ourselves into the 'pre-clear' state, specifically to try
361 * and accumulate multiple clears to color and depth_stencil
362 * buffers which the app or state-tracker might issue
365 set_state( setup
, SETUP_CLEARED
);
367 setup
->clear
.flags
|= flags
;
369 if (flags
& PIPE_CLEAR_COLOR
) {
370 util_pack_color(color
,
371 setup
->fb
.cbuf
->format
,
372 &setup
->clear
.color
.clear_color
);
375 if (flags
& PIPE_CLEAR_DEPTHSTENCIL
) {
376 setup
->clear
.zstencil
.clear_zstencil
=
377 util_pack_z_stencil(setup
->fb
.zsbuf
->format
,
387 lp_setup_set_tri_state( struct setup_context
*setup
,
389 boolean ccw_is_frontface
)
391 setup
->ccw_is_frontface
= ccw_is_frontface
;
392 setup
->cullmode
= cull_mode
;
393 setup
->triangle
= first_triangle
;
399 lp_setup_set_fs_inputs( struct setup_context
*setup
,
400 const struct lp_shader_input
*input
,
403 memcpy( setup
->fs
.input
, input
, nr
* sizeof input
[0] );
404 setup
->fs
.nr_inputs
= nr
;
408 lp_setup_set_shader_state( struct setup_context
*setup
,
409 const struct lp_jit_context
*jc
)
418 /* Stubs for lines & points for now:
421 lp_setup_point(struct setup_context
*setup
,
422 const float (*v0
)[4])
424 setup
->point( setup
, v0
);
428 lp_setup_line(struct setup_context
*setup
,
429 const float (*v0
)[4],
430 const float (*v1
)[4])
432 setup
->line( setup
, v0
, v1
);
436 lp_setup_tri(struct setup_context
*setup
,
437 const float (*v0
)[4],
438 const float (*v1
)[4],
439 const float (*v2
)[4])
441 setup
->triangle( setup
, v0
, v1
, v2
);
446 lp_setup_destroy( struct setup_context
*setup
)
450 reset_context( setup
);
452 for (i
= 0; i
< TILES_X
; i
++)
453 for (j
= 0; j
< TILES_Y
; j
++)
454 FREE(setup
->tile
[i
][j
].head
);
456 lp_rast_destroy( setup
->rast
);
462 * Create a new primitive tiling engine. Currently also creates a
463 * rasterizer to use with it.
465 struct setup_context
*
466 lp_setup_create( void )
468 struct setup_context
*setup
= CALLOC_STRUCT(setup_context
);
471 setup
->rast
= lp_rast_create();
475 for (i
= 0; i
< TILES_X
; i
++)
476 for (j
= 0; j
< TILES_Y
; j
++)
477 setup
->tile
[i
][j
].head
=
478 setup
->tile
[i
][j
].tail
= CALLOC_STRUCT(cmd_block
);