lp_setup.c revision 84ab7dcf48e87350c0622c533e51aa495f7256c2
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 * Tiling engine. 30 * 31 * Builds per-tile display lists and executes them on calls to 32 * lp_setup_flush(). 33 */ 34 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" 40 41static void set_state( struct setup_context *, unsigned ); 42 43void lp_setup_new_cmd_block( struct cmd_block_list *list ) 44{ 45 struct cmd_block *block = MALLOC_STRUCT(cmd_block); 46 list->tail->next = block; 47 list->tail = block; 48 block->next = NULL; 49 block->count = 0; 50} 51 52void lp_setup_new_data_block( struct data_block_list *list ) 53{ 54 struct data_block *block = MALLOC_STRUCT(data_block); 55 list->tail->next = block; 56 list->tail = block; 57 block->next = NULL; 58 block->used = 0; 59} 60 61 62static void 63first_triangle( struct setup_context *setup, 64 const float (*v0)[4], 65 const float (*v1)[4], 66 const float (*v2)[4]) 67{ 68 set_state( setup, SETUP_ACTIVE ); 69 lp_setup_choose_triangle( setup ); 70 setup->triangle( setup, v0, v1, v2 ); 71} 72 73static void 74first_line( struct setup_context *setup, 75 const float (*v0)[4], 76 const float (*v1)[4]) 77{ 78 set_state( setup, SETUP_ACTIVE ); 79 lp_setup_choose_line( setup ); 80 setup->line( setup, v0, v1 ); 81} 82 83static void 84first_point( struct setup_context *setup, 85 const float (*v0)[4]) 86{ 87 set_state( setup, SETUP_ACTIVE ); 88 lp_setup_choose_point( setup ); 89 setup->point( setup, v0 ); 90} 91 92static void reset_context( struct setup_context *setup ) 93{ 94 unsigned i, j; 95 96 /* Free binner command lists: 97 */ 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; 103 104 for (block = list->head; block != list->tail; block = tmp) { 105 tmp = block->next; 106 FREE(block); 107 } 108 109 list->head = list->tail; 110 } 111 } 112 113 /* Free binned data: 114 */ 115 { 116 struct data_block_list *list = &setup->data; 117 struct data_block *block, *tmp; 118 119 for (block = list->head; block != list->tail; block = tmp) { 120 tmp = block->next; 121 FREE(block); 122 } 123 124 list->head = list->tail; 125 } 126 127 /* Reset some state: 128 */ 129 setup->clear.flags = 0; 130 131 /* Have an explicit "start-binning" call and get rid of this 132 * pointer twiddling? 133 */ 134 setup->line = first_line; 135 setup->point = first_point; 136 setup->triangle = first_triangle; 137} 138 139 140 141 142/* Add a command to all active bins. 143 */ 144static void bin_everywhere( struct setup_context *setup, 145 lp_rast_cmd cmd, 146 const union lp_rast_cmd_arg *arg ) 147{ 148 unsigned i, j; 149 for (i = 0; i < setup->tiles_x; i++) 150 for (j = 0; j < setup->tiles_y; j++) 151 bin_cmd( &setup->tile[i][j], cmd, arg ); 152} 153 154 155static void 156rasterize_bins( struct setup_context *setup, 157 boolean write_depth ) 158{ 159 struct lp_rasterizer *rast = setup->rast; 160 struct cmd_block *block; 161 unsigned i,j,k; 162 163 if (setup->state != SETUP_ACTIVE) { 164 /* this can happen, not a big deal */ 165 debug_printf("%s called when not binning\n", __FUNCTION__); 166 return; 167 } 168 169 lp_rast_begin( rast, 170 setup->fb.width, 171 setup->fb.height ); 172 173 lp_rast_bind_color( rast, 174 setup->fb.cbuf, 175 setup->fb.cbuf != NULL ); 176 177 lp_rast_bind_zstencil( rast, 178 setup->fb.zsbuf, 179 setup->fb.zsbuf != NULL && write_depth ); 180 181 for (i = 0; i < setup->tiles_x; i++) { 182 for (j = 0; j < setup->tiles_y; j++) { 183 184 lp_rast_start_tile( rast, 185 i * TILESIZE, 186 j * TILESIZE ); 187 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] ); 191 } 192 } 193 194 lp_rast_end_tile( rast ); 195 } 196 } 197 198 reset_context( setup ); 199} 200 201 202 203static void 204begin_binning( struct setup_context *setup ) 205{ 206 if (!setup->fb.cbuf && !setup->fb.zsbuf) { 207 setup->fb.width = 0; 208 setup->fb.height = 0; 209 } 210 else if (!setup->fb.zsbuf) { 211 setup->fb.width = setup->fb.cbuf->width; 212 setup->fb.height = setup->fb.cbuf->height; 213 } 214 else if (!setup->fb.cbuf) { 215 setup->fb.width = setup->fb.zsbuf->width; 216 setup->fb.height = setup->fb.zsbuf->height; 217 } 218 else { 219 /* XXX: not sure what we're really supposed to do for 220 * mis-matched color & depth buffer sizes. 221 */ 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); 226 } 227 228 setup->tiles_x = align(setup->fb.width, TILESIZE); 229 setup->tiles_y = align(setup->fb.height, TILESIZE); 230 231 if (setup->fb.cbuf) { 232 if (setup->clear.flags & PIPE_CLEAR_COLOR) 233 bin_everywhere( setup, 234 lp_rast_clear_color, 235 &setup->clear.color ); 236 else 237 bin_everywhere( setup, lp_rast_load_color, NULL ); 238 } 239 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 ); 245 else 246 bin_everywhere( setup, lp_rast_load_zstencil, NULL ); 247 } 248} 249 250 251/* This basically bins and then flushes any outstanding full-screen 252 * clears. 253 * 254 * TODO: fast path for fullscreen clears and no triangles. 255 */ 256static void 257execute_clears( struct setup_context *setup ) 258{ 259 begin_binning( setup ); 260 rasterize_bins( setup, TRUE ); 261} 262 263 264static void 265set_state( struct setup_context *setup, 266 unsigned new_state ) 267{ 268 unsigned old_state = setup->state; 269 270 if (old_state == new_state) 271 return; 272 273 switch (new_state) { 274 case SETUP_ACTIVE: 275 if (old_state == SETUP_FLUSHED) 276 begin_binning( setup ); 277 break; 278 279 case SETUP_CLEARED: 280 if (old_state == SETUP_ACTIVE) { 281 assert(0); 282 return; 283 } 284 break; 285 286 case SETUP_FLUSHED: 287 if (old_state == SETUP_CLEARED) 288 execute_clears( setup ); 289 else 290 rasterize_bins( setup, TRUE ); 291 break; 292 } 293 294 setup->state = new_state; 295} 296 297 298void 299lp_setup_flush( struct setup_context *setup, 300 unsigned flags ) 301{ 302 set_state( setup, SETUP_FLUSHED ); 303} 304 305 306void 307lp_setup_bind_framebuffer( struct setup_context *setup, 308 struct pipe_surface *color, 309 struct pipe_surface *zstencil ) 310{ 311 unsigned width, height; 312 313 set_state( setup, SETUP_FLUSHED ); 314 315 pipe_surface_reference( &setup->fb.cbuf, color ); 316 pipe_surface_reference( &setup->fb.zsbuf, zstencil ); 317 318 width = MAX2( color->width, zstencil->width ); 319 height = MAX2( color->height, zstencil->height ); 320 321 setup->tiles_x = align( width, TILESIZE ) / TILESIZE; 322 setup->tiles_y = align( height, TILESIZE ) / TILESIZE; 323} 324 325void 326lp_setup_clear( struct setup_context *setup, 327 const float *color, 328 double depth, 329 unsigned stencil, 330 unsigned flags ) 331{ 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. 337 */ 338 if (flags & PIPE_CLEAR_COLOR) { 339 union lp_rast_cmd_arg *arg = get_data( &setup->data, sizeof *arg ); 340 341 util_pack_color(color, 342 setup->fb.cbuf->format, 343 &arg->clear_color ); 344 345 bin_everywhere(setup, lp_rast_clear_color, arg ); 346 } 347 348 if (flags & PIPE_CLEAR_DEPTHSTENCIL) { 349 union lp_rast_cmd_arg *arg = get_data( &setup->data, sizeof *arg ); 350 351 arg->clear_zstencil = 352 util_pack_z_stencil(setup->fb.zsbuf->format, 353 depth, 354 stencil); 355 356 bin_everywhere(setup, lp_rast_clear_zstencil, arg ); 357 } 358 } 359 else { 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 363 * separately. 364 */ 365 set_state( setup, SETUP_CLEARED ); 366 367 setup->clear.flags |= flags; 368 369 if (flags & PIPE_CLEAR_COLOR) { 370 util_pack_color(color, 371 setup->fb.cbuf->format, 372 &setup->clear.color.clear_color ); 373 } 374 375 if (flags & PIPE_CLEAR_DEPTHSTENCIL) { 376 setup->clear.zstencil.clear_zstencil = 377 util_pack_z_stencil(setup->fb.zsbuf->format, 378 depth, 379 stencil); 380 } 381 } 382} 383 384 385void 386lp_setup_set_fs_inputs( struct setup_context *setup, 387 const struct lp_shader_input *input, 388 unsigned nr ) 389{ 390 memcpy( setup->fs.input, input, nr * sizeof input[0] ); 391 setup->fs.nr_inputs = nr; 392} 393 394void 395lp_setup_set_shader_state( struct setup_context *setup, 396 const struct lp_jit_context *jc ) 397{ 398 399} 400 401 402 403 404 405/* Stubs for lines & points for now: 406 */ 407void 408lp_setup_point(struct setup_context *setup, 409 const float (*v0)[4]) 410{ 411 setup->point( setup, v0 ); 412} 413 414void 415lp_setup_line(struct setup_context *setup, 416 const float (*v0)[4], 417 const float (*v1)[4]) 418{ 419 setup->line( setup, v0, v1 ); 420} 421 422void 423lp_setup_tri(struct setup_context *setup, 424 const float (*v0)[4], 425 const float (*v1)[4], 426 const float (*v2)[4]) 427{ 428 setup->triangle( setup, v0, v1, v2 ); 429} 430 431 432void 433lp_setup_destroy( struct setup_context *setup ) 434{ 435 lp_rast_destroy( setup->rast ); 436 FREE( setup ); 437} 438 439 440/** 441 * Create a new primitive tiling engine. Currently also creates a 442 * rasterizer to use with it. 443 */ 444struct setup_context * 445lp_setup_create( void ) 446{ 447 struct setup_context *setup = CALLOC_STRUCT(setup_context); 448 unsigned i, j; 449 450 setup->rast = lp_rast_create(); 451 if (!setup->rast) 452 goto fail; 453 454 for (i = 0; i < TILES_X; i++) 455 for (j = 0; j < TILES_Y; j++) 456 setup->tile[i][j].head = 457 setup->tile[i][j].tail = CALLOC_STRUCT(cmd_block); 458 459 return setup; 460 461fail: 462 FREE(setup); 463 return NULL; 464} 465 466