diff options
Diffstat (limited to 'src/gallium/drivers/llvmpipe/lp_scene.c')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_scene.c | 446 |
1 files changed, 243 insertions, 203 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index 1482a777ff8..8b504f23a33 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -25,21 +25,25 @@ * **************************************************************************/ +#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_surface.h" +#include "util/u_format.h" #include "lp_scene.h" -#include "lp_scene_queue.h" +#include "lp_fence.h" +#include "lp_debug.h" -/** List of texture references */ -struct texture_ref { - struct pipe_resource *texture; - struct texture_ref *prev, *next; /**< linked list w/ u_simple_list.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; +}; /** @@ -47,28 +51,16 @@ struct texture_ref { * \param queue the queue to put newly rendered/emptied scenes into */ struct lp_scene * -lp_scene_create( struct pipe_context *pipe, - struct lp_scene_queue *queue ) +lp_scene_create( struct pipe_context *pipe ) { - unsigned i, j; struct lp_scene *scene = CALLOC_STRUCT(lp_scene); if (!scene) return NULL; scene->pipe = pipe; - scene->empty_queue = queue; - - 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->resources); + CALLOC_STRUCT(data_block); pipe_mutex_init(scene->mutex); @@ -82,24 +74,9 @@ lp_scene_create( struct pipe_context *pipe, void lp_scene_destroy(struct lp_scene *scene) { - unsigned i, j; - - lp_scene_reset(scene); - - 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); - assert(bin->commands.head == bin->commands.tail); - FREE(bin->commands.head); - bin->commands.head = NULL; - bin->commands.tail = NULL; - } - - FREE(scene->data.head); - scene->data.head = NULL; - pipe_mutex_destroy(scene->mutex); - + assert(scene->data.head->next == NULL); + FREE(scene->data.head); FREE(scene); } @@ -116,8 +93,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; } } @@ -126,82 +102,166 @@ lp_scene_is_empty(struct lp_scene *scene ) } -/* Free data for one particular bin. May be called from the - * rasterizer thread(s). +/* 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->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]; + scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture, + cbuf->level); + + scene->cbufs[i].map = llvmpipe_resource_map(cbuf->texture, + cbuf->face, + cbuf->level, + cbuf->zslice, + 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; + scene->zsbuf.stride = llvmpipe_resource_stride(zsbuf->texture, zsbuf->level); + scene->zsbuf.blocksize = + util_format_get_blocksize(zsbuf->texture->format); + + scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture, + zsbuf->face, + zsbuf->level, + zsbuf->zslice, + LP_TEX_USAGE_READ_WRITE, + LP_TEX_LAYOUT_NONE); + } } + + /** - * Free all the temporary data in a scene. May be called from the - * rasterizer thread(s). + * 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->face, + cbuf->level, + cbuf->zslice); + 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->face, + zsbuf->level, + zsbuf->zslice); + 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 = bin->tail = 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 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); + } + } + + if (LP_DEBUG & DEBUG_SETUP) + debug_printf("scene %d resources, sz %d\n", + j, scene->resource_reference_size); + } + + /* Free all scene data blocks: */ { struct data_block_list *list = &scene->data; struct data_block *block, *tmp; - for (block = list->head; block != list->tail; block = tmp) { + for (block = list->head->next; block; block = tmp) { tmp = block->next; - FREE(block); + FREE(block); } - - assert(list->tail->next == NULL); - list->head = list->tail; + + list->head->next = NULL; list->head->used = 0; } - /* Release texture refs - */ - { - struct resource_ref *ref, *next, *ref_list = &scene->resources; - for (ref = ref_list->next; ref != ref_list; ref = next) { - next = next_elem(ref); - pipe_resource_reference(&ref->resource, NULL); - FREE(ref); - } - make_empty_list(ref_list); - } + lp_fence_reference(&scene->fence, NULL); + scene->resources = NULL; scene->scene_size = 0; + scene->resource_reference_size = 0; - scene->has_color_clear = FALSE; - scene->has_depth_clear = FALSE; + scene->has_depthstencil_clear = FALSE; + scene->alloc_failed = FALSE; + + util_unreference_framebuffer_state( &scene->fb ); } @@ -209,25 +269,49 @@ lp_scene_reset(struct lp_scene *scene ) -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; + } } @@ -235,7 +319,7 @@ lp_bin_new_data_block( struct data_block_list *list ) * Return number of bytes used for all bin data within a scene. * This does not include resources (textures) referenced by the scene. */ -unsigned +static unsigned lp_scene_data_size( const struct lp_scene *scene ) { unsigned size = 0; @@ -247,36 +331,63 @@ 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 resource by the scene. */ -void +boolean lp_scene_add_resource_reference(struct lp_scene *scene, - struct pipe_resource *resource) + struct pipe_resource *resource, + boolean initializing_scene) { - struct resource_ref *ref = CALLOC_STRUCT(resource_ref); - if (ref) { - struct resource_ref *ref_list = &scene->resources; - pipe_resource_reference(&ref->resource, resource); - insert_at_tail(ref_list, ref); + 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; + } } - scene->scene_size += llvmpipe_resource_size(resource); + /* 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); + } + + /* 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; + + return TRUE; } @@ -287,71 +398,20 @@ boolean lp_scene_is_resource_referenced(const struct lp_scene *scene, const struct pipe_resource *resource) { - const struct resource_ref *ref_list = &scene->resources; const struct resource_ref *ref; - foreach (ref, ref_list) { - if (ref->resource == resource) - return TRUE; - } - return FALSE; -} - - -/** - * 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; -} + int i; + for (ref = scene->resources; ref; ref = ref->next) { + for (i = 0; i < ref->count; i++) + if (ref->resource[i] == resource) + return TRUE; + } -/** - * 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 FALSE; } -/** - * 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. - */ -void -lp_scene_bin_state_command( struct lp_scene *scene, - lp_rast_cmd cmd, - const union lp_rast_cmd_arg arg ) -{ - 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 ); - } - } - } -} - /** advance curr_x,y to the next bin */ static boolean @@ -384,7 +444,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; @@ -401,8 +461,6 @@ 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);*/ @@ -426,34 +484,16 @@ void lp_scene_begin_binning( struct lp_scene *scene, } -void lp_scene_rasterize( struct lp_scene *scene, - struct lp_rasterizer *rast ) +void lp_scene_end_binning( struct lp_scene *scene ) { - if (0) { - unsigned x, y; + if (LP_DEBUG & DEBUG_SCENE) { debug_printf("rasterize scene:\n"); - debug_printf(" data size: %u\n", lp_scene_data_size(scene)); - for (y = 0; y < scene->tiles_y; y++) { - for (x = 0; x < scene->tiles_x; x++) { - debug_printf(" bin %u, %u size: %u\n", x, y, - lp_scene_bin_size(scene, x, y)); - } - } - } + debug_printf(" scene_size: %u\n", + scene->scene_size); + debug_printf(" data size: %u\n", + lp_scene_data_size(scene)); - /* Enqueue the scene for rasterization, then immediately wait for - * it to finish. - */ - lp_rast_queue_scene( rast, scene ); - - /* Currently just wait for the rasterizer to finish. Some - * threading interactions need to be worked out, particularly once - * transfers become per-context: - */ - lp_rast_finish( rast ); - - util_unreference_framebuffer_state( &scene->fb ); - - /* put scene into the empty list */ - lp_scene_enqueue( scene->empty_queue, scene ); + if (0) + lp_debug_bins( scene ); + } } |