lp_setup.c revision f027d5612901de8e6167e6288c4e24d91d964e7f
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 "lp_winsys.h" 50 51#include "draw/draw_context.h" 52#include "draw/draw_vbuf.h" 53 54 55static void set_scene_state( struct setup_context *, unsigned ); 56 57 58struct lp_scene * 59lp_setup_get_current_scene(struct 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 setup_context *setup, 434 boolean flatshade_first ) 435{ 436 setup->flatshade_first = flatshade_first; 437} 438 439 440void 441lp_setup_set_vertex_info( struct 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 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 jit_tex->stride = lp_tex->stride[0]; 475 if (!lp_tex->dt) { 476 /* regular texture - setup array of mipmap level pointers */ 477 int j; 478 for (j = 0; j < LP_MAX_TEXTURE_2D_LEVELS; j++) { 479 jit_tex->data[j] = 480 (ubyte *) lp_tex->data + lp_tex->level_offset[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 llvmpipe_winsys *winsys = screen->winsys; 491 jit_tex->data[0] = winsys->displaytarget_map(winsys, lp_tex->dt, 492 PIPE_BUFFER_USAGE_CPU_READ); 493 assert(jit_tex->data[0]); 494 } 495 496 /* the scene references this texture */ 497 { 498 struct lp_scene *scene = lp_setup_get_current_scene(setup); 499 lp_scene_texture_reference(scene, tex); 500 } 501 } 502 } 503 504 setup->dirty |= LP_SETUP_NEW_FS; 505} 506 507 508/** 509 * Is the given texture referenced by any scene? 510 * Note: we have to check all scenes including any scenes currently 511 * being rendered and the current scene being built. 512 */ 513unsigned 514lp_setup_is_texture_referenced( const struct setup_context *setup, 515 const struct pipe_texture *texture ) 516{ 517 unsigned i; 518 519 /* check the render targets */ 520 for (i = 0; i < setup->fb.nr_cbufs; i++) { 521 if (setup->fb.cbufs[i]->texture == texture) 522 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 523 } 524 if (setup->fb.zsbuf && setup->fb.zsbuf->texture == texture) { 525 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; 526 } 527 528 /* check textures referenced by the scene */ 529 for (i = 0; i < Elements(setup->scenes); i++) { 530 if (lp_scene_is_texture_referenced(setup->scenes[i], texture)) { 531 return PIPE_REFERENCED_FOR_READ; 532 } 533 } 534 535 return PIPE_UNREFERENCED; 536} 537 538 539/** 540 * Called by vbuf code when we're about to draw something. 541 */ 542void 543lp_setup_update_state( struct setup_context *setup ) 544{ 545 struct lp_scene *scene = lp_setup_get_current_scene(setup); 546 547 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 548 549 assert(setup->fs.current.jit_function); 550 551 if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { 552 uint8_t *stored; 553 unsigned i, j; 554 555 stored = lp_scene_alloc_aligned(scene, 4 * 16, 16); 556 557 /* smear each blend color component across 16 ubyte elements */ 558 for (i = 0; i < 4; ++i) { 559 uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); 560 for (j = 0; j < 16; ++j) 561 stored[i*16 + j] = c; 562 } 563 564 setup->blend_color.stored = stored; 565 566 setup->fs.current.jit_context.blend_color = setup->blend_color.stored; 567 setup->dirty |= LP_SETUP_NEW_FS; 568 } 569 570 if (setup->dirty & LP_SETUP_NEW_SCISSOR) { 571 float *stored; 572 573 stored = lp_scene_alloc_aligned(scene, 4 * sizeof(int32_t), 16); 574 575 stored[0] = (float) setup->scissor.current.minx; 576 stored[1] = (float) setup->scissor.current.miny; 577 stored[2] = (float) setup->scissor.current.maxx; 578 stored[3] = (float) setup->scissor.current.maxy; 579 580 setup->scissor.stored = stored; 581 582 setup->fs.current.jit_context.scissor_xmin = stored[0]; 583 setup->fs.current.jit_context.scissor_ymin = stored[1]; 584 setup->fs.current.jit_context.scissor_xmax = stored[2]; 585 setup->fs.current.jit_context.scissor_ymax = stored[3]; 586 587 setup->dirty |= LP_SETUP_NEW_FS; 588 } 589 590 if(setup->dirty & LP_SETUP_NEW_CONSTANTS) { 591 struct pipe_buffer *buffer = setup->constants.current; 592 593 if(buffer) { 594 unsigned current_size = buffer->size; 595 const void *current_data = llvmpipe_buffer(buffer)->data; 596 597 /* TODO: copy only the actually used constants? */ 598 599 if(setup->constants.stored_size != current_size || 600 !setup->constants.stored_data || 601 memcmp(setup->constants.stored_data, 602 current_data, 603 current_size) != 0) { 604 void *stored; 605 606 stored = lp_scene_alloc(scene, current_size); 607 if(stored) { 608 memcpy(stored, 609 current_data, 610 current_size); 611 setup->constants.stored_size = current_size; 612 setup->constants.stored_data = stored; 613 } 614 } 615 } 616 else { 617 setup->constants.stored_size = 0; 618 setup->constants.stored_data = NULL; 619 } 620 621 setup->fs.current.jit_context.constants = setup->constants.stored_data; 622 setup->dirty |= LP_SETUP_NEW_FS; 623 } 624 625 626 if(setup->dirty & LP_SETUP_NEW_FS) { 627 if(!setup->fs.stored || 628 memcmp(setup->fs.stored, 629 &setup->fs.current, 630 sizeof setup->fs.current) != 0) { 631 /* The fs state that's been stored in the scene is different from 632 * the new, current state. So allocate a new lp_rast_state object 633 * and append it to the bin's setup data buffer. 634 */ 635 struct lp_rast_state *stored = 636 (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); 637 if(stored) { 638 memcpy(stored, 639 &setup->fs.current, 640 sizeof setup->fs.current); 641 setup->fs.stored = stored; 642 643 /* put the state-set command into all bins */ 644 lp_scene_bin_state_command( scene, 645 lp_rast_set_state, 646 lp_rast_arg_state(setup->fs.stored) ); 647 } 648 } 649 } 650 651 setup->dirty = 0; 652 653 assert(setup->fs.stored); 654} 655 656 657 658/* Only caller is lp_setup_vbuf_destroy() 659 */ 660void 661lp_setup_destroy( struct setup_context *setup ) 662{ 663 reset_context( setup ); 664 665 pipe_buffer_reference(&setup->constants.current, NULL); 666 667 /* free the scenes in the 'empty' queue */ 668 while (1) { 669 struct lp_scene *scene = lp_scene_dequeue(setup->empty_scenes, FALSE); 670 if (!scene) 671 break; 672 lp_scene_destroy(scene); 673 } 674 675 lp_rast_destroy( setup->rast ); 676 677 FREE( setup ); 678} 679 680 681/** 682 * Create a new primitive tiling engine. Plug it into the backend of 683 * the draw module. Currently also creates a rasterizer to use with 684 * it. 685 */ 686struct setup_context * 687lp_setup_create( struct pipe_context *pipe, 688 struct draw_context *draw ) 689{ 690 unsigned i; 691 struct setup_context *setup = CALLOC_STRUCT(setup_context); 692 693 if (!setup) 694 return NULL; 695 696 lp_setup_init_vbuf(setup); 697 698 setup->empty_scenes = lp_scene_queue_create(); 699 if (!setup->empty_scenes) 700 goto fail; 701 702 /* XXX: move this to the screen and share between contexts: 703 */ 704 setup->rast = lp_rast_create(); 705 if (!setup->rast) 706 goto fail; 707 708 setup->vbuf = draw_vbuf_stage(draw, &setup->base); 709 if (!setup->vbuf) 710 goto fail; 711 712 draw_set_rasterize_stage(draw, setup->vbuf); 713 draw_set_render(draw, &setup->base); 714 715 /* create some empty scenes */ 716 for (i = 0; i < MAX_SCENES; i++) { 717 setup->scenes[i] = lp_scene_create( pipe, setup->empty_scenes ); 718 719 lp_scene_enqueue(setup->empty_scenes, setup->scenes[i]); 720 } 721 722 setup->triangle = first_triangle; 723 setup->line = first_line; 724 setup->point = first_point; 725 726 setup->dirty = ~0; 727 728 return setup; 729 730fail: 731 if (setup->rast) 732 lp_rast_destroy( setup->rast ); 733 734 if (setup->vbuf) 735 ; 736 737 if (setup->empty_scenes) 738 lp_scene_queue_destroy(setup->empty_scenes); 739 740 FREE(setup); 741 return NULL; 742} 743 744