Mesa (master): freedreno/a4xx: mipmaps

Rob Clark robclark at kemper.freedesktop.org
Sat Dec 13 20:34:54 UTC 2014


Module: Mesa
Branch: master
Commit: 0ebd623f6058fd20ee28e206da2da259073fdf86
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=0ebd623f6058fd20ee28e206da2da259073fdf86

Author: Rob Clark <robclark at freedesktop.org>
Date:   Fri Dec 12 13:38:05 2014 -0500

freedreno/a4xx: mipmaps

Signed-off-by: Rob Clark <robclark at freedesktop.org>

---

 src/gallium/drivers/freedreno/a4xx/fd4_emit.c      |    7 +--
 src/gallium/drivers/freedreno/a4xx/fd4_texture.c   |   16 +++++--
 src/gallium/drivers/freedreno/freedreno_resource.c |   47 +++++++++++++++-----
 src/gallium/drivers/freedreno/freedreno_resource.h |   34 +++++++++++---
 4 files changed, 80 insertions(+), 24 deletions(-)

diff --git a/src/gallium/drivers/freedreno/a4xx/fd4_emit.c b/src/gallium/drivers/freedreno/a4xx/fd4_emit.c
index d278bb5..00e92ce 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 849113d..f9b6dcc 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 d604aa3..c412407 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 1073eb7..bad3681 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);




More information about the mesa-commit mailing list