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