1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 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 VMWARE 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#include "util/u_framebuffer.h" 29#include "util/u_math.h" 30#include "util/u_memory.h" 31#include "util/u_inlines.h" 32#include "util/simple_list.h" 33#include "util/format/u_format.h" 34#include "lp_scene.h" 35#include "lp_fence.h" 36#include "lp_debug.h" 37#include "lp_context.h" 38#include "lp_state_fs.h" 39 40 41#define RESOURCE_REF_SZ 32 42 43/** List of resource references */ 44struct resource_ref { 45 struct pipe_resource *resource[RESOURCE_REF_SZ]; 46 int count; 47 struct resource_ref *next; 48}; 49 50#define SHADER_REF_SZ 32 51/** List of shader variant references */ 52struct shader_ref { 53 struct lp_fragment_shader_variant *variant[SHADER_REF_SZ]; 54 int count; 55 struct shader_ref *next; 56}; 57 58 59/** 60 * Create a new scene object. 61 * \param queue the queue to put newly rendered/emptied scenes into 62 */ 63struct lp_scene * 64lp_scene_create( struct pipe_context *pipe ) 65{ 66 struct lp_scene *scene = CALLOC_STRUCT(lp_scene); 67 if (!scene) 68 return NULL; 69 70 scene->pipe = pipe; 71 scene->data.head = &scene->data.first; 72 73 (void) mtx_init(&scene->mutex, mtx_plain); 74 75#ifdef DEBUG 76 /* Do some scene limit sanity checks here */ 77 { 78 size_t maxBins = TILES_X * TILES_Y; 79 size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins; 80 size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE; 81 /* We'll need at least one command block per bin. Make sure that's 82 * less than the max allowed scene size. 83 */ 84 assert(maxCommandBytes < LP_SCENE_MAX_SIZE); 85 /* We'll also need space for at least one other data block */ 86 assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE); 87 } 88#endif 89 90 return scene; 91} 92 93 94/** 95 * Free all data associated with the given scene, and the scene itself. 96 */ 97void 98lp_scene_destroy(struct lp_scene *scene) 99{ 100 lp_fence_reference(&scene->fence, NULL); 101 mtx_destroy(&scene->mutex); 102 assert(scene->data.head == &scene->data.first); 103 FREE(scene); 104} 105 106 107/** 108 * Check if the scene's bins are all empty. 109 * For debugging purposes. 110 */ 111boolean 112lp_scene_is_empty(struct lp_scene *scene ) 113{ 114 unsigned x, y; 115 116 for (y = 0; y < scene->tiles_y; y++) { 117 for (x = 0; x < scene->tiles_x; x++) { 118 const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y); 119 if (bin->head) { 120 return FALSE; 121 } 122 } 123 } 124 return TRUE; 125} 126 127 128/* Returns true if there has ever been a failed allocation attempt in 129 * this scene. Used in triangle/rectangle emit to avoid having to 130 * check success at each bin. 131 */ 132boolean 133lp_scene_is_oom(struct lp_scene *scene) 134{ 135 return scene->alloc_failed; 136} 137 138 139/* Remove all commands from a bin. Tries to reuse some of the memory 140 * allocated to the bin, however. 141 */ 142void 143lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y) 144{ 145 struct cmd_bin *bin = lp_scene_get_bin(scene, x, y); 146 147 bin->last_state = NULL; 148 bin->head = bin->tail; 149 if (bin->tail) { 150 bin->tail->next = NULL; 151 bin->tail->count = 0; 152 } 153} 154 155static void 156init_scene_texture(struct lp_scene_surface *ssurf, struct pipe_surface *psurf) 157{ 158 if (!psurf) { 159 ssurf->stride = 0; 160 ssurf->layer_stride = 0; 161 ssurf->sample_stride = 0; 162 ssurf->nr_samples = 0; 163 ssurf->map = NULL; 164 return; 165 } 166 167 if (llvmpipe_resource_is_texture(psurf->texture)) { 168 ssurf->stride = llvmpipe_resource_stride(psurf->texture, 169 psurf->u.tex.level); 170 ssurf->layer_stride = llvmpipe_layer_stride(psurf->texture, 171 psurf->u.tex.level); 172 ssurf->sample_stride = llvmpipe_sample_stride(psurf->texture); 173 174 ssurf->map = llvmpipe_resource_map(psurf->texture, 175 psurf->u.tex.level, 176 psurf->u.tex.first_layer, 177 LP_TEX_USAGE_READ_WRITE); 178 ssurf->format_bytes = util_format_get_blocksize(psurf->format); 179 ssurf->nr_samples = util_res_sample_count(psurf->texture); 180 } 181 else { 182 struct llvmpipe_resource *lpr = llvmpipe_resource(psurf->texture); 183 unsigned pixstride = util_format_get_blocksize(psurf->format); 184 ssurf->stride = psurf->texture->width0; 185 ssurf->layer_stride = 0; 186 ssurf->sample_stride = 0; 187 ssurf->nr_samples = 1; 188 ssurf->map = lpr->data; 189 ssurf->map += psurf->u.buf.first_element * pixstride; 190 ssurf->format_bytes = util_format_get_blocksize(psurf->format); 191 } 192} 193 194void 195lp_scene_begin_rasterization(struct lp_scene *scene) 196{ 197 const struct pipe_framebuffer_state *fb = &scene->fb; 198 int i; 199 200 //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__); 201 202 for (i = 0; i < scene->fb.nr_cbufs; i++) { 203 struct pipe_surface *cbuf = scene->fb.cbufs[i]; 204 init_scene_texture(&scene->cbufs[i], cbuf); 205 } 206 207 if (fb->zsbuf) { 208 struct pipe_surface *zsbuf = scene->fb.zsbuf; 209 init_scene_texture(&scene->zsbuf, zsbuf); 210 } 211} 212 213 214 215 216/** 217 * Free all the temporary data in a scene. 218 */ 219void 220lp_scene_end_rasterization(struct lp_scene *scene ) 221{ 222 int i; 223 224 /* Unmap color buffers */ 225 for (i = 0; i < scene->fb.nr_cbufs; i++) { 226 if (scene->cbufs[i].map) { 227 struct pipe_surface *cbuf = scene->fb.cbufs[i]; 228 if (llvmpipe_resource_is_texture(cbuf->texture)) { 229 llvmpipe_resource_unmap(cbuf->texture, 230 cbuf->u.tex.level, 231 cbuf->u.tex.first_layer); 232 } 233 scene->cbufs[i].map = NULL; 234 } 235 } 236 237 /* Unmap z/stencil buffer */ 238 if (scene->zsbuf.map) { 239 struct pipe_surface *zsbuf = scene->fb.zsbuf; 240 llvmpipe_resource_unmap(zsbuf->texture, 241 zsbuf->u.tex.level, 242 zsbuf->u.tex.first_layer); 243 scene->zsbuf.map = NULL; 244 } 245 246 /* Reset all command lists: 247 */ 248 memset(scene->tile, 0, sizeof scene->tile); 249 250 /* Decrement texture ref counts 251 */ 252 { 253 struct resource_ref *ref; 254 int i, j = 0; 255 256 for (ref = scene->resources; ref; ref = ref->next) { 257 for (i = 0; i < ref->count; i++) { 258 if (LP_DEBUG & DEBUG_SETUP) 259 debug_printf("resource %d: %p %dx%d sz %d\n", 260 j, 261 (void *) ref->resource[i], 262 ref->resource[i]->width0, 263 ref->resource[i]->height0, 264 llvmpipe_resource_size(ref->resource[i])); 265 j++; 266 llvmpipe_resource_unmap(ref->resource[i], 0, 0); 267 pipe_resource_reference(&ref->resource[i], NULL); 268 } 269 } 270 271 if (LP_DEBUG & DEBUG_SETUP) 272 debug_printf("scene %d resources, sz %d\n", 273 j, scene->resource_reference_size); 274 } 275 276 /* Decrement shader variant ref counts 277 */ 278 { 279 struct shader_ref *ref; 280 int i, j = 0; 281 282 for (ref = scene->frag_shaders; ref; ref = ref->next) { 283 for (i = 0; i < ref->count; i++) { 284 if (LP_DEBUG & DEBUG_SETUP) 285 debug_printf("shader %d: %p\n", j, (void *) ref->variant[i]); 286 j++; 287 lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[i], NULL); 288 } 289 } 290 } 291 292 /* Free all scene data blocks: 293 */ 294 { 295 struct data_block_list *list = &scene->data; 296 struct data_block *block, *tmp; 297 298 for (block = list->head; block; block = tmp) { 299 tmp = block->next; 300 if (block != &list->first) 301 FREE(block); 302 } 303 304 list->head = &list->first; 305 list->head->next = NULL; 306 } 307 308 lp_fence_reference(&scene->fence, NULL); 309 310 scene->resources = NULL; 311 scene->frag_shaders = NULL; 312 scene->scene_size = 0; 313 scene->resource_reference_size = 0; 314 315 scene->alloc_failed = FALSE; 316 317 util_unreference_framebuffer_state( &scene->fb ); 318} 319 320 321 322 323 324 325struct cmd_block * 326lp_scene_new_cmd_block( struct lp_scene *scene, 327 struct cmd_bin *bin ) 328{ 329 struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block)); 330 if (block) { 331 if (bin->tail) { 332 bin->tail->next = block; 333 bin->tail = block; 334 } 335 else { 336 bin->head = block; 337 bin->tail = block; 338 } 339 //memset(block, 0, sizeof *block); 340 block->next = NULL; 341 block->count = 0; 342 } 343 return block; 344} 345 346 347struct data_block * 348lp_scene_new_data_block( struct lp_scene *scene ) 349{ 350 if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) { 351 if (0) debug_printf("%s: failed\n", __FUNCTION__); 352 scene->alloc_failed = TRUE; 353 return NULL; 354 } 355 else { 356 struct data_block *block = MALLOC_STRUCT(data_block); 357 if (!block) 358 return NULL; 359 360 scene->scene_size += sizeof *block; 361 362 block->used = 0; 363 block->next = scene->data.head; 364 scene->data.head = block; 365 366 return block; 367 } 368} 369 370 371/** 372 * Return number of bytes used for all bin data within a scene. 373 * This does not include resources (textures) referenced by the scene. 374 */ 375static unsigned 376lp_scene_data_size( const struct lp_scene *scene ) 377{ 378 unsigned size = 0; 379 const struct data_block *block; 380 for (block = scene->data.head; block; block = block->next) { 381 size += block->used; 382 } 383 return size; 384} 385 386 387 388/** 389 * Add a reference to a resource by the scene. 390 */ 391boolean 392lp_scene_add_resource_reference(struct lp_scene *scene, 393 struct pipe_resource *resource, 394 boolean initializing_scene) 395{ 396 struct resource_ref *ref, **last = &scene->resources; 397 int i; 398 399 /* Look at existing resource blocks: 400 */ 401 for (ref = scene->resources; ref; ref = ref->next) { 402 last = &ref->next; 403 404 /* Search for this resource: 405 */ 406 for (i = 0; i < ref->count; i++) 407 if (ref->resource[i] == resource) 408 return TRUE; 409 410 if (ref->count < RESOURCE_REF_SZ) { 411 /* If the block is half-empty, then append the reference here. 412 */ 413 break; 414 } 415 } 416 417 /* Create a new block if no half-empty block was found. 418 */ 419 if (!ref) { 420 assert(*last == NULL); 421 *last = lp_scene_alloc(scene, sizeof *ref); 422 if (*last == NULL) 423 return FALSE; 424 425 ref = *last; 426 memset(ref, 0, sizeof *ref); 427 } 428 429 /* Map resource again to increment the map count. We likely use the 430 * already-mapped pointer in a texture of the jit context, and that pointer 431 * needs to stay mapped during rasterization. This map is unmap'ed when 432 * finalizing scene rasterization. */ 433 llvmpipe_resource_map(resource, 0, 0, LP_TEX_USAGE_READ); 434 435 /* Append the reference to the reference block. 436 */ 437 pipe_resource_reference(&ref->resource[ref->count++], resource); 438 scene->resource_reference_size += llvmpipe_resource_size(resource); 439 440 /* Heuristic to advise scene flushes. This isn't helpful in the 441 * initial setup of the scene, but after that point flush on the 442 * next resource added which exceeds 64MB in referenced texture 443 * data. 444 */ 445 if (!initializing_scene && 446 scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE) 447 return FALSE; 448 449 return TRUE; 450} 451 452 453/** 454 * Add a reference to a fragment shader variant 455 */ 456boolean 457lp_scene_add_frag_shader_reference(struct lp_scene *scene, 458 struct lp_fragment_shader_variant *variant) 459{ 460 struct shader_ref *ref, **last = &scene->frag_shaders; 461 int i; 462 463 /* Look at existing resource blocks: 464 */ 465 for (ref = scene->frag_shaders; ref; ref = ref->next) { 466 last = &ref->next; 467 468 /* Search for this resource: 469 */ 470 for (i = 0; i < ref->count; i++) 471 if (ref->variant[i] == variant) 472 return TRUE; 473 474 if (ref->count < SHADER_REF_SZ) { 475 /* If the block is half-empty, then append the reference here. 476 */ 477 break; 478 } 479 } 480 481 /* Create a new block if no half-empty block was found. 482 */ 483 if (!ref) { 484 assert(*last == NULL); 485 *last = lp_scene_alloc(scene, sizeof *ref); 486 if (*last == NULL) 487 return FALSE; 488 489 ref = *last; 490 memset(ref, 0, sizeof *ref); 491 } 492 493 /* Append the reference to the reference block. 494 */ 495 lp_fs_variant_reference(llvmpipe_context(scene->pipe), &ref->variant[ref->count++], variant); 496 497 return TRUE; 498} 499 500/** 501 * Does this scene have a reference to the given resource? 502 */ 503boolean 504lp_scene_is_resource_referenced(const struct lp_scene *scene, 505 const struct pipe_resource *resource) 506{ 507 const struct resource_ref *ref; 508 int i; 509 510 for (ref = scene->resources; ref; ref = ref->next) { 511 for (i = 0; i < ref->count; i++) 512 if (ref->resource[i] == resource) 513 return TRUE; 514 } 515 516 return FALSE; 517} 518 519 520 521 522/** advance curr_x,y to the next bin */ 523static boolean 524next_bin(struct lp_scene *scene) 525{ 526 scene->curr_x++; 527 if (scene->curr_x >= scene->tiles_x) { 528 scene->curr_x = 0; 529 scene->curr_y++; 530 } 531 if (scene->curr_y >= scene->tiles_y) { 532 /* no more bins */ 533 return FALSE; 534 } 535 return TRUE; 536} 537 538 539void 540lp_scene_bin_iter_begin( struct lp_scene *scene ) 541{ 542 scene->curr_x = scene->curr_y = -1; 543} 544 545 546/** 547 * Return pointer to next bin to be rendered. 548 * The lp_scene::curr_x and ::curr_y fields will be advanced. 549 * Multiple rendering threads will call this function to get a chunk 550 * of work (a bin) to work on. 551 */ 552struct cmd_bin * 553lp_scene_bin_iter_next( struct lp_scene *scene , int *x, int *y) 554{ 555 struct cmd_bin *bin = NULL; 556 557 mtx_lock(&scene->mutex); 558 559 if (scene->curr_x < 0) { 560 /* first bin */ 561 scene->curr_x = 0; 562 scene->curr_y = 0; 563 } 564 else if (!next_bin(scene)) { 565 /* no more bins left */ 566 goto end; 567 } 568 569 bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y); 570 *x = scene->curr_x; 571 *y = scene->curr_y; 572 573end: 574 /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/ 575 mtx_unlock(&scene->mutex); 576 return bin; 577} 578 579 580void lp_scene_begin_binning(struct lp_scene *scene, 581 struct pipe_framebuffer_state *fb) 582{ 583 int i; 584 unsigned max_layer = ~0; 585 586 assert(lp_scene_is_empty(scene)); 587 588 util_copy_framebuffer_state(&scene->fb, fb); 589 590 scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE; 591 scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE; 592 assert(scene->tiles_x <= TILES_X); 593 assert(scene->tiles_y <= TILES_Y); 594 595 /* 596 * Determine how many layers the fb has (used for clamping layer value). 597 * OpenGL (but not d3d10) permits different amount of layers per rt, however 598 * results are undefined if layer exceeds the amount of layers of ANY 599 * attachment hence don't need separate per cbuf and zsbuf max. 600 */ 601 for (i = 0; i < scene->fb.nr_cbufs; i++) { 602 struct pipe_surface *cbuf = scene->fb.cbufs[i]; 603 if (cbuf) { 604 if (llvmpipe_resource_is_texture(cbuf->texture)) { 605 max_layer = MIN2(max_layer, 606 cbuf->u.tex.last_layer - cbuf->u.tex.first_layer); 607 } 608 else { 609 max_layer = 0; 610 } 611 } 612 } 613 if (fb->zsbuf) { 614 struct pipe_surface *zsbuf = scene->fb.zsbuf; 615 max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer); 616 } 617 scene->fb_max_layer = max_layer; 618 scene->fb_max_samples = util_framebuffer_get_num_samples(fb); 619 if (scene->fb_max_samples == 4) { 620 for (unsigned i = 0; i < 4; i++) { 621 scene->fixed_sample_pos[i][0] = util_iround(lp_sample_pos_4x[i][0] * FIXED_ONE); 622 scene->fixed_sample_pos[i][1] = util_iround(lp_sample_pos_4x[i][1] * FIXED_ONE); 623 } 624 } 625} 626 627 628void lp_scene_end_binning( struct lp_scene *scene ) 629{ 630 if (LP_DEBUG & DEBUG_SCENE) { 631 debug_printf("rasterize scene:\n"); 632 debug_printf(" scene_size: %u\n", 633 scene->scene_size); 634 debug_printf(" data size: %u\n", 635 lp_scene_data_size(scene)); 636 637 if (0) 638 lp_debug_bins( scene ); 639 } 640} 641