lp_setup.c revision 402c189af7e95be99ba2e5fd71a71987ffd73c2f
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 "pipe/p_defines.h" 36#include "pipe/p_inlines.h" 37#include "util/u_math.h" 38#include "util/u_memory.h" 39#include "util/u_pack_color.h" 40#include "lp_state.h" 41#include "lp_buffer.h" 42#include "lp_texture.h" 43#include "lp_setup_context.h" 44 45#define SETUP_DEBUG debug_printf 46 47static void set_state( struct setup_context *, unsigned ); 48 49void lp_setup_new_cmd_block( struct cmd_block_list *list ) 50{ 51 struct cmd_block *block = MALLOC_STRUCT(cmd_block); 52 list->tail->next = block; 53 list->tail = block; 54 block->next = NULL; 55 block->count = 0; 56} 57 58void lp_setup_new_data_block( struct data_block_list *list ) 59{ 60 struct data_block *block = MALLOC_STRUCT(data_block); 61 list->tail->next = block; 62 list->tail = block; 63 block->next = NULL; 64 block->used = 0; 65} 66 67 68static void 69first_triangle( struct setup_context *setup, 70 const float (*v0)[4], 71 const float (*v1)[4], 72 const float (*v2)[4]) 73{ 74 set_state( setup, SETUP_ACTIVE ); 75 lp_setup_choose_triangle( setup ); 76 setup->triangle( setup, v0, v1, v2 ); 77} 78 79static void 80first_line( struct setup_context *setup, 81 const float (*v0)[4], 82 const float (*v1)[4]) 83{ 84 set_state( setup, SETUP_ACTIVE ); 85 lp_setup_choose_line( setup ); 86 setup->line( setup, v0, v1 ); 87} 88 89static void 90first_point( struct setup_context *setup, 91 const float (*v0)[4]) 92{ 93 set_state( setup, SETUP_ACTIVE ); 94 lp_setup_choose_point( setup ); 95 setup->point( setup, v0 ); 96} 97 98static void reset_context( struct setup_context *setup ) 99{ 100 unsigned i, j; 101 102 SETUP_DEBUG("%s\n", __FUNCTION__); 103 104 /* Free binner command lists: 105 */ 106 for (i = 0; i < setup->tiles_x; i++) { 107 for (j = 0; j < setup->tiles_y; j++) { 108 struct cmd_block_list *list = &setup->tile[i][j]; 109 struct cmd_block *block; 110 struct cmd_block *tmp; 111 112 for (block = list->head; block != list->tail; block = tmp) { 113 tmp = block->next; 114 FREE(block); 115 } 116 117 list->head = list->tail; 118 } 119 } 120 121 /* Free binned data: 122 */ 123 { 124 struct data_block_list *list = &setup->data; 125 struct data_block *block, *tmp; 126 127 for (block = list->head; block != list->tail; block = tmp) { 128 tmp = block->next; 129 FREE(block); 130 } 131 132 list->head = list->tail; 133 } 134 135 /* Reset some state: 136 */ 137 setup->clear.flags = 0; 138 139 /* Have an explicit "start-binning" call and get rid of this 140 * pointer twiddling? 141 */ 142 setup->line = first_line; 143 setup->point = first_point; 144 setup->triangle = first_triangle; 145} 146 147 148 149 150/* Add a command to all active bins. 151 */ 152static void bin_everywhere( struct setup_context *setup, 153 lp_rast_cmd cmd, 154 const union lp_rast_cmd_arg arg ) 155{ 156 unsigned i, j; 157 for (i = 0; i < setup->tiles_x; i++) 158 for (j = 0; j < setup->tiles_y; j++) 159 bin_command( &setup->tile[i][j], cmd, arg ); 160} 161 162 163static void 164rasterize_bins( struct setup_context *setup, 165 boolean write_depth ) 166{ 167 struct lp_rasterizer *rast = setup->rast; 168 struct cmd_block *block; 169 unsigned i,j,k; 170 171 SETUP_DEBUG("%s\n", __FUNCTION__); 172 173 lp_rast_begin( rast, 174 setup->fb.cbuf, 175 setup->fb.zsbuf, 176 setup->fb.cbuf != NULL, 177 setup->fb.zsbuf != NULL && write_depth, 178 setup->fb.width, 179 setup->fb.height ); 180 181 182 183 for (i = 0; i < setup->tiles_x; i++) { 184 for (j = 0; j < setup->tiles_y; j++) { 185 186 lp_rast_start_tile( rast, 187 i * TILESIZE, 188 j * TILESIZE ); 189 190 for (block = setup->tile[i][j].head; block; block = block->next) { 191 for (k = 0; k < block->count; k++) { 192 block->cmd[k]( rast, block->arg[k] ); 193 } 194 } 195 196 lp_rast_end_tile( rast ); 197 } 198 } 199 200 lp_rast_end( rast ); 201 202 reset_context( setup ); 203} 204 205 206 207static void 208begin_binning( struct setup_context *setup ) 209{ 210 SETUP_DEBUG("%s\n", __FUNCTION__); 211 212 if (!setup->fb.cbuf && !setup->fb.zsbuf) { 213 setup->fb.width = 0; 214 setup->fb.height = 0; 215 } 216 else if (!setup->fb.zsbuf) { 217 setup->fb.width = setup->fb.cbuf->width; 218 setup->fb.height = setup->fb.cbuf->height; 219 } 220 else if (!setup->fb.cbuf) { 221 setup->fb.width = setup->fb.zsbuf->width; 222 setup->fb.height = setup->fb.zsbuf->height; 223 } 224 else { 225 /* XXX: not sure what we're really supposed to do for 226 * mis-matched color & depth buffer sizes. 227 */ 228 setup->fb.width = MIN2(setup->fb.cbuf->width, 229 setup->fb.zsbuf->width); 230 setup->fb.height = MIN2(setup->fb.cbuf->height, 231 setup->fb.zsbuf->height); 232 } 233 234 setup->tiles_x = align(setup->fb.width, TILESIZE) / TILESIZE; 235 setup->tiles_y = align(setup->fb.height, TILESIZE) / TILESIZE; 236 237 if (setup->fb.cbuf) { 238 if (setup->clear.flags & PIPE_CLEAR_COLOR) 239 bin_everywhere( setup, 240 lp_rast_clear_color, 241 setup->clear.color ); 242 else 243 bin_everywhere( setup, lp_rast_load_color, lp_rast_arg_null() ); 244 } 245 246 if (setup->fb.zsbuf) { 247 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 248 bin_everywhere( setup, 249 lp_rast_clear_zstencil, 250 setup->clear.zstencil ); 251 else 252 bin_everywhere( setup, lp_rast_load_zstencil, lp_rast_arg_null() ); 253 } 254} 255 256 257/* This basically bins and then flushes any outstanding full-screen 258 * clears. 259 * 260 * TODO: fast path for fullscreen clears and no triangles. 261 */ 262static void 263execute_clears( struct setup_context *setup ) 264{ 265 SETUP_DEBUG("%s\n", __FUNCTION__); 266 267 begin_binning( setup ); 268 rasterize_bins( setup, TRUE ); 269} 270 271 272static void 273set_state( struct setup_context *setup, 274 unsigned new_state ) 275{ 276 unsigned old_state = setup->state; 277 278 if (old_state == new_state) 279 return; 280 281 SETUP_DEBUG("%s old %d new %d\n", __FUNCTION__, old_state, new_state); 282 283 switch (new_state) { 284 case SETUP_ACTIVE: 285 begin_binning( setup ); 286 break; 287 288 case SETUP_CLEARED: 289 if (old_state == SETUP_ACTIVE) { 290 assert(0); 291 return; 292 } 293 break; 294 295 case SETUP_FLUSHED: 296 if (old_state == SETUP_CLEARED) 297 execute_clears( setup ); 298 else 299 rasterize_bins( setup, TRUE ); 300 break; 301 } 302 303 setup->state = new_state; 304} 305 306 307void 308lp_setup_flush( struct setup_context *setup, 309 unsigned flags ) 310{ 311 SETUP_DEBUG("%s\n", __FUNCTION__); 312 313 set_state( setup, SETUP_FLUSHED ); 314} 315 316 317void 318lp_setup_bind_framebuffer( struct setup_context *setup, 319 struct pipe_surface *color, 320 struct pipe_surface *zstencil ) 321{ 322 SETUP_DEBUG("%s\n", __FUNCTION__); 323 324 set_state( setup, SETUP_FLUSHED ); 325 326 pipe_surface_reference( &setup->fb.cbuf, color ); 327 pipe_surface_reference( &setup->fb.zsbuf, zstencil ); 328} 329 330void 331lp_setup_clear( struct setup_context *setup, 332 const float *color, 333 double depth, 334 unsigned stencil, 335 unsigned flags ) 336{ 337 unsigned i; 338 339 SETUP_DEBUG("%s state %d\n", __FUNCTION__, setup->state); 340 341 342 if (flags & PIPE_CLEAR_COLOR) { 343 for (i = 0; i < 4; ++i) 344 setup->clear.color.clear_color[i] = float_to_ubyte(color[i]); 345 } 346 347 if (flags & PIPE_CLEAR_DEPTHSTENCIL) { 348 setup->clear.zstencil.clear_zstencil = 349 util_pack_z_stencil(setup->fb.zsbuf->format, 350 depth, 351 stencil); 352 } 353 354 if (setup->state == SETUP_ACTIVE) { 355 /* Add the clear to existing bins. In the unusual case where 356 * both color and depth-stencilare being cleared, we could 357 * discard the currently binned scene and start again, but I 358 * don't see that as being a common usage. 359 */ 360 if (flags & PIPE_CLEAR_COLOR) 361 bin_everywhere( setup, 362 lp_rast_clear_color, 363 setup->clear.color ); 364 365 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 366 bin_everywhere( setup, 367 lp_rast_clear_zstencil, 368 setup->clear.zstencil ); 369 } 370 else { 371 /* Put ourselves into the 'pre-clear' state, specifically to try 372 * and accumulate multiple clears to color and depth_stencil 373 * buffers which the app or state-tracker might issue 374 * separately. 375 */ 376 set_state( setup, SETUP_CLEARED ); 377 378 setup->clear.flags |= flags; 379 } 380} 381 382 383 384void 385lp_setup_set_triangle_state( struct setup_context *setup, 386 unsigned cull_mode, 387 boolean ccw_is_frontface) 388{ 389 SETUP_DEBUG("%s\n", __FUNCTION__); 390 391 setup->ccw_is_frontface = ccw_is_frontface; 392 setup->cullmode = cull_mode; 393 setup->triangle = first_triangle; 394} 395 396 397 398void 399lp_setup_set_fs_inputs( struct setup_context *setup, 400 const struct lp_shader_input *input, 401 unsigned nr ) 402{ 403 SETUP_DEBUG("%s\n", __FUNCTION__); 404 405 memcpy( setup->fs.input, input, nr * sizeof input[0] ); 406 setup->fs.nr_inputs = nr; 407} 408 409void 410lp_setup_set_fs( struct setup_context *setup, 411 struct lp_fragment_shader *fs ) 412{ 413 SETUP_DEBUG("%s\n", __FUNCTION__); 414 /* FIXME: reference count */ 415 416 setup->fs.jit_function = fs->current->jit_function; 417} 418 419void 420lp_setup_set_fs_constants(struct setup_context *setup, 421 struct pipe_buffer *buffer) 422{ 423 const void *data = buffer ? llvmpipe_buffer(buffer)->data : NULL; 424 struct pipe_buffer *dummy; 425 426 SETUP_DEBUG("%s\n", __FUNCTION__); 427 428 /* FIXME: hold on to the reference */ 429 dummy = NULL; 430 pipe_buffer_reference(&dummy, buffer); 431 432 setup->fs.jit_context.constants = data; 433 434 setup->fs.jit_context_dirty = TRUE; 435} 436 437 438void 439lp_setup_set_alpha_ref_value( struct setup_context *setup, 440 float alpha_ref_value ) 441{ 442 SETUP_DEBUG("%s\n", __FUNCTION__); 443 444 if(setup->fs.jit_context.alpha_ref_value != alpha_ref_value) { 445 setup->fs.jit_context.alpha_ref_value = alpha_ref_value; 446 setup->fs.jit_context_dirty = TRUE; 447 } 448} 449 450void 451lp_setup_set_blend_color( struct setup_context *setup, 452 const struct pipe_blend_color *blend_color ) 453{ 454 unsigned i, j; 455 456 SETUP_DEBUG("%s\n", __FUNCTION__); 457 458 if(!setup->fs.jit_context.blend_color) 459 setup->fs.jit_context.blend_color = align_malloc(4 * 16, 16); 460 461 for (i = 0; i < 4; ++i) { 462 uint8_t c = float_to_ubyte(blend_color->color[i]); 463 for (j = 0; j < 16; ++j) 464 setup->fs.jit_context.blend_color[i*4 + j] = c; 465 } 466 467 setup->fs.jit_context_dirty = TRUE; 468} 469 470void 471lp_setup_set_sampler_textures( struct setup_context *setup, 472 unsigned num, struct pipe_texture **texture) 473{ 474 struct pipe_texture *dummy; 475 unsigned i; 476 477 SETUP_DEBUG("%s\n", __FUNCTION__); 478 479 480 assert(num <= PIPE_MAX_SAMPLERS); 481 482 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { 483 struct pipe_texture *tex = i < num ? texture[i] : NULL; 484 485 /* FIXME: hold on to the reference */ 486 dummy = NULL; 487 pipe_texture_reference(&dummy, tex); 488 489 if(tex) { 490 struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex); 491 struct lp_jit_texture *jit_tex = &setup->fs.jit_context.textures[i]; 492 jit_tex->width = tex->width[0]; 493 jit_tex->height = tex->height[0]; 494 jit_tex->stride = lp_tex->stride[0]; 495 if(!lp_tex->dt) 496 jit_tex->data = lp_tex->data; 497 else 498 /* FIXME: map the rendertarget */ 499 assert(0); 500 } 501 } 502 503 setup->fs.jit_context_dirty = TRUE; 504} 505 506boolean 507lp_setup_is_texture_referenced( struct setup_context *setup, 508 const struct pipe_texture *texture ) 509{ 510 /* FIXME */ 511 return PIPE_UNREFERENCED; 512} 513 514 515static INLINE void 516lp_setup_update_shader_state( struct setup_context *setup ) 517{ 518 SETUP_DEBUG("%s\n", __FUNCTION__); 519 520 if(setup->fs.jit_context_dirty) { 521 if(!setup->fs.last_jc || 522 memcmp(setup->fs.last_jc, &setup->fs.jit_context, sizeof *setup->fs.last_jc)) { 523 struct lp_jit_context *jc; 524 525 jc = get_data(&setup->data, sizeof *jc); 526 if(jc) { 527 memcpy(jc, &setup->fs.jit_context, sizeof *jc); 528 setup->fs.last_jc = jc; 529 } 530 } 531 532 setup->fs.jit_context_dirty = FALSE; 533 } 534 535 assert(setup->fs.last_jc); 536} 537 538 539/* Stubs for lines & points for now: 540 */ 541void 542lp_setup_point(struct setup_context *setup, 543 const float (*v0)[4]) 544{ 545 lp_setup_update_shader_state(setup); 546 setup->point( setup, v0 ); 547} 548 549void 550lp_setup_line(struct setup_context *setup, 551 const float (*v0)[4], 552 const float (*v1)[4]) 553{ 554 lp_setup_update_shader_state(setup); 555 setup->line( setup, v0, v1 ); 556} 557 558void 559lp_setup_tri(struct setup_context *setup, 560 const float (*v0)[4], 561 const float (*v1)[4], 562 const float (*v2)[4]) 563{ 564 SETUP_DEBUG("%s\n", __FUNCTION__); 565 566 lp_setup_update_shader_state(setup); 567 setup->triangle( setup, v0, v1, v2 ); 568} 569 570 571void 572lp_setup_destroy( struct setup_context *setup ) 573{ 574 unsigned i, j; 575 576 reset_context( setup ); 577 578 for (i = 0; i < TILES_X; i++) 579 for (j = 0; j < TILES_Y; j++) 580 FREE(setup->tile[i][j].head); 581 582 lp_rast_destroy( setup->rast ); 583 FREE( setup ); 584} 585 586 587/** 588 * Create a new primitive tiling engine. Currently also creates a 589 * rasterizer to use with it. 590 */ 591struct setup_context * 592lp_setup_create( struct pipe_screen *screen ) 593{ 594 struct setup_context *setup = CALLOC_STRUCT(setup_context); 595 unsigned i, j; 596 597 setup->rast = lp_rast_create( screen ); 598 if (!setup->rast) 599 goto fail; 600 601 for (i = 0; i < TILES_X; i++) 602 for (j = 0; j < TILES_Y; j++) 603 setup->tile[i][j].head = 604 setup->tile[i][j].tail = CALLOC_STRUCT(cmd_block); 605 606 setup->data.head = 607 setup->data.tail = CALLOC_STRUCT(data_block); 608 609 setup->triangle = first_triangle; 610 setup->line = first_line; 611 setup->point = first_point; 612 613 return setup; 614 615fail: 616 FREE(setup); 617 return NULL; 618} 619 620