lp_scene.c revision 0639765b2850739af1678f10fc0c5706d5827776
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_math.h" 29#include "util/u_memory.h" 30#include "util/u_inlines.h" 31#include "util/u_simple_list.h" 32#include "util/u_surface.h" 33#include "lp_scene.h" 34#include "lp_scene_queue.h" 35#include "lp_debug.h" 36 37 38struct lp_scene * 39lp_scene_create( struct pipe_context *pipe, 40 struct lp_scene_queue *queue ) 41{ 42 unsigned i, j; 43 struct lp_scene *scene = CALLOC_STRUCT(lp_scene); 44 if (!scene) 45 return NULL; 46 47 scene->pipe = pipe; 48 scene->empty_queue = queue; 49 50 for (i = 0; i < TILES_X; i++) { 51 for (j = 0; j < TILES_Y; j++) { 52 struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); 53 bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block); 54 } 55 } 56 57 scene->data.head = 58 scene->data.tail = CALLOC_STRUCT(data_block); 59 60 make_empty_list(&scene->textures); 61 62 pipe_mutex_init(scene->mutex); 63 64 return scene; 65} 66 67 68/** 69 * Free all data associated with the given scene, and free(scene). 70 */ 71void 72lp_scene_destroy(struct lp_scene *scene) 73{ 74 unsigned i, j; 75 76 lp_scene_reset(scene); 77 78 for (i = 0; i < TILES_X; i++) 79 for (j = 0; j < TILES_Y; j++) { 80 struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); 81 assert(bin->commands.head == bin->commands.tail); 82 FREE(bin->commands.head); 83 bin->commands.head = NULL; 84 bin->commands.tail = NULL; 85 } 86 87 FREE(scene->data.head); 88 scene->data.head = NULL; 89 90 pipe_mutex_destroy(scene->mutex); 91 92 FREE(scene); 93} 94 95 96/** 97 * Check if the scene's bins are all empty. 98 * For debugging purposes. 99 */ 100boolean 101lp_scene_is_empty(struct lp_scene *scene ) 102{ 103 unsigned x, y; 104 105 for (y = 0; y < TILES_Y; y++) { 106 for (x = 0; x < TILES_X; x++) { 107 const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y); 108 const struct cmd_block_list *list = &bin->commands; 109 if (list->head != list->tail || list->head->count > 0) { 110 return FALSE; 111 } 112 } 113 } 114 return TRUE; 115} 116 117 118/* Free data for one particular bin. May be called from the 119 * rasterizer thread(s). 120 */ 121void 122lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y) 123{ 124 struct cmd_bin *bin = lp_scene_get_bin(scene, x, y); 125 struct cmd_block_list *list = &bin->commands; 126 struct cmd_block *block; 127 struct cmd_block *tmp; 128 129 assert(x < TILES_X); 130 assert(y < TILES_Y); 131 132 for (block = list->head; block != list->tail; block = tmp) { 133 tmp = block->next; 134 FREE(block); 135 } 136 137 assert(list->tail->next == NULL); 138 list->head = list->tail; 139 list->head->count = 0; 140} 141 142 143/** 144 * Free all the temporary data in a scene. May be called from the 145 * rasterizer thread(s). 146 */ 147void 148lp_scene_reset(struct lp_scene *scene ) 149{ 150 unsigned i, j; 151 152 /* Free all but last binner command lists: 153 */ 154 for (i = 0; i < scene->tiles_x; i++) { 155 for (j = 0; j < scene->tiles_y; j++) { 156 lp_scene_bin_reset(scene, i, j); 157 } 158 } 159 160 assert(lp_scene_is_empty(scene)); 161 162 /* Free all but last binned data block: 163 */ 164 { 165 struct data_block_list *list = &scene->data; 166 struct data_block *block, *tmp; 167 168 for (block = list->head; block != list->tail; block = tmp) { 169 tmp = block->next; 170 FREE(block); 171 } 172 173 assert(list->tail->next == NULL); 174 list->head = list->tail; 175 list->head->used = 0; 176 } 177 178 /* Release texture refs 179 */ 180 { 181 struct texture_ref *ref, *next, *ref_list = &scene->textures; 182 for (ref = ref_list->next; ref != ref_list; ref = next) { 183 next = next_elem(ref); 184 pipe_resource_reference(&ref->texture, NULL); 185 FREE(ref); 186 } 187 make_empty_list(ref_list); 188 } 189 190 scene->has_color_clear = FALSE; 191 scene->has_depth_clear = FALSE; 192} 193 194 195 196 197 198 199void 200lp_bin_new_cmd_block( struct cmd_block_list *list ) 201{ 202 struct cmd_block *block = MALLOC_STRUCT(cmd_block); 203 list->tail->next = block; 204 list->tail = block; 205 block->next = NULL; 206 block->count = 0; 207} 208 209 210void 211lp_bin_new_data_block( struct data_block_list *list ) 212{ 213 struct data_block *block = MALLOC_STRUCT(data_block); 214 list->tail->next = block; 215 list->tail = block; 216 block->next = NULL; 217 block->used = 0; 218} 219 220 221/** Return number of bytes used for all bin data within a scene */ 222unsigned 223lp_scene_data_size( const struct lp_scene *scene ) 224{ 225 unsigned size = 0; 226 const struct data_block *block; 227 for (block = scene->data.head; block; block = block->next) { 228 size += block->used; 229 } 230 return size; 231} 232 233 234/** Return number of bytes used for a single bin */ 235unsigned 236lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y ) 237{ 238 struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y); 239 const struct cmd_block *cmd; 240 unsigned size = 0; 241 for (cmd = bin->commands.head; cmd; cmd = cmd->next) { 242 size += (cmd->count * 243 (sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg))); 244 } 245 return size; 246} 247 248 249/** 250 * Add a reference to a texture by the scene. 251 */ 252void 253lp_scene_texture_reference( struct lp_scene *scene, 254 struct pipe_resource *texture ) 255{ 256 struct texture_ref *ref = CALLOC_STRUCT(texture_ref); 257 if (ref) { 258 struct texture_ref *ref_list = &scene->textures; 259 pipe_resource_reference(&ref->texture, texture); 260 insert_at_tail(ref_list, ref); 261 } 262} 263 264 265/** 266 * Does this scene have a reference to the given texture? 267 */ 268boolean 269lp_scene_is_resource_referenced( const struct lp_scene *scene, 270 const struct pipe_resource *texture ) 271{ 272 const struct texture_ref *ref_list = &scene->textures; 273 const struct texture_ref *ref; 274 foreach (ref, ref_list) { 275 if (ref->texture == texture) 276 return TRUE; 277 } 278 return FALSE; 279} 280 281 282/** 283 * Return last command in the bin 284 */ 285static lp_rast_cmd 286lp_get_last_command( const struct cmd_bin *bin ) 287{ 288 const struct cmd_block *tail = bin->commands.tail; 289 const unsigned i = tail->count; 290 if (i > 0) 291 return tail->cmd[i - 1]; 292 else 293 return NULL; 294} 295 296 297/** 298 * Replace the arg of the last command in the bin. 299 */ 300static void 301lp_replace_last_command_arg( struct cmd_bin *bin, 302 const union lp_rast_cmd_arg arg ) 303{ 304 struct cmd_block *tail = bin->commands.tail; 305 const unsigned i = tail->count; 306 assert(i > 0); 307 tail->arg[i - 1] = arg; 308} 309 310 311 312/** 313 * Put a state-change command into all bins. 314 * If we find that the last command in a bin was also a state-change 315 * command, we can simply replace that one with the new one. 316 */ 317void 318lp_scene_bin_state_command( struct lp_scene *scene, 319 lp_rast_cmd cmd, 320 const union lp_rast_cmd_arg arg ) 321{ 322 unsigned i, j; 323 for (i = 0; i < scene->tiles_x; i++) { 324 for (j = 0; j < scene->tiles_y; j++) { 325 struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); 326 lp_rast_cmd last_cmd = lp_get_last_command(bin); 327 if (last_cmd == cmd) { 328 lp_replace_last_command_arg(bin, arg); 329 } 330 else { 331 lp_scene_bin_command( scene, i, j, cmd, arg ); 332 } 333 } 334 } 335} 336 337 338/** advance curr_x,y to the next bin */ 339static boolean 340next_bin(struct lp_scene *scene) 341{ 342 scene->curr_x++; 343 if (scene->curr_x >= scene->tiles_x) { 344 scene->curr_x = 0; 345 scene->curr_y++; 346 } 347 if (scene->curr_y >= scene->tiles_y) { 348 /* no more bins */ 349 return FALSE; 350 } 351 return TRUE; 352} 353 354 355void 356lp_scene_bin_iter_begin( struct lp_scene *scene ) 357{ 358 scene->curr_x = scene->curr_y = -1; 359} 360 361 362/** 363 * Return pointer to next bin to be rendered. 364 * The lp_scene::curr_x and ::curr_y fields will be advanced. 365 * Multiple rendering threads will call this function to get a chunk 366 * of work (a bin) to work on. 367 */ 368struct cmd_bin * 369lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y ) 370{ 371 struct cmd_bin *bin = NULL; 372 373 pipe_mutex_lock(scene->mutex); 374 375 if (scene->curr_x < 0) { 376 /* first bin */ 377 scene->curr_x = 0; 378 scene->curr_y = 0; 379 } 380 else if (!next_bin(scene)) { 381 /* no more bins left */ 382 goto end; 383 } 384 385 bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y); 386 *bin_x = scene->curr_x; 387 *bin_y = scene->curr_y; 388 389end: 390 /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/ 391 pipe_mutex_unlock(scene->mutex); 392 return bin; 393} 394 395 396 397/** 398 * Prepare this scene for the rasterizer. 399 * Map the framebuffer surfaces. Initialize the 'rast' state. 400 */ 401static boolean 402lp_scene_map_buffers( struct lp_scene *scene ) 403{ 404 LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__); 405 406 /* XXX framebuffer surfaces are no longer mapped here */ 407 /* XXX move all map/unmap stuff into rast module... */ 408 409 return TRUE; 410} 411 412 413 414/** 415 * Called after rasterizer as finished rasterizing a scene. 416 * 417 * We want to call this from the pipe_context's current thread to 418 * avoid having to have mutexes on the transfer functions. 419 */ 420static void 421lp_scene_unmap_buffers( struct lp_scene *scene ) 422{ 423#if 0 424 unsigned i; 425 426 for (i = 0; i < scene->fb.nr_cbufs; i++) { 427 if (scene->cbuf_map[i]) { 428 struct pipe_surface *cbuf = scene->fb.cbufs[i]; 429 llvmpipe_resource_unmap(cbuf->texture, 430 cbuf->face, 431 cbuf->level, 432 cbuf->zslice); 433 scene->cbuf_map[i] = NULL; 434 } 435 } 436 437 if (scene->zsbuf_map) { 438 struct pipe_surface *zsbuf = scene->fb.zsbuf; 439 llvmpipe_resource_unmap(zsbuf->texture, 440 zsbuf->face, 441 zsbuf->level, 442 zsbuf->zslice); 443 scene->zsbuf_map = NULL; 444 } 445#endif 446 447 util_unreference_framebuffer_state( &scene->fb ); 448} 449 450 451void lp_scene_begin_binning( struct lp_scene *scene, 452 struct pipe_framebuffer_state *fb ) 453{ 454 assert(lp_scene_is_empty(scene)); 455 456 util_copy_framebuffer_state(&scene->fb, fb); 457 458 scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE; 459 scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE; 460 461 assert(scene->tiles_x <= TILES_X); 462 assert(scene->tiles_y <= TILES_Y); 463} 464 465 466void lp_scene_rasterize( struct lp_scene *scene, 467 struct lp_rasterizer *rast, 468 boolean write_depth ) 469{ 470 if (0) { 471 unsigned x, y; 472 debug_printf("rasterize scene:\n"); 473 debug_printf(" data size: %u\n", lp_scene_data_size(scene)); 474 for (y = 0; y < scene->tiles_y; y++) { 475 for (x = 0; x < scene->tiles_x; x++) { 476 debug_printf(" bin %u, %u size: %u\n", x, y, 477 lp_scene_bin_size(scene, x, y)); 478 } 479 } 480 } 481 482 scene->write_depth = (scene->fb.zsbuf != NULL && 483 write_depth); 484 485 lp_scene_map_buffers( scene ); 486 487 /* Enqueue the scene for rasterization, then immediately wait for 488 * it to finish. 489 */ 490 lp_rast_queue_scene( rast, scene ); 491 492 /* Currently just wait for the rasterizer to finish. Some 493 * threading interactions need to be worked out, particularly once 494 * transfers become per-context: 495 */ 496 lp_rast_finish( rast ); 497 lp_scene_unmap_buffers( scene ); 498 lp_scene_enqueue( scene->empty_queue, scene ); 499} 500