X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fllvmpipe%2Flp_scene.c;h=ef0136c4fd2eb40a2d65055c9e11dd27e5cfdff0;hb=ce785f5ffd7dbed14a3909164e55a975a023ee97;hp=0b185c4c412717f58f51bea4ad128bff2fd59cca;hpb=e4c54d404959aa1bce26caa313c0a47e65ff211a;p=mesa.git diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index 0b185c4c412..ef0136c4fd2 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -25,78 +25,74 @@ * **************************************************************************/ +#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/simple_list.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; +}; +/** + * Create a new scene object. + * \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); + CALLOC_STRUCT(data_block); - make_empty_list(&scene->resources); + (void) mtx_init(&scene->mutex, mtx_plain); - pipe_mutex_init(scene->mutex); +#ifdef DEBUG + /* Do some scene limit sanity checks here */ + { + size_t maxBins = TILES_X * TILES_Y; + size_t maxCommandBytes = sizeof(struct cmd_block) * maxBins; + size_t maxCommandPlusData = maxCommandBytes + DATA_BLOCK_SIZE; + /* We'll need at least one command block per bin. Make sure that's + * less than the max allowed scene size. + */ + assert(maxCommandBytes < LP_SCENE_MAX_SIZE); + /* We'll also need space for at least one other data block */ + assert(maxCommandPlusData <= LP_SCENE_MAX_SIZE); + } +#endif return scene; } /** - * Free all data associated with the given scene, and free(scene). + * Free all data associated with the given scene, and the scene itself. */ 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; - } - + lp_fence_reference(&scene->fence, NULL); + mtx_destroy(&scene->mutex); + assert(scene->data.head->next == NULL); FREE(scene->data.head); - scene->data.head = NULL; - - pipe_mutex_destroy(scene->mutex); - FREE(scene); } @@ -113,8 +109,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; } } @@ -123,80 +118,186 @@ 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->last_state = NULL; + bin->head = bin->tail; + if (bin->tail) { + bin->tail->next = NULL; + bin->tail->count = 0; + } +} + + +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]; + + if (!cbuf) { + scene->cbufs[i].stride = 0; + scene->cbufs[i].layer_stride = 0; + scene->cbufs[i].map = NULL; + continue; + } - for (block = list->head; block != list->tail; block = tmp) { - tmp = block->next; - FREE(block); + if (llvmpipe_resource_is_texture(cbuf->texture)) { + scene->cbufs[i].stride = llvmpipe_resource_stride(cbuf->texture, + cbuf->u.tex.level); + scene->cbufs[i].layer_stride = llvmpipe_layer_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); + scene->cbufs[i].format_bytes = util_format_get_blocksize(cbuf->format); + } + else { + struct llvmpipe_resource *lpr = llvmpipe_resource(cbuf->texture); + unsigned pixstride = util_format_get_blocksize(cbuf->format); + scene->cbufs[i].stride = cbuf->texture->width0; + scene->cbufs[i].layer_stride = 0; + scene->cbufs[i].map = lpr->data; + scene->cbufs[i].map += cbuf->u.buf.first_element * pixstride; + scene->cbufs[i].format_bytes = util_format_get_blocksize(cbuf->format); + } } - 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->u.tex.level); + scene->zsbuf.layer_stride = llvmpipe_layer_stride(zsbuf->texture, zsbuf->u.tex.level); + + scene->zsbuf.map = llvmpipe_resource_map(zsbuf->texture, + zsbuf->u.tex.level, + zsbuf->u.tex.first_layer, + LP_TEX_USAGE_READ_WRITE); + scene->zsbuf.format_bytes = util_format_get_blocksize(zsbuf->format); + } } + + /** - * 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]; + if (llvmpipe_resource_is_texture(cbuf->texture)) { + llvmpipe_resource_unmap(cbuf->texture, + cbuf->u.tex.level, + cbuf->u.tex.first_layer); + } + scene->cbufs[i].map = NULL; + } + } - /* Free all but last binner command lists: + /* 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; + } + + /* 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 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->alloc_failed = FALSE; + + util_unreference_framebuffer_state( &scene->fb ); } @@ -204,30 +305,57 @@ 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) + 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; @@ -239,34 +367,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; + } + } + + /* 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; } @@ -277,71 +434,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 @@ -374,11 +480,11 @@ 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 , int *x, int *y) { struct cmd_bin *bin = NULL; - pipe_mutex_lock(scene->mutex); + mtx_lock(&scene->mutex); if (scene->curr_x < 0) { /* first bin */ @@ -391,117 +497,67 @@ 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; + *x = scene->curr_x; + *y = scene->curr_y; end: /*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/ - pipe_mutex_unlock(scene->mutex); + mtx_unlock(&scene->mutex); return bin; } - -/** - * Prepare this scene for the rasterizer. - * Map the framebuffer surfaces. Initialize the 'rast' state. - */ -static boolean -lp_scene_map_buffers( struct lp_scene *scene ) +void lp_scene_begin_binning(struct lp_scene *scene, + struct pipe_framebuffer_state *fb) { - LP_DBG(DEBUG_RAST, "%s\n", __FUNCTION__); + int i; + unsigned max_layer = ~0; - /* XXX framebuffer surfaces are no longer mapped here */ - /* XXX move all map/unmap stuff into rast module... */ - - return TRUE; -} - - - -/** - * Called after rasterizer as finished rasterizing a scene. - * - * We want to call this from the pipe_context's current thread to - * avoid having to have mutexes on the transfer functions. - */ -static void -lp_scene_unmap_buffers( struct lp_scene *scene ) -{ -#if 0 - unsigned i; - - for (i = 0; i < scene->fb.nr_cbufs; i++) { - if (scene->cbuf_map[i]) { - struct pipe_surface *cbuf = scene->fb.cbufs[i]; - llvmpipe_resource_unmap(cbuf->texture, - cbuf->face, - cbuf->level, - cbuf->zslice); - scene->cbuf_map[i] = NULL; - } - } - - 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; - } -#endif - - util_unreference_framebuffer_state( &scene->fb ); -} - - -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_rasterize( struct lp_scene *scene, - struct lp_rasterizer *rast, - boolean write_depth ) -{ - if (0) { - unsigned x, y; - 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)); + /* + * Determine how many layers the fb has (used for clamping layer value). + * OpenGL (but not d3d10) permits different amount of layers per rt, however + * results are undefined if layer exceeds the amount of layers of ANY + * attachment hence don't need separate per cbuf and zsbuf max. + */ + for (i = 0; i < scene->fb.nr_cbufs; i++) { + struct pipe_surface *cbuf = scene->fb.cbufs[i]; + if (cbuf) { + if (llvmpipe_resource_is_texture(cbuf->texture)) { + max_layer = MIN2(max_layer, + cbuf->u.tex.last_layer - cbuf->u.tex.first_layer); + } + else { + max_layer = 0; } } } + if (fb->zsbuf) { + struct pipe_surface *zsbuf = scene->fb.zsbuf; + max_layer = MIN2(max_layer, zsbuf->u.tex.last_layer - zsbuf->u.tex.first_layer); + } + scene->fb_max_layer = max_layer; +} - scene->write_depth = (scene->fb.zsbuf != NULL && - write_depth); - - lp_scene_map_buffers( scene ); - /* Enqueue the scene for rasterization, then immediately wait for - * it to finish. - */ - lp_rast_queue_scene( rast, scene ); +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)); - /* 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 ); - lp_scene_unmap_buffers( scene ); - lp_scene_enqueue( scene->empty_queue, scene ); + if (0) + lp_debug_bins( scene ); + } }