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