lp_setup.c revision 1928c965b1fb76987cbc834111bd1d1e1f2cda51
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_math.h" 38#include "util/u_memory.h" 39#include "util/u_pack_color.h" 40#include "lp_state.h" 41#include "lp_buffer.h" 42#include "lp_texture.h" 43#include "lp_setup_context.h" 44 45static void set_state( struct setup_context *, unsigned ); 46 47void lp_setup_new_cmd_block( struct cmd_block_list *list ) 48{ 49 struct cmd_block *block = MALLOC_STRUCT(cmd_block); 50 list->tail->next = block; 51 list->tail = block; 52 block->next = NULL; 53 block->count = 0; 54} 55 56void lp_setup_new_data_block( struct data_block_list *list ) 57{ 58 struct data_block *block = MALLOC_STRUCT(data_block); 59 list->tail->next = block; 60 list->tail = block; 61 block->next = NULL; 62 block->used = 0; 63} 64 65 66static void 67first_triangle( struct setup_context *setup, 68 const float (*v0)[4], 69 const float (*v1)[4], 70 const float (*v2)[4]) 71{ 72 set_state( setup, SETUP_ACTIVE ); 73 lp_setup_choose_triangle( setup ); 74 setup->triangle( setup, v0, v1, v2 ); 75} 76 77static void 78first_line( struct setup_context *setup, 79 const float (*v0)[4], 80 const float (*v1)[4]) 81{ 82 set_state( setup, SETUP_ACTIVE ); 83 lp_setup_choose_line( setup ); 84 setup->line( setup, v0, v1 ); 85} 86 87static void 88first_point( struct setup_context *setup, 89 const float (*v0)[4]) 90{ 91 set_state( setup, SETUP_ACTIVE ); 92 lp_setup_choose_point( setup ); 93 setup->point( setup, v0 ); 94} 95 96static void reset_context( struct setup_context *setup ) 97{ 98 unsigned i, j; 99 100 /* Free binner command lists: 101 */ 102 for (i = 0; i < setup->tiles_x; i++) { 103 for (j = 0; j < setup->tiles_y; j++) { 104 struct cmd_block_list *list = &setup->tile[i][j]; 105 struct cmd_block *block; 106 struct cmd_block *tmp; 107 108 for (block = list->head; block != list->tail; block = tmp) { 109 tmp = block->next; 110 FREE(block); 111 } 112 113 list->head = list->tail; 114 } 115 } 116 117 /* Free binned data: 118 */ 119 { 120 struct data_block_list *list = &setup->data; 121 struct data_block *block, *tmp; 122 123 for (block = list->head; block != list->tail; block = tmp) { 124 tmp = block->next; 125 FREE(block); 126 } 127 128 list->head = list->tail; 129 } 130 131 /* Reset some state: 132 */ 133 setup->clear.flags = 0; 134 135 /* Have an explicit "start-binning" call and get rid of this 136 * pointer twiddling? 137 */ 138 setup->line = first_line; 139 setup->point = first_point; 140 setup->triangle = first_triangle; 141} 142 143 144 145 146/* Add a command to all active bins. 147 */ 148static void bin_everywhere( struct setup_context *setup, 149 lp_rast_cmd cmd, 150 const union lp_rast_cmd_arg arg ) 151{ 152 unsigned i, j; 153 for (i = 0; i < setup->tiles_x; i++) 154 for (j = 0; j < setup->tiles_y; j++) 155 bin_command( &setup->tile[i][j], cmd, arg ); 156} 157 158 159static void 160rasterize_bins( struct setup_context *setup, 161 boolean write_depth ) 162{ 163 struct lp_rasterizer *rast = setup->rast; 164 struct cmd_block *block; 165 unsigned i,j,k; 166 167 if (setup->state != SETUP_ACTIVE) { 168 /* this can happen, not a big deal */ 169 debug_printf("%s called when not binning\n", __FUNCTION__); 170 return; 171 } 172 173 lp_rast_begin( rast, 174 setup->fb.width, 175 setup->fb.height ); 176 177 lp_rast_bind_color( rast, 178 setup->fb.cbuf, 179 setup->fb.cbuf != NULL ); 180 181 lp_rast_bind_zstencil( rast, 182 setup->fb.zsbuf, 183 setup->fb.zsbuf != NULL && write_depth ); 184 185 for (i = 0; i < setup->tiles_x; i++) { 186 for (j = 0; j < setup->tiles_y; j++) { 187 188 lp_rast_start_tile( rast, 189 i * TILESIZE, 190 j * TILESIZE ); 191 192 for (block = setup->tile[i][j].head; block; block = block->next) { 193 for (k = 0; k < block->count; k++) { 194 block->cmd[k]( rast, block->arg[k] ); 195 } 196 } 197 198 lp_rast_end_tile( rast ); 199 } 200 } 201 202 reset_context( setup ); 203} 204 205 206 207static void 208begin_binning( struct setup_context *setup ) 209{ 210 if (!setup->fb.cbuf && !setup->fb.zsbuf) { 211 setup->fb.width = 0; 212 setup->fb.height = 0; 213 } 214 else if (!setup->fb.zsbuf) { 215 setup->fb.width = setup->fb.cbuf->width; 216 setup->fb.height = setup->fb.cbuf->height; 217 } 218 else if (!setup->fb.cbuf) { 219 setup->fb.width = setup->fb.zsbuf->width; 220 setup->fb.height = setup->fb.zsbuf->height; 221 } 222 else { 223 /* XXX: not sure what we're really supposed to do for 224 * mis-matched color & depth buffer sizes. 225 */ 226 setup->fb.width = MIN2(setup->fb.cbuf->width, 227 setup->fb.zsbuf->width); 228 setup->fb.height = MIN2(setup->fb.cbuf->height, 229 setup->fb.zsbuf->height); 230 } 231 232 setup->tiles_x = align(setup->fb.width, TILESIZE); 233 setup->tiles_y = align(setup->fb.height, TILESIZE); 234 235 if (setup->fb.cbuf) { 236 if (setup->clear.flags & PIPE_CLEAR_COLOR) 237 bin_everywhere( setup, 238 lp_rast_clear_color, 239 setup->clear.color ); 240 else 241 bin_everywhere( setup, lp_rast_load_color, lp_rast_arg_null() ); 242 } 243 244 if (setup->fb.zsbuf) { 245 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 246 bin_everywhere( setup, 247 lp_rast_clear_zstencil, 248 setup->clear.zstencil ); 249 else 250 bin_everywhere( setup, lp_rast_load_zstencil, lp_rast_arg_null() ); 251 } 252} 253 254 255/* This basically bins and then flushes any outstanding full-screen 256 * clears. 257 * 258 * TODO: fast path for fullscreen clears and no triangles. 259 */ 260static void 261execute_clears( struct setup_context *setup ) 262{ 263 begin_binning( setup ); 264 rasterize_bins( setup, TRUE ); 265} 266 267 268static void 269set_state( struct setup_context *setup, 270 unsigned new_state ) 271{ 272 unsigned old_state = setup->state; 273 274 if (old_state == new_state) 275 return; 276 277 switch (new_state) { 278 case SETUP_ACTIVE: 279 if (old_state == SETUP_FLUSHED) 280 begin_binning( setup ); 281 break; 282 283 case SETUP_CLEARED: 284 if (old_state == SETUP_ACTIVE) { 285 assert(0); 286 return; 287 } 288 break; 289 290 case SETUP_FLUSHED: 291 if (old_state == SETUP_CLEARED) 292 execute_clears( setup ); 293 else 294 rasterize_bins( setup, TRUE ); 295 break; 296 } 297 298 setup->state = new_state; 299} 300 301 302void 303lp_setup_flush( struct setup_context *setup, 304 unsigned flags ) 305{ 306 set_state( setup, SETUP_FLUSHED ); 307} 308 309 310void 311lp_setup_bind_framebuffer( struct setup_context *setup, 312 struct pipe_surface *color, 313 struct pipe_surface *zstencil ) 314{ 315 unsigned width, height; 316 317 set_state( setup, SETUP_FLUSHED ); 318 319 pipe_surface_reference( &setup->fb.cbuf, color ); 320 pipe_surface_reference( &setup->fb.zsbuf, zstencil ); 321 322 width = MAX2( color->width, zstencil->width ); 323 height = MAX2( color->height, zstencil->height ); 324 325 setup->tiles_x = align( width, TILESIZE ) / TILESIZE; 326 setup->tiles_y = align( height, TILESIZE ) / TILESIZE; 327} 328 329void 330lp_setup_clear( struct setup_context *setup, 331 const float *color, 332 double depth, 333 unsigned stencil, 334 unsigned flags ) 335{ 336 if (flags & PIPE_CLEAR_COLOR) { 337 util_pack_color(color, 338 setup->fb.cbuf->format, 339 &setup->clear.color.clear_color ); 340 } 341 342 if (flags & PIPE_CLEAR_DEPTHSTENCIL) { 343 setup->clear.zstencil.clear_zstencil = 344 util_pack_z_stencil(setup->fb.zsbuf->format, 345 depth, 346 stencil); 347 } 348 349 if (setup->state == SETUP_ACTIVE) { 350 /* Add the clear to existing bins. In the unusual case where 351 * both color and depth-stencilare being cleared, we could 352 * discard the currently binned scene and start again, but I 353 * don't see that as being a common usage. 354 */ 355 if (flags & PIPE_CLEAR_COLOR) 356 bin_everywhere( setup, 357 lp_rast_clear_color, 358 setup->clear.color ); 359 360 if (setup->clear.flags & PIPE_CLEAR_DEPTHSTENCIL) 361 bin_everywhere( setup, 362 lp_rast_clear_zstencil, 363 setup->clear.zstencil ); 364 } 365 else { 366 /* Put ourselves into the 'pre-clear' state, specifically to try 367 * and accumulate multiple clears to color and depth_stencil 368 * buffers which the app or state-tracker might issue 369 * separately. 370 */ 371 set_state( setup, SETUP_CLEARED ); 372 373 setup->clear.flags |= flags; 374 } 375} 376 377 378 379void 380lp_setup_set_triangle_state( struct setup_context *setup, 381 unsigned cull_mode, 382 boolean ccw_is_frontface) 383{ 384 setup->ccw_is_frontface = ccw_is_frontface; 385 setup->cullmode = cull_mode; 386 setup->triangle = first_triangle; 387} 388 389 390 391void 392lp_setup_set_fs_inputs( struct setup_context *setup, 393 const struct lp_shader_input *input, 394 unsigned nr ) 395{ 396 memcpy( setup->fs.input, input, nr * sizeof input[0] ); 397 setup->fs.nr_inputs = nr; 398} 399 400void 401lp_setup_set_fs( struct setup_context *setup, 402 struct lp_fragment_shader *fs ) 403{ 404 /* FIXME: reference count */ 405 406 setup->fs.jit_function = fs->current->jit_function; 407} 408 409void 410lp_setup_set_fs_constants(struct setup_context *setup, 411 struct pipe_buffer *buffer) 412{ 413 const void *data = buffer ? llvmpipe_buffer(buffer)->data : NULL; 414 struct pipe_buffer *dummy; 415 416 /* FIXME: hold on to the reference */ 417 dummy = NULL; 418 pipe_buffer_reference(&dummy, buffer); 419 420 setup->fs.jit_context.constants = data; 421 422 setup->fs.jit_context_dirty = TRUE; 423} 424 425 426void 427lp_setup_set_alpha_ref_value( struct setup_context *setup, 428 float alpha_ref_value ) 429{ 430 if(setup->fs.jit_context.alpha_ref_value != alpha_ref_value) { 431 setup->fs.jit_context.alpha_ref_value = alpha_ref_value; 432 setup->fs.jit_context_dirty = TRUE; 433 } 434} 435 436void 437lp_setup_set_blend_color( struct setup_context *setup, 438 const struct pipe_blend_color *blend_color ) 439{ 440 unsigned i, j; 441 442 if(!setup->fs.jit_context.blend_color) 443 setup->fs.jit_context.blend_color = align_malloc(4 * 16, 16); 444 445 for (i = 0; i < 4; ++i) { 446 uint8_t c = float_to_ubyte(blend_color->color[i]); 447 for (j = 0; j < 16; ++j) 448 setup->fs.jit_context.blend_color[i*4 + j] = c; 449 } 450 451 setup->fs.jit_context_dirty = TRUE; 452} 453 454void 455lp_setup_set_sampler_textures( struct setup_context *setup, 456 unsigned num, struct pipe_texture **texture) 457{ 458 struct pipe_texture *dummy; 459 unsigned i; 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 /* FIXME: hold on to the reference */ 467 dummy = NULL; 468 pipe_texture_reference(&dummy, tex); 469 470 if(tex) { 471 struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex); 472 struct lp_jit_texture *jit_tex = &setup->fs.jit_context.textures[i]; 473 jit_tex->width = tex->width[0]; 474 jit_tex->height = tex->height[0]; 475 jit_tex->stride = lp_tex->stride[0]; 476 if(!lp_tex->dt) 477 jit_tex->data = lp_tex->data; 478 else 479 /* FIXME: map the rendertarget */ 480 assert(0); 481 } 482 } 483 484 setup->fs.jit_context_dirty = TRUE; 485} 486 487boolean 488lp_setup_is_texture_referenced( struct setup_context *setup, 489 const struct pipe_texture *texture ) 490{ 491 /* FIXME */ 492 return PIPE_UNREFERENCED; 493} 494 495 496/* Stubs for lines & points for now: 497 */ 498void 499lp_setup_point(struct setup_context *setup, 500 const float (*v0)[4]) 501{ 502 setup->point( setup, v0 ); 503} 504 505void 506lp_setup_line(struct setup_context *setup, 507 const float (*v0)[4], 508 const float (*v1)[4]) 509{ 510 setup->line( setup, v0, v1 ); 511} 512 513void 514lp_setup_tri(struct setup_context *setup, 515 const float (*v0)[4], 516 const float (*v1)[4], 517 const float (*v2)[4]) 518{ 519 setup->triangle( setup, v0, v1, v2 ); 520} 521 522 523void 524lp_setup_destroy( struct setup_context *setup ) 525{ 526 unsigned i, j; 527 528 reset_context( setup ); 529 530 for (i = 0; i < TILES_X; i++) 531 for (j = 0; j < TILES_Y; j++) 532 FREE(setup->tile[i][j].head); 533 534 lp_rast_destroy( setup->rast ); 535 FREE( setup ); 536} 537 538 539/** 540 * Create a new primitive tiling engine. Currently also creates a 541 * rasterizer to use with it. 542 */ 543struct setup_context * 544lp_setup_create( void ) 545{ 546 struct setup_context *setup = CALLOC_STRUCT(setup_context); 547 unsigned i, j; 548 549 setup->rast = lp_rast_create(); 550 if (!setup->rast) 551 goto fail; 552 553 for (i = 0; i < TILES_X; i++) 554 for (j = 0; j < TILES_Y; j++) 555 setup->tile[i][j].head = 556 setup->tile[i][j].tail = CALLOC_STRUCT(cmd_block); 557 558 return setup; 559 560fail: 561 FREE(setup); 562 return NULL; 563} 564 565