diff options
Diffstat (limited to 'src/gallium/drivers/llvmpipe/lp_texture.c')
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_texture.c | 290 |
1 files changed, 247 insertions, 43 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c index 3468fbfb1f3..a4b9f2590af 100644 --- a/src/gallium/drivers/llvmpipe/lp_texture.c +++ b/src/gallium/drivers/llvmpipe/lp_texture.c @@ -36,9 +36,11 @@ #include "pipe/p_defines.h" #include "util/u_inlines.h" +#include "util/u_cpu_detect.h" #include "util/u_format.h" #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_simple_list.h" #include "util/u_transfer.h" #include "lp_context.h" @@ -51,6 +53,12 @@ #include "state_tracker/sw_winsys.h" +#ifdef DEBUG +static struct llvmpipe_resource resource_list; +#endif +static unsigned id_counter = 0; + + static INLINE boolean resource_is_texture(const struct pipe_resource *resource) { @@ -59,6 +67,7 @@ resource_is_texture(const struct pipe_resource *resource) return FALSE; case PIPE_TEXTURE_1D: case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: case PIPE_TEXTURE_3D: case PIPE_TEXTURE_CUBE: return TRUE; @@ -107,32 +116,55 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen, assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS); for (level = 0; level <= pt->last_level; level++) { - const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE; - const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE; - unsigned nblocksx, num_slices; - - if (lpr->base.target == PIPE_TEXTURE_CUBE) - num_slices = 6; - else if (lpr->base.target == PIPE_TEXTURE_3D) - num_slices = depth; - else - num_slices = 1; - - /* Allocate storage for whole quads. This is particularly important - * for depth surfaces, which are currently stored in a swizzled format. - */ - nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE)); - lpr->row_stride[level] = - align(nblocksx * util_format_get_blocksize(pt->format), 16); + /* Row stride and image stride (for linear layout) */ + { + unsigned alignment, nblocksx, nblocksy, block_size; + + /* For non-compressed formats we need to align the texture size + * to the tile size to facilitate render-to-texture. + */ + if (util_format_is_compressed(pt->format)) + alignment = 1; + else + alignment = TILE_SIZE; + + nblocksx = util_format_get_nblocksx(pt->format, + align(width, alignment)); + nblocksy = util_format_get_nblocksy(pt->format, + align(height, alignment)); + block_size = util_format_get_blocksize(pt->format); + + lpr->row_stride[level] = align(nblocksx * block_size, 16); + + lpr->img_stride[level] = lpr->row_stride[level] * nblocksy; + } + + /* Size of the image in tiles (for tiled layout) */ + { + const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE; + const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE; + lpr->tiles_per_row[level] = width_t; + lpr->tiles_per_image[level] = width_t * height_t; + } + + /* Number of 3D image slices or cube faces */ + { + unsigned num_slices; + + if (lpr->base.target == PIPE_TEXTURE_CUBE) + num_slices = 6; + else if (lpr->base.target == PIPE_TEXTURE_3D) + num_slices = depth; + else + num_slices = 1; - lpr->img_stride[level] = lpr->row_stride[level] * align(height, TILE_SIZE); + lpr->num_slices_faces[level] = num_slices; - lpr->tiles_per_row[level] = width_t; - lpr->tiles_per_image[level] = width_t * height_t; - lpr->num_slices_faces[level] = num_slices; - lpr->layout[level] = alloc_layout_array(num_slices, width, height); + lpr->layout[level] = alloc_layout_array(num_slices, width, height); + } + /* Compute size of next mipmap level */ width = u_minify(width, 1); height = u_minify(height, 1); depth = u_minify(depth, 1); @@ -154,8 +186,8 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen, */ const unsigned width = align(lpr->base.width0, TILE_SIZE); const unsigned height = align(lpr->base.height0, TILE_SIZE); - const unsigned width_t = align(width, TILE_SIZE) / TILE_SIZE; - const unsigned height_t = align(height, TILE_SIZE) / TILE_SIZE; + const unsigned width_t = width / TILE_SIZE; + const unsigned height_t = height / TILE_SIZE; lpr->tiles_per_row[0] = width_t; lpr->tiles_per_image[0] = width_t * height_t; @@ -180,7 +212,6 @@ static struct pipe_resource * llvmpipe_resource_create(struct pipe_screen *_screen, const struct pipe_resource *templat) { - static unsigned id_counter = 0; struct llvmpipe_screen *screen = llvmpipe_screen(_screen); struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource); if (!lpr) @@ -190,7 +221,7 @@ llvmpipe_resource_create(struct pipe_screen *_screen, pipe_reference_init(&lpr->base.reference, 1); lpr->base.screen = &screen->base; - assert(lpr->base.bind); + /* assert(lpr->base.bind); */ if (resource_is_texture(&lpr->base)) { if (lpr->base.bind & PIPE_BIND_DISPLAY_TARGET) { @@ -222,6 +253,10 @@ llvmpipe_resource_create(struct pipe_screen *_screen, lpr->id = id_counter++; +#ifdef DEBUG + insert_at_tail(&resource_list, lpr); +#endif + return &lpr->base; fail: @@ -242,6 +277,11 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen, struct sw_winsys *winsys = screen->winsys; winsys->displaytarget_destroy(winsys, lpr->dt); + if (lpr->tiled[0].data) { + align_free(lpr->tiled[0].data); + lpr->tiled[0].data = NULL; + } + FREE(lpr->layout[0]); } else if (resource_is_texture(pt)) { @@ -275,6 +315,11 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen, align_free(lpr->data); } +#ifdef DEBUG + if (lpr->next) + remove_from_list(lpr); +#endif + FREE(lpr); } @@ -346,7 +391,6 @@ llvmpipe_resource_map(struct pipe_resource *resource, map = llvmpipe_get_texture_image(lpr, face + zslice, level, tex_usage, layout); - assert(map); return map; } else { @@ -403,6 +447,10 @@ llvmpipe_resource_from_handle(struct pipe_screen *screen, { struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys; struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource); + unsigned width, height, width_t, height_t; + + /* XXX Seems like from_handled depth textures doesn't work that well */ + if (!lpr) return NULL; @@ -410,6 +458,25 @@ llvmpipe_resource_from_handle(struct pipe_screen *screen, pipe_reference_init(&lpr->base.reference, 1); lpr->base.screen = screen; + width = align(lpr->base.width0, TILE_SIZE); + height = align(lpr->base.height0, TILE_SIZE); + width_t = width / TILE_SIZE; + height_t = height / TILE_SIZE; + + /* + * Looks like unaligned displaytargets work just fine, + * at least sampler/render ones. + */ +#if 0 + assert(lpr->base.width0 == width); + assert(lpr->base.height0 == height); +#endif + + lpr->tiles_per_row[0] = width_t; + lpr->tiles_per_image[0] = width_t * height_t; + lpr->num_slices_faces[0] = 1; + lpr->img_stride[0] = 0; + lpr->dt = winsys->displaytarget_from_handle(winsys, template, whandle, @@ -417,6 +484,17 @@ llvmpipe_resource_from_handle(struct pipe_screen *screen, if (!lpr->dt) goto fail; + lpr->layout[0] = alloc_layout_array(1, lpr->base.width0, lpr->base.height0); + + assert(lpr->layout[0]); + assert(lpr->layout[0][0] == LP_TEX_LAYOUT_NONE); + + lpr->id = id_counter++; + +#ifdef DEBUG + insert_at_tail(&resource_list, lpr); +#endif + return &lpr->base; fail: @@ -445,7 +523,7 @@ static struct pipe_surface * llvmpipe_get_tex_surface(struct pipe_screen *screen, struct pipe_resource *pt, unsigned face, unsigned level, unsigned zslice, - enum lp_texture_usage usage) + unsigned usage) { struct pipe_surface *ps; @@ -506,7 +584,8 @@ llvmpipe_get_transfer(struct pipe_context *pipe, 0, /* flush_flags */ read_only, TRUE, /* cpu_access */ - do_not_block)) { + do_not_block, + __FUNCTION__)) { /* * It would have blocked, but state tracker requested no to. */ @@ -522,6 +601,7 @@ llvmpipe_get_transfer(struct pipe_context *pipe, pt->box = *box; pt->sr = sr; pt->stride = lprex->row_stride[sr.level]; + pt->slice_stride = lprex->img_stride[sr.level]; pt->usage = usage; return pt; @@ -693,11 +773,8 @@ tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level, return buffer_size; } else { - const enum pipe_format format = lpr->base.format; - const unsigned nblocksy = - util_format_get_nblocksy(format, align(height, TILE_SIZE)); - const unsigned buffer_size = nblocksy * lpr->row_stride[level]; - return buffer_size; + /* we already computed this */ + return lpr->img_stride[level]; } } @@ -858,13 +935,15 @@ static void alloc_image_data(struct llvmpipe_resource *lpr, unsigned level, enum lp_texture_layout layout) { + uint alignment = MAX2(16, util_cpu_caps.cacheline); + if (lpr->dt) assert(level == 0); if (layout == LP_TEX_LAYOUT_TILED) { /* tiled data is stored in regular memory */ uint buffer_size = tex_image_size(lpr, level, layout); - lpr->tiled[level].data = align_malloc(buffer_size, 16); + lpr->tiled[level].data = align_malloc(buffer_size, alignment); } else { assert(layout == LP_TEX_LAYOUT_LINEAR); @@ -880,7 +959,7 @@ alloc_image_data(struct llvmpipe_resource *lpr, unsigned level, else { /* not a display target - allocate regular memory */ uint buffer_size = tex_image_size(lpr, level, LP_TEX_LAYOUT_LINEAR); - lpr->linear[level].data = align_malloc(buffer_size, 16); + lpr->linear[level].data = align_malloc(buffer_size, alignment); } } } @@ -994,7 +1073,7 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *lpr, layout_logic(cur_layout, layout, usage, &new_layout, &convert); - if (convert) { + if (convert && other_data && target_data) { if (layout == LP_TEX_LAYOUT_TILED) { lp_linear_to_tiled(other_data, target_data, x * TILE_SIZE, y * TILE_SIZE, @@ -1004,6 +1083,7 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *lpr, lpr->tiles_per_row[level]); } else { + assert(layout == LP_TEX_LAYOUT_LINEAR); lp_tiled_to_linear(other_data, target_data, x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE, @@ -1013,8 +1093,9 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *lpr, } } - llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y, - new_layout); + if (new_layout != cur_layout) + llvmpipe_set_texture_tile_layout(lpr, face_slice, level, x, y, + new_layout); } } } @@ -1024,8 +1105,6 @@ llvmpipe_get_texture_image(struct llvmpipe_resource *lpr, width_t, height_t, layout); } - assert(target_data); - return target_data; } @@ -1095,7 +1174,7 @@ llvmpipe_get_texture_tile_linear(struct llvmpipe_resource *lpr, layout_logic(cur_layout, LP_TEX_LAYOUT_LINEAR, usage, &new_layout, &convert); - if (convert) { + if (convert && tiled_image && linear_image) { lp_tiled_to_linear(tiled_image, linear_image, x, y, TILE_SIZE, TILE_SIZE, lpr->base.format, lpr->row_stride[level], @@ -1144,13 +1223,16 @@ llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr, cur_layout = llvmpipe_get_texture_tile_layout(lpr, face_slice, level, tx, ty); layout_logic(cur_layout, LP_TEX_LAYOUT_TILED, usage, &new_layout, &convert); - if (convert) { + if (convert && linear_image && tiled_image) { lp_linear_to_tiled(linear_image, tiled_image, x, y, TILE_SIZE, TILE_SIZE, lpr->base.format, lpr->row_stride[level], lpr->tiles_per_row[level]); } + if (!tiled_image) + return NULL; + if (new_layout != cur_layout) llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, new_layout); @@ -1163,6 +1245,94 @@ llvmpipe_get_texture_tile(struct llvmpipe_resource *lpr, /** + * Get pointer to tiled data for rendering. + * \return pointer to the tiled data at the given tile position + */ +void +llvmpipe_unswizzle_cbuf_tile(struct llvmpipe_resource *lpr, + unsigned face_slice, unsigned level, + unsigned x, unsigned y, + uint8_t *tile) +{ + struct llvmpipe_texture_image *linear_img = &lpr->linear[level]; + const unsigned tx = x / TILE_SIZE, ty = y / TILE_SIZE; + uint8_t *linear_image; + + assert(x % TILE_SIZE == 0); + assert(y % TILE_SIZE == 0); + + if (!linear_img->data) { + /* allocate memory for the linear image now */ + alloc_image_data(lpr, level, LP_TEX_LAYOUT_LINEAR); + } + + /* compute address of the slice/face of the image that contains the tile */ + linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level, + LP_TEX_LAYOUT_LINEAR); + + { + uint ii = x, jj = y; + uint tile_offset = jj / TILE_SIZE + ii / TILE_SIZE; + uint byte_offset = tile_offset * TILE_SIZE * TILE_SIZE * 4; + + /* Note that lp_tiled_to_linear expects the tile parameter to + * point at the first tile in a whole-image sized array. In + * this code, we have only a single tile and have to do some + * pointer arithmetic to figure out where the "image" would have + * started. + */ + lp_tiled_to_linear(tile - byte_offset, linear_image, + x, y, TILE_SIZE, TILE_SIZE, + lpr->base.format, + lpr->row_stride[level], + 1); /* tiles per row */ + } + + llvmpipe_set_texture_tile_layout(lpr, face_slice, level, tx, ty, + LP_TEX_LAYOUT_LINEAR); +} + + +/** + * Get pointer to tiled data for rendering. + * \return pointer to the tiled data at the given tile position + */ +void +llvmpipe_swizzle_cbuf_tile(struct llvmpipe_resource *lpr, + unsigned face_slice, unsigned level, + unsigned x, unsigned y, + uint8_t *tile) +{ + uint8_t *linear_image; + + assert(x % TILE_SIZE == 0); + assert(y % TILE_SIZE == 0); + + /* compute address of the slice/face of the image that contains the tile */ + linear_image = llvmpipe_get_texture_image_address(lpr, face_slice, level, + LP_TEX_LAYOUT_LINEAR); + + if (linear_image) { + uint ii = x, jj = y; + uint tile_offset = jj / TILE_SIZE + ii / TILE_SIZE; + uint byte_offset = tile_offset * TILE_SIZE * TILE_SIZE * 4; + + /* Note that lp_linear_to_tiled expects the tile parameter to + * point at the first tile in a whole-image sized array. In + * this code, we have only a single tile and have to do some + * pointer arithmetic to figure out where the "image" would have + * started. + */ + lp_linear_to_tiled(linear_image, tile - byte_offset, + x, y, TILE_SIZE, TILE_SIZE, + lpr->base.format, + lpr->row_stride[level], + 1); /* tiles per row */ + } +} + + +/** * Return size of resource in bytes */ unsigned @@ -1183,9 +1353,43 @@ llvmpipe_resource_size(const struct pipe_resource *resource) } +#ifdef DEBUG +void +llvmpipe_print_resources(void) +{ + struct llvmpipe_resource *lpr; + unsigned n = 0, total = 0; + + debug_printf("LLVMPIPE: current resources:\n"); + foreach(lpr, &resource_list) { + unsigned size = llvmpipe_resource_size(&lpr->base); + debug_printf("resource %u at %p, size %ux%ux%u: %u bytes, refcount %u\n", + lpr->id, (void *) lpr, + lpr->base.width0, lpr->base.height0, lpr->base.depth0, + size, lpr->base.reference.count); + total += size; + n++; + } + debug_printf("LLVMPIPE: total size of %u resources: %u\n", n, total); +} +#endif + + void llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen) { +#ifdef DEBUG + /* init linked list for tracking resources */ + { + static boolean first_call = TRUE; + if (first_call) { + memset(&resource_list, 0, sizeof(resource_list)); + make_empty_list(&resource_list); + first_call = FALSE; + } + } +#endif + screen->resource_create = llvmpipe_resource_create; screen->resource_destroy = llvmpipe_resource_destroy; screen->resource_from_handle = llvmpipe_resource_from_handle; |