lp_setup.c revision 3160cbabccf1f7d8bdf344242507b9c3082f15c6
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 "util/u_inlines.h" 37#include "util/u_memory.h" 38#include "util/u_pack_color.h" 39#include "util/u_surface.h" 40#include "lp_scene.h" 41#include "lp_scene_queue.h" 42#include "lp_buffer.h" 43#include "lp_texture.h" 44#include "lp_debug.h" 45#include "lp_fence.h" 46#include "lp_rast.h" 47#include "lp_setup_context.h" 48#include "lp_screen.h" 49#include "state_tracker/sw_winsys.h" 50 51#include "draw/draw_context.h" 52#include "draw/draw_vbuf.h" 53 54 55static void set_scene_state( struct lp_setup_context *, unsigned ); 56 57 58struct lp_scene * 59lp_setup_get_current_scene(struct lp_setup_context *setup) 60{ 61 if (!setup->scene) { 62 63 /* wait for a free/empty scene 64 */ 65 setup->scene = lp_scene_dequeue(setup->empty_scenes, TRUE); 66 67 assert(lp_scene_is_empty(setup->scene)); 68 69 lp_scene_begin_binning(setup->scene, 70 &setup->fb ); 71 } 72 return setup->scene; 73} 74 75 76static void 77first_triangle( struct lp_setup_context *setup, 78 const float (*v0)[4], 79 const float (*v1)[4], 80 const float (*v2)[4]) 81{ 82 set_scene_state( setup, SETUP_ACTIVE ); 83 lp_setup_choose_triangle( setup ); 84 setup->triangle( setup, v0, v1, v2 ); 85} 86 87static void 88first_line( struct lp_setup_context *setup, 89 const float (*v0)[4], 90 const float (*v1)[4]) 91{ 92 set_scene_state( setup, SETUP_ACTIVE ); 93 lp_setup_choose_line( setup ); 94 setup->line( setup, v0, v1 ); 95} 96 97static void 98first_point( struct lp_setup_context *setup, 99 const float (*v0)[4]) 100{ 101 set_scene_state( setup, SETUP_ACTIVE ); 102 lp_setup_choose_point( setup ); 103 setup->point( setup, v0 ); 104} 105 106static void reset_context( struct lp_setup_context *setup ) 107{ 108 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 109 110 /* Reset derived state */ 111 setup->constants.stored_size = 0; 112 setup->constants.stored_data = NULL; 113 setup->fs.stored = NULL; 114 setup->dirty = ~0; 115 116 /* no current bin */ 117 setup->scene = NULL; 118 119 /* Reset some state: 120 */ 121 setup->clear.flags = 0; 122 123 /* Have an explicit "start-binning" call and get rid of this 124 * pointer twiddling? 125 */ 126 setup->line = first_line; 127 setup->point = first_point; 128 setup->triangle = first_triangle; 129} 130 131 132/** Rasterize all scene's bins */ 133static void 134lp_setup_rasterize_scene( struct lp_setup_context *setup, 135 boolean write_depth ) 136{ 137 struct lp_scene *scene = lp_setup_get_current_scene(setup); 138 139 lp_scene_rasterize(scene, 140 setup->rast, 141 write_depth); 142 143 reset_context( setup ); 144 145 LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__); 146} 147 148 149 150static void 151begin_binning( struct lp_setup_context *setup ) 152{ 153 struct lp_scene *scene = lp_setup_get_current_scene(setup); 154 155 LP_DBG(DEBUG_SETUP, "%s color: %s depth: %s\n", __FUNCTION__, 156 (setup->clear.flags & PIPE_CLEAR_COLOR) ? "clear": "load", 157 (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) ? "clear": "load"); 158 159 if (setup->fb.nr_cbufs) { 160 if (setup->clear.flags & PIPE_CLEAR_COLOR) 161 lp_scene_bin_everywhere( scene, 162 lp_rast_clear_color, 163 setup->clear.color ); 164 else 165 lp_scene_bin_everywhere( scene, 166 lp_rast_load_color, 167 lp_rast_arg_null() ); 168 } 169 170 if (setup->fb.zsbuf) { 171 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 172 lp_scene_bin_everywhere( scene, 173 lp_rast_clear_zstencil, 174 setup->clear.zstencil ); 175 } 176 177 LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__); 178} 179 180 181/* This basically bins and then flushes any outstanding full-screen 182 * clears. 183 * 184 * TODO: fast path for fullscreen clears and no triangles. 185 */ 186static void 187execute_clears( struct lp_setup_context *setup ) 188{ 189 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 190 191 begin_binning( setup ); 192 lp_setup_rasterize_scene( setup, TRUE ); 193} 194 195 196static void 197set_scene_state( struct lp_setup_context *setup, 198 unsigned new_state ) 199{ 200 unsigned old_state = setup->state; 201 202 if (old_state == new_state) 203 return; 204 205 LP_DBG(DEBUG_SETUP, "%s old %d new %d\n", __FUNCTION__, old_state, new_state); 206 207 switch (new_state) { 208 case SETUP_ACTIVE: 209 begin_binning( setup ); 210 break; 211 212 case SETUP_CLEARED: 213 if (old_state == SETUP_ACTIVE) { 214 assert(0); 215 return; 216 } 217 break; 218 219 case SETUP_FLUSHED: 220 if (old_state == SETUP_CLEARED) 221 execute_clears( setup ); 222 else 223 lp_setup_rasterize_scene( setup, TRUE ); 224 break; 225 } 226 227 setup->state = new_state; 228} 229 230 231void 232lp_setup_flush( struct lp_setup_context *setup, 233 unsigned flags ) 234{ 235 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 236 237 set_scene_state( setup, SETUP_FLUSHED ); 238} 239 240 241void 242lp_setup_bind_framebuffer( struct lp_setup_context *setup, 243 const struct pipe_framebuffer_state *fb ) 244{ 245 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 246 247 /* Flush any old scene. 248 */ 249 set_scene_state( setup, SETUP_FLUSHED ); 250 251 /* Set new state. This will be picked up later when we next need a 252 * scene. 253 */ 254 util_copy_framebuffer_state(&setup->fb, fb); 255} 256 257 258void 259lp_setup_clear( struct lp_setup_context *setup, 260 const float *color, 261 double depth, 262 unsigned stencil, 263 unsigned flags ) 264{ 265 struct lp_scene *scene = lp_setup_get_current_scene(setup); 266 unsigned i; 267 268 LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state); 269 270 271 if (flags & PIPE_CLEAR_COLOR) { 272 for (i = 0; i < 4; ++i) 273 setup->clear.color.clear_color[i] = float_to_ubyte(color[i]); 274 } 275 276 if (flags & PIPE_CLEAR_DEPTHSTENCIL) { 277 setup->clear.zstencil.clear_zstencil = 278 util_pack_z_stencil(setup->fb.zsbuf->format, 279 depth, 280 stencil); 281 } 282 283 if (setup->state == SETUP_ACTIVE) { 284 /* Add the clear to existing scene. In the unusual case where 285 * both color and depth-stencil are being cleared when there's 286 * already been some rendering, we could discard the currently 287 * binned scene and start again, but I don't see that as being 288 * a common usage. 289 */ 290 if (flags & PIPE_CLEAR_COLOR) 291 lp_scene_bin_everywhere( scene, 292 lp_rast_clear_color, 293 setup->clear.color ); 294 295 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 296 lp_scene_bin_everywhere( scene, 297 lp_rast_clear_zstencil, 298 setup->clear.zstencil ); 299 } 300 else { 301 /* Put ourselves into the 'pre-clear' state, specifically to try 302 * and accumulate multiple clears to color and depth_stencil 303 * buffers which the app or state-tracker might issue 304 * separately. 305 */ 306 set_scene_state( setup, SETUP_CLEARED ); 307 308 setup->clear.flags |= flags; 309 } 310} 311 312 313/** 314 * Emit a fence. 315 */ 316struct pipe_fence_handle * 317lp_setup_fence( struct lp_setup_context *setup ) 318{ 319 struct lp_scene *scene = lp_setup_get_current_scene(setup); 320 const unsigned rank = lp_scene_get_num_bins( scene ); /* xxx */ 321 struct lp_fence *fence = lp_fence_create(rank); 322 323 LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank); 324 325 set_scene_state( setup, SETUP_ACTIVE ); 326 327 /* insert the fence into all command bins */ 328 lp_scene_bin_everywhere( scene, 329 lp_rast_fence, 330 lp_rast_arg_fence(fence) ); 331 332 return (struct pipe_fence_handle *) fence; 333} 334 335 336void 337lp_setup_set_triangle_state( struct lp_setup_context *setup, 338 unsigned cull_mode, 339 boolean ccw_is_frontface, 340 boolean scissor ) 341{ 342 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 343 344 setup->ccw_is_frontface = ccw_is_frontface; 345 setup->cullmode = cull_mode; 346 setup->triangle = first_triangle; 347 setup->scissor_test = scissor; 348} 349 350 351 352void 353lp_setup_set_fs_inputs( struct lp_setup_context *setup, 354 const struct lp_shader_input *input, 355 unsigned nr ) 356{ 357 LP_DBG(DEBUG_SETUP, "%s %p %u\n", __FUNCTION__, (void *) input, nr); 358 359 memcpy( setup->fs.input, input, nr * sizeof input[0] ); 360 setup->fs.nr_inputs = nr; 361} 362 363void 364lp_setup_set_fs_functions( struct lp_setup_context *setup, 365 lp_jit_frag_func jit_function0, 366 lp_jit_frag_func jit_function1, 367 boolean opaque ) 368{ 369 LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) jit_function0); 370 /* FIXME: reference count */ 371 372 setup->fs.current.jit_function[0] = jit_function0; 373 setup->fs.current.jit_function[1] = jit_function1; 374 setup->fs.current.opaque = opaque; 375 setup->dirty |= LP_SETUP_NEW_FS; 376} 377 378void 379lp_setup_set_fs_constants(struct lp_setup_context *setup, 380 struct pipe_buffer *buffer) 381{ 382 LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffer); 383 384 pipe_buffer_reference(&setup->constants.current, buffer); 385 386 setup->dirty |= LP_SETUP_NEW_CONSTANTS; 387} 388 389 390void 391lp_setup_set_alpha_ref_value( struct lp_setup_context *setup, 392 float alpha_ref_value ) 393{ 394 LP_DBG(DEBUG_SETUP, "%s %f\n", __FUNCTION__, alpha_ref_value); 395 396 if(setup->fs.current.jit_context.alpha_ref_value != alpha_ref_value) { 397 setup->fs.current.jit_context.alpha_ref_value = alpha_ref_value; 398 setup->dirty |= LP_SETUP_NEW_FS; 399 } 400} 401 402void 403lp_setup_set_blend_color( struct lp_setup_context *setup, 404 const struct pipe_blend_color *blend_color ) 405{ 406 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 407 408 assert(blend_color); 409 410 if(memcmp(&setup->blend_color.current, blend_color, sizeof *blend_color) != 0) { 411 memcpy(&setup->blend_color.current, blend_color, sizeof *blend_color); 412 setup->dirty |= LP_SETUP_NEW_BLEND_COLOR; 413 } 414} 415 416 417void 418lp_setup_set_scissor( struct lp_setup_context *setup, 419 const struct pipe_scissor_state *scissor ) 420{ 421 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 422 423 assert(scissor); 424 425 if (memcmp(&setup->scissor.current, scissor, sizeof(*scissor)) != 0) { 426 setup->scissor.current = *scissor; /* struct copy */ 427 setup->dirty |= LP_SETUP_NEW_SCISSOR; 428 } 429} 430 431 432void 433lp_setup_set_flatshade_first( struct lp_setup_context *setup, 434 boolean flatshade_first ) 435{ 436 setup->flatshade_first = flatshade_first; 437} 438 439 440void 441lp_setup_set_vertex_info( struct lp_setup_context *setup, 442 struct vertex_info *vertex_info ) 443{ 444 /* XXX: just silently holding onto the pointer: 445 */ 446 setup->vertex_info = vertex_info; 447} 448 449 450/** 451 * Called during state validation when LP_NEW_TEXTURE is set. 452 */ 453void 454lp_setup_set_sampler_textures( struct lp_setup_context *setup, 455 unsigned num, struct pipe_texture **texture) 456{ 457 unsigned i; 458 459 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 460 461 assert(num <= PIPE_MAX_SAMPLERS); 462 463 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { 464 struct pipe_texture *tex = i < num ? texture[i] : NULL; 465 466 if(tex) { 467 struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex); 468 struct lp_jit_texture *jit_tex; 469 jit_tex = &setup->fs.current.jit_context.textures[i]; 470 jit_tex->width = tex->width0; 471 jit_tex->height = tex->height0; 472 jit_tex->depth = tex->depth0; 473 jit_tex->last_level = tex->last_level; 474 if (!lp_tex->dt) { 475 /* regular texture - setup array of mipmap level pointers */ 476 int j; 477 for (j = 0; j <= tex->last_level; j++) { 478 jit_tex->data[j] = 479 (ubyte *) lp_tex->data + lp_tex->level_offset[j]; 480 jit_tex->row_stride[j] = lp_tex->stride[j]; 481 } 482 } 483 else { 484 /* display target texture/surface */ 485 /* 486 * XXX: Where should this be unmapped? 487 */ 488 489 struct llvmpipe_screen *screen = llvmpipe_screen(tex->screen); 490 struct sw_winsys *winsys = screen->winsys; 491 jit_tex->data[0] = winsys->displaytarget_map(winsys, lp_tex->dt, 492 PIPE_BUFFER_USAGE_CPU_READ); 493 jit_tex->row_stride[0] = lp_tex->stride[0]; 494 assert(jit_tex->data[0]); 495 } 496 497 /* the scene references this texture */ 498 { 499 struct lp_scene *scene = lp_setup_get_current_scene(setup); 500 lp_scene_texture_reference(scene, tex); 501 } 502 } 503 } 504 505 setup->dirty |= LP_SETUP_NEW_FS; 506} 507 508 509/** 510 * Is the given texture referenced by any scene? 511 * Note: we have to check all scenes including any scenes currently 512 * being rendered and the current scene being built. 513 */ 514unsigned 515lp_setup_is_texture_referenced( const struct lp_setup_context *setup, 516 const struct pipe_texture *texture ) 517{ 518 unsigned i; 519 520 /* check the render targets */ 521 for (i = 0; i < setup->fb.nr_cbufs; i++) { 522 if (setup->fb.cbufs[i]->texture == texture) 523 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 524 } 525 if (setup->fb.zsbuf && setup->fb.zsbuf->texture == texture) { 526 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 527 } 528 529 /* check textures referenced by the scene */ 530 for (i = 0; i < Elements(setup->scenes); i++) { 531 if (lp_scene_is_texture_referenced(setup->scenes[i], texture)) { 532 return PIPE_REFERENCED_FOR_READ; 533 } 534 } 535 536 return PIPE_UNREFERENCED; 537} 538 539 540/** 541 * Called by vbuf code when we're about to draw something. 542 */ 543void 544lp_setup_update_state( struct lp_setup_context *setup ) 545{ 546 struct lp_scene *scene = lp_setup_get_current_scene(setup); 547 548 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 549 550 assert(setup->fs.current.jit_function); 551 552 if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { 553 uint8_t *stored; 554 unsigned i, j; 555 556 stored = lp_scene_alloc_aligned(scene, 4 * 16, 16); 557 558 /* smear each blend color component across 16 ubyte elements */ 559 for (i = 0; i < 4; ++i) { 560 uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); 561 for (j = 0; j < 16; ++j) 562 stored[i*16 + j] = c; 563 } 564 565 setup->blend_color.stored = stored; 566 567 setup->fs.current.jit_context.blend_color = setup->blend_color.stored; 568 setup->dirty |= LP_SETUP_NEW_FS; 569 } 570 571 if (setup->dirty & LP_SETUP_NEW_SCISSOR) { 572 float *stored; 573 574 stored = lp_scene_alloc_aligned(scene, 4 * sizeof(int32_t), 16); 575 576 stored[0] = (float) setup->scissor.current.minx; 577 stored[1] = (float) setup->scissor.current.miny; 578 stored[2] = (float) setup->scissor.current.maxx; 579 stored[3] = (float) setup->scissor.current.maxy; 580 581 setup->scissor.stored = stored; 582 583 setup->fs.current.jit_context.scissor_xmin = stored[0]; 584 setup->fs.current.jit_context.scissor_ymin = stored[1]; 585 setup->fs.current.jit_context.scissor_xmax = stored[2]; 586 setup->fs.current.jit_context.scissor_ymax = stored[3]; 587 588 setup->dirty |= LP_SETUP_NEW_FS; 589 } 590 591 if(setup->dirty & LP_SETUP_NEW_CONSTANTS) { 592 struct pipe_buffer *buffer = setup->constants.current; 593 594 if(buffer) { 595 unsigned current_size = buffer->size; 596 const void *current_data = llvmpipe_buffer(buffer)->data; 597 598 /* TODO: copy only the actually used constants? */ 599 600 if(setup->constants.stored_size != current_size || 601 !setup->constants.stored_data || 602 memcmp(setup->constants.stored_data, 603 current_data, 604 current_size) != 0) { 605 void *stored; 606 607 stored = lp_scene_alloc(scene, current_size); 608 if(stored) { 609 memcpy(stored, 610 current_data, 611 current_size); 612 setup->constants.stored_size = current_size; 613 setup->constants.stored_data = stored; 614 } 615 } 616 } 617 else { 618 setup->constants.stored_size = 0; 619 setup->constants.stored_data = NULL; 620 } 621 622 setup->fs.current.jit_context.constants = setup->constants.stored_data; 623 setup->dirty |= LP_SETUP_NEW_FS; 624 } 625 626 627 if(setup->dirty & LP_SETUP_NEW_FS) { 628 if(!setup->fs.stored || 629 memcmp(setup->fs.stored, 630 &setup->fs.current, 631 sizeof setup->fs.current) != 0) { 632 /* The fs state that's been stored in the scene is different from 633 * the new, current state. So allocate a new lp_rast_state object 634 * and append it to the bin's setup data buffer. 635 */ 636 struct lp_rast_state *stored = 637 (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); 638 if(stored) { 639 memcpy(stored, 640 &setup->fs.current, 641 sizeof setup->fs.current); 642 setup->fs.stored = stored; 643 644 /* put the state-set command into all bins */ 645 lp_scene_bin_state_command( scene, 646 lp_rast_set_state, 647 lp_rast_arg_state(setup->fs.stored) ); 648 } 649 } 650 } 651 652 setup->dirty = 0; 653 654 assert(setup->fs.stored); 655} 656 657 658 659/* Only caller is lp_setup_vbuf_destroy() 660 */ 661void 662lp_setup_destroy( struct lp_setup_context *setup ) 663{ 664 reset_context( setup ); 665 666 pipe_buffer_reference(&setup->constants.current, NULL); 667 668 /* free the scenes in the 'empty' queue */ 669 while (1) { 670 struct lp_scene *scene = lp_scene_dequeue(setup->empty_scenes, FALSE); 671 if (!scene) 672 break; 673 lp_scene_destroy(scene); 674 } 675 676 lp_rast_destroy( setup->rast ); 677 678 FREE( setup ); 679} 680 681 682/** 683 * Create a new primitive tiling engine. Plug it into the backend of 684 * the draw module. Currently also creates a rasterizer to use with 685 * it. 686 */ 687struct lp_setup_context * 688lp_setup_create( struct pipe_context *pipe, 689 struct draw_context *draw ) 690{ 691 unsigned i; 692 struct lp_setup_context *setup = CALLOC_STRUCT(lp_setup_context); 693 694 if (!setup) 695 return NULL; 696 697 lp_setup_init_vbuf(setup); 698 699 setup->empty_scenes = lp_scene_queue_create(); 700 if (!setup->empty_scenes) 701 goto fail; 702 703 /* XXX: move this to the screen and share between contexts: 704 */ 705 setup->rast = lp_rast_create(); 706 if (!setup->rast) 707 goto fail; 708 709 setup->vbuf = draw_vbuf_stage(draw, &setup->base); 710 if (!setup->vbuf) 711 goto fail; 712 713 draw_set_rasterize_stage(draw, setup->vbuf); 714 draw_set_render(draw, &setup->base); 715 716 /* create some empty scenes */ 717 for (i = 0; i < MAX_SCENES; i++) { 718 setup->scenes[i] = lp_scene_create( pipe, setup->empty_scenes ); 719 720 lp_scene_enqueue(setup->empty_scenes, setup->scenes[i]); 721 } 722 723 setup->triangle = first_triangle; 724 setup->line = first_line; 725 setup->point = first_point; 726 727 setup->dirty = ~0; 728 729 return setup; 730 731fail: 732 if (setup->rast) 733 lp_rast_destroy( setup->rast ); 734 735 if (setup->vbuf) 736 ; 737 738 if (setup->empty_scenes) 739 lp_scene_queue_destroy(setup->empty_scenes); 740 741 FREE(setup); 742 return NULL; 743} 744 745