X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fllvmpipe%2Flp_scene.c;h=ed998246fb9364e98a6fdb9f09a01d0399b6af85;hb=437ab1d6df7282770ee869180446db36c2dbdfa8;hp=cba0e2129851f08781c4523492ecccd997de126f;hpb=c8aaa24f2da4e4da3d726e0a58459c7d9cb64b93;p=mesa.git diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index cba0e212985..ed998246fb9 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -25,51 +25,63 @@ * **************************************************************************/ +#include "util/u_framebuffer.h" #include "util/u_math.h" #include "util/u_memory.h" #include "util/u_inlines.h" #include "util/u_simple_list.h" +#include "util/u_format.h" #include "lp_scene.h" +#include "lp_fence.h" +#include "lp_debug.h" +#define RESOURCE_REF_SZ 32 + +/** List of resource references */ +struct resource_ref { + struct pipe_resource *resource[RESOURCE_REF_SZ]; + int count; + struct resource_ref *next; +}; + + +/** + * Create a new scene object. + * \param queue the queue to put newly rendered/emptied scenes into + */ struct lp_scene * -lp_scene_create(void) +lp_scene_create( struct pipe_context *pipe ) { struct lp_scene *scene = CALLOC_STRUCT(lp_scene); - if (scene) - lp_scene_init(scene); + if (!scene) + return NULL; + + scene->pipe = pipe; + + scene->data.head = + CALLOC_STRUCT(data_block); + + pipe_mutex_init(scene->mutex); + return scene; } +/** + * Free all data associated with the given scene, and the scene itself. + */ void lp_scene_destroy(struct lp_scene *scene) { - lp_scene_reset(scene); - lp_scene_free_bin_data(scene); + lp_fence_reference(&scene->fence, NULL); + pipe_mutex_destroy(scene->mutex); + assert(scene->data.head->next == NULL); + FREE(scene->data.head); FREE(scene); } -void -lp_scene_init(struct lp_scene *scene) -{ - unsigned i, j; - for (i = 0; i < TILES_X; i++) - for (j = 0; j < TILES_Y; j++) { - struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); - bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block); - } - - scene->data.head = - scene->data.tail = CALLOC_STRUCT(data_block); - - make_empty_list(&scene->textures); - - pipe_mutex_init(scene->mutex); -} - - /** * Check if the scene's bins are all empty. * For debugging purposes. @@ -82,8 +94,7 @@ lp_scene_is_empty(struct lp_scene *scene ) for (y = 0; y < TILES_Y; y++) { for (x = 0; x < TILES_X; x++) { const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y); - const struct cmd_block_list *list = &bin->commands; - if (list->head != list->tail || list->head->count > 0) { + if (bin->head) { return FALSE; } } @@ -92,136 +103,225 @@ lp_scene_is_empty(struct lp_scene *scene ) } +/* Returns true if there has ever been a failed allocation attempt in + * this scene. Used in triangle emit to avoid having to check success + * at each bin. + */ +boolean +lp_scene_is_oom(struct lp_scene *scene) +{ + return scene->alloc_failed; +} + + +/* Remove all commands from a bin. Tries to reuse some of the memory + * allocated to the bin, however. + */ void lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y) { struct cmd_bin *bin = lp_scene_get_bin(scene, x, y); - struct cmd_block_list *list = &bin->commands; - struct cmd_block *block; - struct cmd_block *tmp; - assert(x < TILES_X); - assert(y < TILES_Y); + bin->last_state = NULL; + bin->head = bin->tail; + if (bin->tail) { + bin->tail->next = NULL; + bin->tail->count = 0; + } +} + - for (block = list->head; block != list->tail; block = tmp) { - tmp = block->next; - FREE(block); +void +lp_scene_begin_rasterization(struct lp_scene *scene) +{ + const struct pipe_framebuffer_state *fb = &scene->fb; + int i; + + //LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__); + + for (i = 0; i < scene->fb.nr_cbufs; i++) { + struct pipe_surface *cbuf = scene->fb.cbufs[i]; + assert(cbuf->u.tex.first_layer == cbuf->u.tex.last_layer); + scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture, + cbuf->u.tex.level); + + scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture, + cbuf->u.tex.level, + cbuf->u.tex.first_layer, + LP_TEX_USAGE_READ_WRITE, + LP_TEX_LAYOUT_LINEAR); } - assert(list->tail->next == NULL); - list->head = list->tail; - list->head->count = 0; + if (fb->zsbuf) { + struct pipe_surface *zsbuf = scene->fb.zsbuf; + assert(zsbuf->u.tex.first_layer == zsbuf->u.tex.last_layer); + scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->u.tex.level); + scene->zsbuf.blocksize = + util_format_get_blocksize(zsbuf->texture->format); + + scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture, + zsbuf->u.tex.level, + zsbuf->u.tex.first_layer, + LP_TEX_USAGE_READ_WRITE, + LP_TEX_LAYOUT_NONE); + } } + + /** - * Set scene to empty state. + * Free all the temporary data in a scene. */ void -lp_scene_reset(struct lp_scene *scene ) +lp_scene_end_rasterization(struct lp_scene *scene ) { - unsigned i, j; + int i, j; + + /* Unmap color buffers */ + for (i = 0; i < scene->fb.nr_cbufs; i++) { + if (scene->cbufs[i].map) { + struct pipe_surface *cbuf = scene->fb.cbufs[i]; + llvmpipe_resource_unmap(cbuf->texture, + cbuf->u.tex.level, + cbuf->u.tex.first_layer); + scene->cbufs[i].map = NULL; + } + } + + /* Unmap z/stencil buffer */ + if (scene->zsbuf.map) { + struct pipe_surface *zsbuf = scene->fb.zsbuf; + llvmpipe_resource_unmap(zsbuf->texture, + zsbuf->u.tex.level, + zsbuf->u.tex.first_layer); + scene->zsbuf.map = NULL; + } - /* Free all but last binner command lists: + /* Reset all command lists: */ for (i = 0; i < scene->tiles_x; i++) { for (j = 0; j < scene->tiles_y; j++) { - lp_scene_bin_reset(scene, i, j); + struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); + bin->head = NULL; + bin->tail = NULL; + bin->last_state = NULL; } } + /* If there are any bins which weren't cleared by the loop above, + * they will be caught (on debug builds at least) by this assert: + */ assert(lp_scene_is_empty(scene)); - /* Free all but last binned data block: + /* Decrement texture ref counts */ { - struct data_block_list *list = &scene->data; - struct data_block *block, *tmp; - - for (block = list->head; block != list->tail; block = tmp) { - tmp = block->next; - FREE(block); + struct resource_ref *ref; + int i, j = 0; + + for (ref = scene->resources; ref; ref = ref->next) { + for (i = 0; i < ref->count; i++) { + if (LP_DEBUG & DEBUG_SETUP) + debug_printf("resource %d: %p %dx%d sz %d\n", + j, + (void *) ref->resource[i], + ref->resource[i]->width0, + ref->resource[i]->height0, + llvmpipe_resource_size(ref->resource[i])); + j++; + pipe_resource_reference(&ref->resource[i], NULL); + } } - - assert(list->tail->next == NULL); - list->head = list->tail; - list->head->used = 0; + + if (LP_DEBUG & DEBUG_SETUP) + debug_printf("scene %d resources, sz %d\n", + j, scene->resource_reference_size); } - /* Release texture refs + /* Free all scene data blocks: */ { - struct texture_ref *ref, *next, *ref_list = &scene->textures; - for (ref = ref_list->next; ref != ref_list; ref = next) { - next = next_elem(ref); - pipe_texture_reference(&ref->texture, NULL); - FREE(ref); + struct data_block_list *list = &scene->data; + struct data_block *block, *tmp; + + for (block = list->head->next; block; block = tmp) { + tmp = block->next; + FREE(block); } - make_empty_list(ref_list); - } -} + list->head->next = NULL; + list->head->used = 0; + } -/** - * Free all data associated with the given bin, but don't free(scene). - */ -void -lp_scene_free_bin_data(struct lp_scene *scene) -{ - unsigned i, j; + lp_fence_reference(&scene->fence, NULL); - for (i = 0; i < TILES_X; i++) - for (j = 0; j < TILES_Y; j++) { - struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); - /* lp_reset_scene() should have been already called */ - assert(bin->commands.head == bin->commands.tail); - FREE(bin->commands.head); - bin->commands.head = NULL; - bin->commands.tail = NULL; - } + scene->resources = NULL; + scene->scene_size = 0; + scene->resource_reference_size = 0; - FREE(scene->data.head); - scene->data.head = NULL; + scene->has_depthstencil_clear = FALSE; + scene->alloc_failed = FALSE; - pipe_mutex_destroy(scene->mutex); + util_unreference_framebuffer_state( &scene->fb ); } -void -lp_scene_set_framebuffer_size( struct lp_scene *scene, - unsigned width, unsigned height ) -{ - assert(lp_scene_is_empty(scene)); - scene->tiles_x = align(width, TILE_SIZE) / TILE_SIZE; - scene->tiles_y = align(height, TILE_SIZE) / TILE_SIZE; -} -void -lp_bin_new_cmd_block( struct cmd_block_list *list ) + +struct cmd_block * +lp_scene_new_cmd_block( struct lp_scene *scene, + struct cmd_bin *bin ) { - struct cmd_block *block = MALLOC_STRUCT(cmd_block); - list->tail->next = block; - list->tail = block; - block->next = NULL; - block->count = 0; + struct cmd_block *block = lp_scene_alloc(scene, sizeof(struct cmd_block)); + if (block) { + if (bin->tail) { + bin->tail->next = block; + bin->tail = block; + } + else { + bin->head = block; + bin->tail = block; + } + //memset(block, 0, sizeof *block); + block->next = NULL; + block->count = 0; + } + return block; } -void -lp_bin_new_data_block( struct data_block_list *list ) +struct data_block * +lp_scene_new_data_block( struct lp_scene *scene ) { - struct data_block *block = MALLOC_STRUCT(data_block); - list->tail->next = block; - list->tail = block; - block->next = NULL; - block->used = 0; + if (scene->scene_size + DATA_BLOCK_SIZE > LP_SCENE_MAX_SIZE) { + if (0) debug_printf("%s: failed\n", __FUNCTION__); + scene->alloc_failed = TRUE; + return NULL; + } + else { + struct data_block *block = MALLOC_STRUCT(data_block); + if (block == NULL) + return NULL; + + scene->scene_size += sizeof *block; + + block->used = 0; + block->next = scene->data.head; + scene->data.head = block; + + return block; + } } -/** Return number of bytes used for all bin data within a scene */ -unsigned +/** + * Return number of bytes used for all bin data within a scene. + * This does not include resources (textures) referenced by the scene. + */ +static unsigned lp_scene_data_size( const struct lp_scene *scene ) { unsigned size = 0; @@ -233,110 +333,88 @@ lp_scene_data_size( const struct lp_scene *scene ) } -/** Return number of bytes used for a single bin */ -unsigned -lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y ) -{ - struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y); - const struct cmd_block *cmd; - unsigned size = 0; - for (cmd = bin->commands.head; cmd; cmd = cmd->next) { - size += (cmd->count * - (sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg))); - } - return size; -} - /** - * Add a reference to a texture by the scene. - */ -void -lp_scene_texture_reference( struct lp_scene *scene, - struct pipe_texture *texture ) -{ - struct texture_ref *ref = CALLOC_STRUCT(texture_ref); - if (ref) { - struct texture_ref *ref_list = &scene->textures; - pipe_texture_reference(&ref->texture, texture); - insert_at_tail(ref_list, ref); - } -} - - -/** - * Does this scene have a reference to the given texture? + * Add a reference to a resource by the scene. */ boolean -lp_scene_is_texture_referenced( const struct lp_scene *scene, - const struct pipe_texture *texture ) +lp_scene_add_resource_reference(struct lp_scene *scene, + struct pipe_resource *resource, + boolean initializing_scene) { - const struct texture_ref *ref_list = &scene->textures; - const struct texture_ref *ref; - foreach (ref, ref_list) { - if (ref->texture == texture) - return TRUE; + struct resource_ref *ref, **last = &scene->resources; + int i; + + /* Look at existing resource blocks: + */ + for (ref = scene->resources; ref; ref = ref->next) { + last = &ref->next; + + /* Search for this resource: + */ + for (i = 0; i < ref->count; i++) + if (ref->resource[i] == resource) + return TRUE; + + if (ref->count < RESOURCE_REF_SZ) { + /* If the block is half-empty, then append the reference here. + */ + break; + } } - return FALSE; -} + /* Create a new block if no half-empty block was found. + */ + if (!ref) { + assert(*last == NULL); + *last = lp_scene_alloc(scene, sizeof *ref); + if (*last == NULL) + return FALSE; + + ref = *last; + memset(ref, 0, sizeof *ref); + } -/** - * Return last command in the bin - */ -static lp_rast_cmd -lp_get_last_command( const struct cmd_bin *bin ) -{ - const struct cmd_block *tail = bin->commands.tail; - const unsigned i = tail->count; - if (i > 0) - return tail->cmd[i - 1]; - else - return NULL; -} + /* Append the reference to the reference block. + */ + pipe_resource_reference(&ref->resource[ref->count++], resource); + scene->resource_reference_size += llvmpipe_resource_size(resource); + /* Heuristic to advise scene flushes. This isn't helpful in the + * initial setup of the scene, but after that point flush on the + * next resource added which exceeds 64MB in referenced texture + * data. + */ + if (!initializing_scene && + scene->resource_reference_size >= LP_SCENE_MAX_RESOURCE_SIZE) + return FALSE; -/** - * Replace the arg of the last command in the bin. - */ -static void -lp_replace_last_command_arg( struct cmd_bin *bin, - const union lp_rast_cmd_arg arg ) -{ - struct cmd_block *tail = bin->commands.tail; - const unsigned i = tail->count; - assert(i > 0); - tail->arg[i - 1] = arg; + return TRUE; } - /** - * Put a state-change command into all bins. - * If we find that the last command in a bin was also a state-change - * command, we can simply replace that one with the new one. + * Does this scene have a reference to the given resource? */ -void -lp_scene_bin_state_command( struct lp_scene *scene, - lp_rast_cmd cmd, - const union lp_rast_cmd_arg arg ) +boolean +lp_scene_is_resource_referenced(const struct lp_scene *scene, + const struct pipe_resource *resource) { - unsigned i, j; - for (i = 0; i < scene->tiles_x; i++) { - for (j = 0; j < scene->tiles_y; j++) { - struct cmd_bin *bin = lp_scene_get_bin(scene, i, j); - lp_rast_cmd last_cmd = lp_get_last_command(bin); - if (last_cmd == cmd) { - lp_replace_last_command_arg(bin, arg); - } - else { - lp_scene_bin_command( scene, i, j, cmd, arg ); - } - } + const struct resource_ref *ref; + int i; + + for (ref = scene->resources; ref; ref = ref->next) { + for (i = 0; i < ref->count; i++) + if (ref->resource[i] == resource) + return TRUE; } + + return FALSE; } + + /** advance curr_x,y to the next bin */ static boolean next_bin(struct lp_scene *scene) @@ -368,7 +446,7 @@ lp_scene_bin_iter_begin( struct lp_scene *scene ) * of work (a bin) to work on. */ struct cmd_bin * -lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y ) +lp_scene_bin_iter_next( struct lp_scene *scene ) { struct cmd_bin *bin = NULL; @@ -385,11 +463,39 @@ lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y ) } bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y); - *bin_x = scene->curr_x; - *bin_y = scene->curr_y; end: /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/ pipe_mutex_unlock(scene->mutex); return bin; } + + +void lp_scene_begin_binning( struct lp_scene *scene, + struct pipe_framebuffer_state *fb ) +{ + assert(lp_scene_is_empty(scene)); + + util_copy_framebuffer_state(&scene->fb, fb); + + scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE; + scene->tiles_y = align(fb->height, TILE_SIZE) / TILE_SIZE; + + assert(scene->tiles_x <= TILES_X); + assert(scene->tiles_y <= TILES_Y); +} + + +void lp_scene_end_binning( struct lp_scene *scene ) +{ + if (LP_DEBUG & DEBUG_SCENE) { + debug_printf("rasterize scene:\n"); + debug_printf(" scene_size: %u\n", + scene->scene_size); + debug_printf(" data size: %u\n", + lp_scene_data_size(scene)); + + if (0) + lp_debug_bins( scene ); + } +}