lp_setup.c revision 9a6567f1ed88727545f747e8670b713f17627c94
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-stencil are being cleared when there's 284 * already been some rendering, we could discard the currently 285 * binned scene and start again, but I don't see that as being 286 * a common usage. 287 */ 288 if (flags & PIPE_CLEAR_COLOR) 289 lp_bin_everywhere( bins, 290 lp_rast_clear_color, 291 setup->clear.color ); 292 293 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 294 lp_bin_everywhere( bins, 295 lp_rast_clear_zstencil, 296 setup->clear.zstencil ); 297 } 298 else { 299 /* Put ourselves into the 'pre-clear' state, specifically to try 300 * and accumulate multiple clears to color and depth_stencil 301 * buffers which the app or state-tracker might issue 302 * separately. 303 */ 304 set_state( setup, SETUP_CLEARED ); 305 306 setup->clear.flags |= flags; 307 } 308} 309 310 311 312void 313lp_setup_set_triangle_state( struct setup_context *setup, 314 unsigned cull_mode, 315 boolean ccw_is_frontface) 316{ 317 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 318 319 setup->ccw_is_frontface = ccw_is_frontface; 320 setup->cullmode = cull_mode; 321 setup->triangle = first_triangle; 322} 323 324 325 326void 327lp_setup_set_fs_inputs( struct setup_context *setup, 328 const struct lp_shader_input *input, 329 unsigned nr ) 330{ 331 LP_DBG(DEBUG_SETUP, "%s %p %u\n", __FUNCTION__, (void *) input, nr); 332 333 memcpy( setup->fs.input, input, nr * sizeof input[0] ); 334 setup->fs.nr_inputs = nr; 335} 336 337void 338lp_setup_set_fs( struct setup_context *setup, 339 struct lp_fragment_shader *fs ) 340{ 341 LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) fs); 342 /* FIXME: reference count */ 343 344 setup->fs.current.jit_function = fs ? fs->current->jit_function : NULL; 345 setup->dirty |= LP_SETUP_NEW_FS; 346} 347 348void 349lp_setup_set_fs_constants(struct setup_context *setup, 350 struct pipe_buffer *buffer) 351{ 352 LP_DBG(DEBUG_SETUP, "%s %p\n", __FUNCTION__, (void *) buffer); 353 354 pipe_buffer_reference(&setup->constants.current, buffer); 355 356 setup->dirty |= LP_SETUP_NEW_CONSTANTS; 357} 358 359 360void 361lp_setup_set_alpha_ref_value( struct setup_context *setup, 362 float alpha_ref_value ) 363{ 364 LP_DBG(DEBUG_SETUP, "%s %f\n", __FUNCTION__, alpha_ref_value); 365 366 if(setup->fs.current.jit_context.alpha_ref_value != alpha_ref_value) { 367 setup->fs.current.jit_context.alpha_ref_value = alpha_ref_value; 368 setup->dirty |= LP_SETUP_NEW_FS; 369 } 370} 371 372void 373lp_setup_set_blend_color( struct setup_context *setup, 374 const struct pipe_blend_color *blend_color ) 375{ 376 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 377 378 assert(blend_color); 379 380 if(memcmp(&setup->blend_color.current, blend_color, sizeof *blend_color) != 0) { 381 memcpy(&setup->blend_color.current, blend_color, sizeof *blend_color); 382 setup->dirty |= LP_SETUP_NEW_BLEND_COLOR; 383 } 384} 385 386void 387lp_setup_set_sampler_textures( struct setup_context *setup, 388 unsigned num, struct pipe_texture **texture) 389{ 390 struct pipe_texture *dummy; 391 unsigned i; 392 393 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 394 395 396 assert(num <= PIPE_MAX_SAMPLERS); 397 398 for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { 399 struct pipe_texture *tex = i < num ? texture[i] : NULL; 400 401 /* FIXME: hold on to the reference */ 402 dummy = NULL; 403 pipe_texture_reference(&dummy, tex); 404 405 if(tex) { 406 struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex); 407 struct lp_jit_texture *jit_tex; 408 jit_tex = &setup->fs.current.jit_context.textures[i]; 409 jit_tex->width = tex->width[0]; 410 jit_tex->height = tex->height[0]; 411 jit_tex->stride = lp_tex->stride[0]; 412 if(!lp_tex->dt) 413 jit_tex->data = lp_tex->data; 414 else 415 /* FIXME: map the rendertarget */ 416 assert(0); 417 } 418 } 419 420 setup->dirty |= LP_SETUP_NEW_FS; 421} 422 423boolean 424lp_setup_is_texture_referenced( struct setup_context *setup, 425 const struct pipe_texture *texture ) 426{ 427 /* FIXME */ 428 return PIPE_UNREFERENCED; 429} 430 431 432static INLINE void 433lp_setup_update_shader_state( struct setup_context *setup ) 434{ 435 struct lp_bins *bins = lp_setup_get_current_bins(setup); 436 437 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 438 439 assert(setup->fs.current.jit_function); 440 441 if(setup->dirty & LP_SETUP_NEW_BLEND_COLOR) { 442 uint8_t *stored; 443 unsigned i, j; 444 445 stored = lp_bin_alloc_aligned(bins, 4 * 16, 16); 446 447 /* smear each blend color component across 16 ubyte elements */ 448 for (i = 0; i < 4; ++i) { 449 uint8_t c = float_to_ubyte(setup->blend_color.current.color[i]); 450 for (j = 0; j < 16; ++j) 451 stored[i*16 + j] = c; 452 } 453 454 setup->blend_color.stored = stored; 455 456 setup->fs.current.jit_context.blend_color = setup->blend_color.stored; 457 setup->dirty |= LP_SETUP_NEW_FS; 458 } 459 460 461 if(setup->dirty & LP_SETUP_NEW_CONSTANTS) { 462 struct pipe_buffer *buffer = setup->constants.current; 463 464 if(buffer) { 465 unsigned current_size = buffer->size; 466 const void *current_data = llvmpipe_buffer(buffer)->data; 467 468 /* TODO: copy only the actually used constants? */ 469 470 if(setup->constants.stored_size != current_size || 471 !setup->constants.stored_data || 472 memcmp(setup->constants.stored_data, 473 current_data, 474 current_size) != 0) { 475 void *stored; 476 477 stored = lp_bin_alloc(bins, current_size); 478 if(stored) { 479 memcpy(stored, 480 current_data, 481 current_size); 482 setup->constants.stored_size = current_size; 483 setup->constants.stored_data = stored; 484 } 485 } 486 } 487 else { 488 setup->constants.stored_size = 0; 489 setup->constants.stored_data = NULL; 490 } 491 492 setup->fs.current.jit_context.constants = setup->constants.stored_data; 493 setup->dirty |= LP_SETUP_NEW_FS; 494 } 495 496 497 if(setup->dirty & LP_SETUP_NEW_FS) { 498 if(!setup->fs.stored || 499 memcmp(setup->fs.stored, 500 &setup->fs.current, 501 sizeof setup->fs.current) != 0) { 502 /* The fs state that's been stored in the bins is different from 503 * the new, current state. So allocate a new lp_rast_state object 504 * and append it to the bin's setup data buffer. 505 */ 506 struct lp_rast_state *stored = 507 (struct lp_rast_state *) lp_bin_alloc(bins, sizeof *stored); 508 if(stored) { 509 memcpy(stored, 510 &setup->fs.current, 511 sizeof setup->fs.current); 512 setup->fs.stored = stored; 513 514 /* put the state-set command into all bins */ 515 lp_bin_state_command( bins, 516 lp_rast_set_state, 517 lp_rast_arg_state(setup->fs.stored) ); 518 } 519 } 520 } 521 522 setup->dirty = 0; 523 524 assert(setup->fs.stored); 525} 526 527 528/* Stubs for lines & points for now: 529 */ 530void 531lp_setup_point(struct setup_context *setup, 532 const float (*v0)[4]) 533{ 534 lp_setup_update_shader_state(setup); 535 setup->point( setup, v0 ); 536} 537 538void 539lp_setup_line(struct setup_context *setup, 540 const float (*v0)[4], 541 const float (*v1)[4]) 542{ 543 lp_setup_update_shader_state(setup); 544 setup->line( setup, v0, v1 ); 545} 546 547void 548lp_setup_tri(struct setup_context *setup, 549 const float (*v0)[4], 550 const float (*v1)[4], 551 const float (*v2)[4]) 552{ 553 LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__); 554 555 lp_setup_update_shader_state(setup); 556 setup->triangle( setup, v0, v1, v2 ); 557} 558 559 560void 561lp_setup_destroy( struct setup_context *setup ) 562{ 563 reset_context( setup ); 564 565 pipe_buffer_reference(&setup->constants.current, NULL); 566 567 /* free the bins in the 'empty' queue */ 568 while (lp_bins_queue_size(setup->empty_bins) > 0) { 569 struct lp_bins *bins = lp_bins_dequeue(setup->empty_bins); 570 if (!bins) 571 break; 572 lp_bins_destroy(bins); 573 } 574 575 lp_rast_destroy( setup->rast ); 576 577 FREE( setup ); 578} 579 580 581/** 582 * Create a new primitive tiling engine. Currently also creates a 583 * rasterizer to use with it. 584 */ 585struct setup_context * 586lp_setup_create( struct pipe_screen *screen ) 587{ 588 unsigned i; 589 struct setup_context *setup = CALLOC_STRUCT(setup_context); 590 591 if (!setup) 592 return NULL; 593 594 setup->empty_bins = lp_bins_queue_create(); 595 if (!setup->empty_bins) 596 goto fail; 597 598 setup->rast = lp_rast_create( screen, setup->empty_bins ); 599 if (!setup->rast) 600 goto fail; 601 602 /* create some empty bins */ 603 for (i = 0; i < MAX_BINS; i++) { 604 struct lp_bins *bins = lp_bins_create(); 605 lp_bins_enqueue(setup->empty_bins, bins); 606 } 607 608 setup->triangle = first_triangle; 609 setup->line = first_line; 610 setup->point = first_point; 611 612 setup->dirty = ~0; 613 614 return setup; 615 616fail: 617 if (setup->empty_bins) 618 lp_bins_queue_destroy(setup->empty_bins); 619 620 FREE(setup); 621 return NULL; 622} 623 624