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