lp_setup.c revision da45f49cc63fff06513dc28d9616084fc81798d4
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 "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 49#include "draw/draw_context.h" 50#include "draw/draw_vbuf.h" 51 52 53/** XXX temporary value, temporary here */ 54#define MAX_SCENES 2 55 56 57static void set_scene_state( struct setup_context *, unsigned ); 58 59 60struct lp_scene * 61lp_setup_get_current_scene(struct setup_context *setup) 62{ 63 if (!setup->scene) { 64 /* wait for a free/empty bin */ 65 setup->scene = lp_scene_dequeue(setup->empty_scenes); 66 if(0)lp_scene_reset( setup->scene ); /* XXX temporary? */ 67 68 lp_scene_set_framebuffer_size(setup->scene, 69 setup->fb.width, 70 setup->fb.height); 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_rasterize_scene(setup->rast, 140 scene, 141 &setup->fb, 142 write_depth); 143 144 reset_context( setup ); 145 146 LP_DBG(DEBUG_SETUP, "%s done \n", __FUNCTION__); 147} 148 149 150 151static void 152begin_binning( struct setup_context *setup ) 153{ 154 struct lp_scene *scene = lp_setup_get_current_scene(setup); 155 156 LP_DBG(DEBUG_SETUP, "%s color: %s depth: %s\n", __FUNCTION__, 157 (setup->clear.flags & PIPE_CLEAR_COLOR) ? "clear": "load", 158 (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) ? "clear": "load"); 159 160 if (setup->fb.nr_cbufs) { 161 if (setup->clear.flags & PIPE_CLEAR_COLOR) 162 lp_scene_bin_everywhere( scene, 163 lp_rast_clear_color, 164 setup->clear.color ); 165 else 166 lp_scene_bin_everywhere( scene, 167 lp_rast_load_color, 168 lp_rast_arg_null() ); 169 } 170 171 if (setup->fb.zsbuf) { 172 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 173 lp_scene_bin_everywhere( scene, 174 lp_rast_clear_zstencil, 175 setup->clear.zstencil ); 176 else 177 lp_scene_bin_everywhere( scene, 178 lp_rast_load_zstencil, 179 lp_rast_arg_null() ); 180 } 181 182 LP_DBG(DEBUG_SETUP, "%s done\n", __FUNCTION__); 183} 184 185 186/* This basically bins and then flushes any outstanding full-screen 187 * clears. 188 * 189 * TODO: fast path for fullscreen clears and no triangles. 190 */ 191static void 192execute_clears( struct setup_context *setup ) 193{ 194 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 195 196 begin_binning( setup ); 197 lp_setup_rasterize_scene( setup, TRUE ); 198} 199 200 201static void 202set_scene_state( struct setup_context *setup, 203 unsigned new_state ) 204{ 205 unsigned old_state = setup->state; 206 207 if (old_state == new_state) 208 return; 209 210 LP_DBG(DEBUG_SETUP, "%s old %d new %d\n", __FUNCTION__, old_state, new_state); 211 212 switch (new_state) { 213 case SETUP_ACTIVE: 214 begin_binning( setup ); 215 break; 216 217 case SETUP_CLEARED: 218 if (old_state == SETUP_ACTIVE) { 219 assert(0); 220 return; 221 } 222 break; 223 224 case SETUP_FLUSHED: 225 if (old_state == SETUP_CLEARED) 226 execute_clears( setup ); 227 else 228 lp_setup_rasterize_scene( setup, TRUE ); 229 break; 230 } 231 232 setup->state = new_state; 233} 234 235 236void 237lp_setup_flush( struct setup_context *setup, 238 unsigned flags ) 239{ 240 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 241 242 set_scene_state( setup, SETUP_FLUSHED ); 243} 244 245 246void 247lp_setup_bind_framebuffer( struct setup_context *setup, 248 const struct pipe_framebuffer_state *fb ) 249{ 250 struct lp_scene *scene = lp_setup_get_current_scene(setup); 251 252 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 253 254 set_scene_state( setup, SETUP_FLUSHED ); 255 256 util_copy_framebuffer_state(&setup->fb, fb); 257 258 lp_scene_set_framebuffer_size(scene, setup->fb.width, setup->fb.height); 259} 260 261 262void 263lp_setup_clear( struct setup_context *setup, 264 const float *color, 265 double depth, 266 unsigned stencil, 267 unsigned flags ) 268{ 269 struct lp_scene *scene = lp_setup_get_current_scene(setup); 270 unsigned i; 271 272 LP_DBG(DEBUG_SETUP, "%s state %d\n", __FUNCTION__, setup->state); 273 274 275 if (flags & PIPE_CLEAR_COLOR) { 276 for (i = 0; i < 4; ++i) 277 setup->clear.color.clear_color[i] = float_to_ubyte(color[i]); 278 } 279 280 if (flags & PIPE_CLEAR_DEPTHSTENCIL) { 281 setup->clear.zstencil.clear_zstencil = 282 util_pack_z_stencil(setup->fb.zsbuf->format, 283 depth, 284 stencil); 285 } 286 287 if (setup->state == SETUP_ACTIVE) { 288 /* Add the clear to existing scene. In the unusual case where 289 * both color and depth-stencil are being cleared when there's 290 * already been some rendering, we could discard the currently 291 * binned scene and start again, but I don't see that as being 292 * a common usage. 293 */ 294 if (flags & PIPE_CLEAR_COLOR) 295 lp_scene_bin_everywhere( scene, 296 lp_rast_clear_color, 297 setup->clear.color ); 298 299 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 300 lp_scene_bin_everywhere( scene, 301 lp_rast_clear_zstencil, 302 setup->clear.zstencil ); 303 } 304 else { 305 /* Put ourselves into the 'pre-clear' state, specifically to try 306 * and accumulate multiple clears to color and depth_stencil 307 * buffers which the app or state-tracker might issue 308 * separately. 309 */ 310 set_scene_state( setup, SETUP_CLEARED ); 311 312 setup->clear.flags |= flags; 313 } 314} 315 316 317/** 318 * Emit a fence. 319 */ 320struct pipe_fence_handle * 321lp_setup_fence( struct setup_context *setup ) 322{ 323 struct lp_scene *scene = lp_setup_get_current_scene(setup); 324 const unsigned rank = lp_scene_get_num_bins( scene ); /* xxx */ 325 struct lp_fence *fence = lp_fence_create(rank); 326 327 LP_DBG(DEBUG_SETUP, "%s rank %u\n", __FUNCTION__, rank); 328 329 set_scene_state( setup, SETUP_ACTIVE ); 330 331 /* insert the fence into all command bins */ 332 lp_scene_bin_everywhere( scene, 333 lp_rast_fence, 334 lp_rast_arg_fence(fence) ); 335 336 return (struct pipe_fence_handle *) fence; 337} 338 339 340void 341lp_setup_set_triangle_state( struct setup_context *setup, 342 unsigned cull_mode, 343 boolean ccw_is_frontface) 344{ 345 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 346 347 setup->ccw_is_frontface = ccw_is_frontface; 348 setup->cullmode = cull_mode; 349 setup->triangle = first_triangle; 350} 351 352 353 354void 355lp_setup_set_fs_inputs( struct setup_context *setup, 356 const struct lp_shader_input *input, 357 unsigned nr ) 358{ 359 LP_DBG(DEBUG_SETUP, "%s %p %u\n", __FUNCTION__, (void *) input, nr); 360 361 memcpy( setup->fs.input, input, nr * sizeof input[0] ); 362 setup->fs.nr_inputs = nr; 363} 364 365void 366lp_setup_set_fs_function( struct setup_context *setup, 367 lp_jit_frag_func jit_function ) 368{ 369 LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) jit_function); 370 /* FIXME: reference count */ 371 372 setup->fs.current.jit_function = jit_function; 373 setup->dirty |= LP_SETUP_NEW_FS; 374} 375 376void 377lp_setup_set_fs_constants(struct setup_context *setup, 378 struct pipe_buffer *buffer) 379{ 380 LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffer); 381 382 pipe_buffer_reference(&setup->constants.current, buffer); 383 384 setup->dirty |= LP_SETUP_NEW_CONSTANTS; 385} 386 387 388void 389lp_setup_set_alpha_ref_value( struct setup_context *setup, 390 float alpha_ref_value ) 391{ 392 LP_DBG(DEBUG_SETUP, "%s %f\n", __FUNCTION__, alpha_ref_value); 393 394 if(setup->fs.current.jit_context.alpha_ref_value != alpha_ref_value) { 395 setup->fs.current.jit_context.alpha_ref_value = alpha_ref_value; 396 setup->dirty |= LP_SETUP_NEW_FS; 397 } 398} 399 400void 401lp_setup_set_blend_color( struct setup_context *setup, 402 const struct pipe_blend_color *blend_color ) 403{ 404 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 405 406 assert(blend_color); 407 408 if(memcmp(&setup->blend_color.current, blend_color, sizeof *blend_color) != 0) { 409 memcpy(&setup->blend_color.current, blend_color, sizeof *blend_color); 410 setup->dirty |= LP_SETUP_NEW_BLEND_COLOR; 411 } 412} 413 414 415void 416lp_setup_set_flatshade_first( struct setup_context *setup, 417 boolean flatshade_first ) 418{ 419 setup->flatshade_first = flatshade_first; 420} 421 422 423void 424lp_setup_set_vertex_info( struct setup_context *setup, 425 struct vertex_info *vertex_info ) 426{ 427 /* XXX: just silently holding onto the pointer: 428 */ 429 setup->vertex_info = vertex_info; 430} 431 432 433void 434lp_setup_set_sampler_textures( struct setup_context *setup, 435 unsigned num, struct pipe_texture **texture) 436{ 437 struct pipe_texture *dummy; 438 unsigned i; 439 440 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 441 442 443 assert(num <= PIPE_MAX_SAMPLERS); 444 445 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { 446 struct pipe_texture *tex = i < num ? texture[i] : NULL; 447 448 /* FIXME: hold on to the reference */ 449 dummy = NULL; 450 pipe_texture_reference(&dummy, tex); 451 452 if(tex) { 453 struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex); 454 struct lp_jit_texture *jit_tex; 455 jit_tex = &setup->fs.current.jit_context.textures[i]; 456 jit_tex->width = tex->width0; 457 jit_tex->height = tex->height0; 458 jit_tex->stride = lp_tex->stride[0]; 459 if(!lp_tex->dt) 460 jit_tex->data = lp_tex->data; 461 else 462 /* FIXME: map the rendertarget */ 463 assert(0); 464 } 465 } 466 467 setup->dirty |= LP_SETUP_NEW_FS; 468} 469 470boolean 471lp_setup_is_texture_referenced( struct setup_context *setup, 472 const struct pipe_texture *texture ) 473{ 474 /* FIXME */ 475 return PIPE_UNREFERENCED; 476} 477 478 479void 480lp_setup_update_state( struct setup_context *setup ) 481{ 482 struct lp_scene *scene = lp_setup_get_current_scene(setup); 483 484 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 485 486 assert(setup->fs.current.jit_function); 487 488 if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { 489 uint8_t *stored; 490 unsigned i, j; 491 492 stored = lp_scene_alloc_aligned(scene, 4 * 16, 16); 493 494 /* smear each blend color component across 16 ubyte elements */ 495 for (i = 0; i < 4; ++i) { 496 uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); 497 for (j = 0; j < 16; ++j) 498 stored[i*16 + j] = c; 499 } 500 501 setup->blend_color.stored = stored; 502 503 setup->fs.current.jit_context.blend_color = setup->blend_color.stored; 504 setup->dirty |= LP_SETUP_NEW_FS; 505 } 506 507 508 if(setup->dirty & LP_SETUP_NEW_CONSTANTS) { 509 struct pipe_buffer *buffer = setup->constants.current; 510 511 if(buffer) { 512 unsigned current_size = buffer->size; 513 const void *current_data = llvmpipe_buffer(buffer)->data; 514 515 /* TODO: copy only the actually used constants? */ 516 517 if(setup->constants.stored_size != current_size || 518 !setup->constants.stored_data || 519 memcmp(setup->constants.stored_data, 520 current_data, 521 current_size) != 0) { 522 void *stored; 523 524 stored = lp_scene_alloc(scene, current_size); 525 if(stored) { 526 memcpy(stored, 527 current_data, 528 current_size); 529 setup->constants.stored_size = current_size; 530 setup->constants.stored_data = stored; 531 } 532 } 533 } 534 else { 535 setup->constants.stored_size = 0; 536 setup->constants.stored_data = NULL; 537 } 538 539 setup->fs.current.jit_context.constants = setup->constants.stored_data; 540 setup->dirty |= LP_SETUP_NEW_FS; 541 } 542 543 544 if(setup->dirty & LP_SETUP_NEW_FS) { 545 if(!setup->fs.stored || 546 memcmp(setup->fs.stored, 547 &setup->fs.current, 548 sizeof setup->fs.current) != 0) { 549 /* The fs state that's been stored in the scene is different from 550 * the new, current state. So allocate a new lp_rast_state object 551 * and append it to the bin's setup data buffer. 552 */ 553 struct lp_rast_state *stored = 554 (struct lp_rast_state *) lp_scene_alloc(scene, sizeof *stored); 555 if(stored) { 556 memcpy(stored, 557 &setup->fs.current, 558 sizeof setup->fs.current); 559 setup->fs.stored = stored; 560 561 /* put the state-set command into all bins */ 562 lp_scene_bin_state_command( scene, 563 lp_rast_set_state, 564 lp_rast_arg_state(setup->fs.stored) ); 565 } 566 } 567 } 568 569 setup->dirty = 0; 570 571 assert(setup->fs.stored); 572} 573 574 575 576/* Only caller is lp_setup_vbuf_destroy() 577 */ 578void 579lp_setup_destroy( struct setup_context *setup ) 580{ 581 reset_context( setup ); 582 583 pipe_buffer_reference(&setup->constants.current, NULL); 584 585 /* free the scenes in the 'empty' queue */ 586 while (lp_scene_queue_count(setup->empty_scenes) > 0) { 587 struct lp_scene *scene = lp_scene_dequeue(setup->empty_scenes); 588 if (!scene) 589 break; 590 lp_scene_destroy(scene); 591 } 592 593 lp_rast_destroy( setup->rast ); 594 595 FREE( setup ); 596} 597 598 599/** 600 * Create a new primitive tiling engine. Plug it into the backend of 601 * the draw module. Currently also creates a rasterizer to use with 602 * it. 603 */ 604struct setup_context * 605lp_setup_create( struct pipe_screen *screen, 606 struct draw_context *draw ) 607{ 608 unsigned i; 609 struct setup_context *setup = CALLOC_STRUCT(setup_context); 610 611 if (!setup) 612 return NULL; 613 614 lp_setup_init_vbuf(setup); 615 616 setup->empty_scenes = lp_scene_queue_create(); 617 if (!setup->empty_scenes) 618 goto fail; 619 620 setup->rast = lp_rast_create( screen, setup->empty_scenes ); 621 if (!setup->rast) 622 goto fail; 623 624 setup->vbuf = draw_vbuf_stage(draw, &setup->base); 625 if (!setup->vbuf) 626 goto fail; 627 628 draw_set_rasterize_stage(draw, setup->vbuf); 629 draw_set_render(draw, &setup->base); 630 631 /* create some empty scenes */ 632 for (i = 0; i < MAX_SCENES; i++) { 633 struct lp_scene *scene = lp_scene_create(); 634 lp_scene_enqueue(setup->empty_scenes, scene); 635 } 636 637 setup->triangle = first_triangle; 638 setup->line = first_line; 639 setup->point = first_point; 640 641 setup->dirty = ~0; 642 643 return setup; 644 645fail: 646 if (setup->rast) 647 lp_rast_destroy( setup->rast ); 648 649 if (setup->vbuf) 650 ; 651 652 if (setup->empty_scenes) 653 lp_scene_queue_destroy(setup->empty_scenes); 654 655 FREE(setup); 656 return NULL; 657} 658 659