From: Rob Clark Date: Fri, 12 Dec 2014 18:38:05 +0000 (-0500) Subject: freedreno/a4xx: mipmaps X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0ebd623f6058fd20ee28e206da2da259073fdf86;p=mesa.git freedreno/a4xx: mipmaps Signed-off-by: Rob Clark --- diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c index d278bb5e009..00e92ceba36 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c @@ -208,13 +208,14 @@ emit_textures(struct fd_context *ctx, struct fd_ringbuffer *ring, fd4_pipe_sampler_view(tex->textures[i]) : &dummy_view; struct fd_resource *rsc = view->tex_resource; - struct fd_resource_slice *slice = fd_resource_slice(rsc, 0); + unsigned start = view->base.u.tex.first_level; + uint32_t offset = fd_resource_offset(rsc, start, 0); + OUT_RING(ring, view->texconst0); OUT_RING(ring, view->texconst1); OUT_RING(ring, view->texconst2); OUT_RING(ring, view->texconst3); - OUT_RELOC(ring, rsc->bo, slice->offset, - view->textconst4, 0); + OUT_RELOC(ring, rsc->bo, offset, view->textconst4, 0); OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000); diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_texture.c b/src/gallium/drivers/freedreno/a4xx/fd4_texture.c index 849113d80cc..f9b6dcc7057 100644 --- a/src/gallium/drivers/freedreno/a4xx/fd4_texture.c +++ b/src/gallium/drivers/freedreno/a4xx/fd4_texture.c @@ -86,13 +86,18 @@ fd4_sampler_state_create(struct pipe_context *pctx, const struct pipe_sampler_state *cso) { struct fd4_sampler_stateobj *so = CALLOC_STRUCT(fd4_sampler_stateobj); + bool miplinear = false; if (!so) return NULL; + if (cso->min_mip_filter == PIPE_TEX_MIPFILTER_LINEAR) + miplinear = true; + so->base = *cso; so->texsamp0 = + COND(miplinear, A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR) | A4XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter)) | A4XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter)) | A4XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s)) | @@ -100,6 +105,7 @@ fd4_sampler_state_create(struct pipe_context *pctx, A4XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r)); so->texsamp1 = +// COND(miplinear, A4XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR) | COND(!cso->normalized_coords, A4XX_TEX_SAMP_1_UNNORM_COORDS); if (cso->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) { @@ -143,6 +149,7 @@ fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, struct fd4_pipe_sampler_view *so = CALLOC_STRUCT(fd4_pipe_sampler_view); struct fd_resource *rsc = fd_resource(prsc); unsigned lvl = cso->u.tex.first_level; + unsigned miplevels = cso->u.tex.last_level - lvl; if (!so) return NULL; @@ -158,12 +165,13 @@ fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, so->texconst0 = A4XX_TEX_CONST_0_TYPE(tex_type(prsc->target)) | A4XX_TEX_CONST_0_FMT(fd4_pipe2tex(cso->format)) | + A4XX_TEX_CONST_0_MIPLVLS(miplevels) | fd4_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, cso->swizzle_a); so->texconst1 = - A4XX_TEX_CONST_1_WIDTH(prsc->width0) | - A4XX_TEX_CONST_1_HEIGHT(prsc->height0); + A4XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | + A4XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); so->texconst2 = A4XX_TEX_CONST_2_FETCHSIZE(fd4_pipe2fetchsize(cso->format)) | A4XX_TEX_CONST_2_PITCH(rsc->slices[lvl].pitch * rsc->cpp); @@ -173,13 +181,13 @@ fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, case PIPE_TEXTURE_2D_ARRAY: so->texconst3 = A4XX_TEX_CONST_3_DEPTH(prsc->array_size) | - A4XX_TEX_CONST_3_LAYERSZ(rsc->slices[0].size0); + A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); break; case PIPE_TEXTURE_CUBE: case PIPE_TEXTURE_CUBE_ARRAY: /* ?? not sure about _CUBE_ARRAY */ so->texconst3 = A4XX_TEX_CONST_3_DEPTH(1) | - A4XX_TEX_CONST_3_LAYERSZ(rsc->slices[0].size0); + A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); break; case PIPE_TEXTURE_3D: so->texconst3 = diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index d604aa3f1f8..c412407314f 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -101,6 +101,7 @@ fd_resource_transfer_map(struct pipe_context *pctx, struct pipe_transfer *ptrans; enum pipe_format format = prsc->format; uint32_t op = 0; + uint32_t offset; char *buf; int ret = 0; @@ -146,10 +147,19 @@ fd_resource_transfer_map(struct pipe_context *pctx, *pptrans = ptrans; - return buf + slice->offset + - box->y / util_format_get_blockheight(format) * ptrans->stride + - box->x / util_format_get_blockwidth(format) * rsc->cpp + - box->z * slice->size0; + if (rsc->layer_first) { + offset = slice->offset + + box->y / util_format_get_blockheight(format) * ptrans->stride + + box->x / util_format_get_blockwidth(format) * rsc->cpp + + box->z * rsc->layer_size; + } else { + offset = slice->offset + + box->y / util_format_get_blockheight(format) * ptrans->stride + + box->x / util_format_get_blockwidth(format) * rsc->cpp + + box->z * slice->size0; + } + + return buf + offset; fail: fd_resource_transfer_unmap(pctx, ptrans); @@ -195,6 +205,10 @@ setup_slices(struct fd_resource *rsc, uint32_t alignment) uint32_t width = prsc->width0; uint32_t height = prsc->height0; uint32_t depth = prsc->depth0; + /* in layer_first layout, the level (slice) contains just one + * layer (since in fact the layer contains the slices) + */ + uint32_t layers_in_level = rsc->layer_first ? 1 : prsc->array_size; for (level = 0; level <= prsc->last_level; level++) { struct fd_resource_slice *slice = fd_resource_slice(rsc, level); @@ -203,7 +217,7 @@ setup_slices(struct fd_resource *rsc, uint32_t alignment) slice->offset = size; slice->size0 = align(slice->pitch * height * rsc->cpp, alignment); - size += slice->size0 * depth * prsc->array_size; + size += slice->size0 * depth * layers_in_level; width = u_minify(width, 1); height = u_minify(height, 1); @@ -216,12 +230,6 @@ setup_slices(struct fd_resource *rsc, uint32_t alignment) static uint32_t slice_alignment(struct pipe_screen *pscreen, const struct pipe_resource *tmpl) { - struct fd_screen *screen = fd_screen(pscreen); - - /* on a4xx, seems like everything is aligned to page: */ - if ((screen->gpu_id >= 400) && (screen->gpu_id < 500)) - return 4096; - /* on a3xx, 2d array and 3d textures seem to want their * layers aligned to page boundaries: */ @@ -266,8 +274,25 @@ fd_resource_create(struct pipe_screen *pscreen, assert(rsc->cpp); + if (is_a4xx(fd_screen(pscreen))) { + switch (tmpl->target) { + case PIPE_TEXTURE_3D: + /* TODO 3D_ARRAY? */ + rsc->layer_first = false; + break; + default: + rsc->layer_first = true; + break; + } + } + size = setup_slices(rsc, slice_alignment(pscreen, tmpl)); + if (rsc->layer_first) { + rsc->layer_size = align(size, 4096); + size = rsc->layer_size * prsc->array_size; + } + realloc_bo(rsc, size); if (!rsc->bo) goto fail; diff --git a/src/gallium/drivers/freedreno/freedreno_resource.h b/src/gallium/drivers/freedreno/freedreno_resource.h index 1073eb7547e..bad36813461 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.h +++ b/src/gallium/drivers/freedreno/freedreno_resource.h @@ -33,11 +33,24 @@ #include "freedreno_util.h" -/* for mipmap, cubemap, etc, each level is represented by a slice. - * Currently all slices are part of same bo (just different offsets), - * this is at least how it needs to be for cubemaps, although mipmap - * can be different bo's (although, not sure if there is a strong - * advantage to doing that) +/* Texture Layout on a3xx: + * + * Each mipmap-level contains all of it's layers (ie. all cubmap + * faces, all 1d/2d array elements, etc). The texture sampler is + * programmed with the start address of each mipmap level, and hw + * derives the layer offset within the level. + * + * Texture Layout on a4xx: + * + * For cubemap and 2d array, each layer contains all of it's mipmap + * levels (layer_first layout). + * + * 3d textures are layed out as on a3xx, but unknown about 3d-array + * textures. + * + * In either case, the slice represents the per-miplevel information, + * but in layer_first layout it only includes the first layer, and + * an additional offset of (rsc->layer_size * layer) must be added. */ struct fd_resource_slice { uint32_t offset; /* offset of first layer in slice */ @@ -49,6 +62,8 @@ struct fd_resource { struct u_resource base; struct fd_bo *bo; uint32_t cpp; + bool layer_first; /* see above description */ + uint32_t layer_size; struct fd_resource_slice slices[MAX_MIP_LEVELS]; uint32_t timestamp; bool dirty; @@ -72,7 +87,14 @@ static INLINE uint32_t fd_resource_offset(struct fd_resource *rsc, unsigned level, unsigned layer) { struct fd_resource_slice *slice = fd_resource_slice(rsc, level); - return slice->offset + (slice->size0 * layer); + unsigned offset; + if (rsc->layer_first) { + offset = slice->offset + (rsc->layer_size * layer); + } else { + offset = slice->offset + (slice->size0 * layer); + } + debug_assert(offset < fd_bo_size(rsc->bo)); + return offset; } void fd_resource_screen_init(struct pipe_screen *pscreen);