[Mesa-dev] [PATCH 09/16] ac/surface/gfx6: compute FMASK together with the color surface

Marek Olšák maraeo at gmail.com
Wed May 2 04:00:33 UTC 2018


From: Marek Olšák <marek.olsak at amd.com>

instead of invoking FMASK computation separately.
---
 src/amd/common/ac_surface.c                   | 86 ++++++++++++++++---
 src/amd/common/ac_surface.h                   | 13 ++-
 src/amd/vulkan/radv_image.c                   | 54 ++----------
 src/gallium/drivers/radeonsi/si_texture.c     | 48 ++---------
 .../winsys/radeon/drm/radeon_drm_surface.c    | 48 +++++++++++
 5 files changed, 149 insertions(+), 100 deletions(-)

diff --git a/src/amd/common/ac_surface.c b/src/amd/common/ac_surface.c
index 341a7854fe5..69a0c8a0f2f 100644
--- a/src/amd/common/ac_surface.c
+++ b/src/amd/common/ac_surface.c
@@ -220,22 +220,30 @@ ADDR_HANDLE amdgpu_addr_create(const struct radeon_info *info,
 
 	if (max_alignment) {
 		addrRet = AddrGetMaxAlignments(addrCreateOutput.hLib, &addrGetMaxAlignmentsOutput);
 		if (addrRet == ADDR_OK){
 			*max_alignment = addrGetMaxAlignmentsOutput.baseAlign;
 		}
 	}
 	return addrCreateOutput.hLib;
 }
 
-static int surf_config_sanity(const struct ac_surf_config *config)
+static int surf_config_sanity(const struct ac_surf_config *config,
+			      unsigned flags)
 {
+	/* FMASK is allocated together with the color surface and can't be
+	 * allocated separately.
+	 */
+	assert(!(flags & RADEON_SURF_FMASK));
+	if (flags & RADEON_SURF_FMASK)
+		return -EINVAL;
+
 	/* all dimension must be at least 1 ! */
 	if (!config->info.width || !config->info.height || !config->info.depth ||
 	    !config->info.array_size || !config->info.levels)
 		return -EINVAL;
 
 	switch (config->info.samples) {
 	case 0:
 	case 1:
 	case 2:
 	case 4:
@@ -438,21 +446,20 @@ static unsigned cik_get_macro_tile_index(struct radeon_surf *surf)
 	return index;
 }
 
 static bool get_display_flag(const struct ac_surf_config *config,
 			     const struct radeon_surf *surf)
 {
 	unsigned num_channels = config->info.num_channels;
 	unsigned bpe = surf->bpe;
 
 	if (surf->flags & RADEON_SURF_SCANOUT &&
-	    !(surf->flags & RADEON_SURF_FMASK) &&
 	    config->info.samples <= 1 &&
 	    surf->blk_w <= 2 && surf->blk_h == 1) {
 		/* subsampled */
 		if (surf->blk_w == 2 && surf->blk_h == 1)
 			return true;
 
 		if  (/* RGBA8 or RGBA16F */
 		     (bpe >= 4 && bpe <= 8 && num_channels == 4) ||
 		     /* R5G6B5 or R5G5B5A1 */
 		     (bpe == 2 && num_channels >= 3) ||
@@ -549,23 +556,22 @@ static int gfx6_compute_surface(ADDR_HANDLE addrlib,
 	AddrSurfInfoIn.size = sizeof(ADDR_COMPUTE_SURFACE_INFO_INPUT);
 	AddrSurfInfoOut.size = sizeof(ADDR_COMPUTE_SURFACE_INFO_OUTPUT);
 	AddrDccIn.size = sizeof(ADDR_COMPUTE_DCCINFO_INPUT);
 	AddrDccOut.size = sizeof(ADDR_COMPUTE_DCCINFO_OUTPUT);
 	AddrHtileIn.size = sizeof(ADDR_COMPUTE_HTILE_INFO_INPUT);
 	AddrHtileOut.size = sizeof(ADDR_COMPUTE_HTILE_INFO_OUTPUT);
 	AddrSurfInfoOut.pTileInfo = &AddrTileInfoOut;
 
 	compressed = surf->blk_w == 4 && surf->blk_h == 4;
 
-	/* MSAA and FMASK require 2D tiling. */
-	if (config->info.samples > 1 ||
-	    (surf->flags & RADEON_SURF_FMASK))
+	/* MSAA requires 2D tiling. */
+	if (config->info.samples > 1)
 		mode = RADEON_SURF_MODE_2D;
 
 	/* DB doesn't support linear layouts. */
 	if (surf->flags & (RADEON_SURF_Z_OR_SBUFFER) &&
 	    mode < RADEON_SURF_MODE_1D)
 		mode = RADEON_SURF_MODE_1D;
 
 	/* Set the requested tiling mode. */
 	switch (mode) {
 	case RADEON_SURF_MODE_LINEAR_ALIGNED:
@@ -600,29 +606,28 @@ static int gfx6_compute_surface(ADDR_HANDLE addrlib,
 		AddrDccIn.bpp = AddrSurfInfoIn.bpp = surf->bpe * 8;
 	}
 
 	AddrDccIn.numSamples = AddrSurfInfoIn.numSamples =
 		config->info.samples ? config->info.samples : 1;
 	AddrSurfInfoIn.tileIndex = -1;
 
 	/* Set the micro tile type. */
 	if (surf->flags & RADEON_SURF_SCANOUT)
 		AddrSurfInfoIn.tileType = ADDR_DISPLAYABLE;
-	else if (surf->flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_FMASK))
+	else if (surf->flags & RADEON_SURF_Z_OR_SBUFFER)
 		AddrSurfInfoIn.tileType = ADDR_DEPTH_SAMPLE_ORDER;
 	else
 		AddrSurfInfoIn.tileType = ADDR_NON_DISPLAYABLE;
 
 	AddrSurfInfoIn.flags.color = !(surf->flags & RADEON_SURF_Z_OR_SBUFFER);
 	AddrSurfInfoIn.flags.depth = (surf->flags & RADEON_SURF_ZBUFFER) != 0;
 	AddrSurfInfoIn.flags.cube = config->is_cube;
-	AddrSurfInfoIn.flags.fmask = (surf->flags & RADEON_SURF_FMASK) != 0;
 	AddrSurfInfoIn.flags.display = get_display_flag(config, surf);
 	AddrSurfInfoIn.flags.pow2Pad = config->info.levels > 1;
 	AddrSurfInfoIn.flags.tcCompatible = (surf->flags & RADEON_SURF_TC_COMPATIBLE_HTILE) != 0;
 
 	/* Only degrade the tile mode for space if TC-compatible HTILE hasn't been
 	 * requested, because TC-compatible HTILE requires 2D tiling.
 	 */
 	AddrSurfInfoIn.flags.opt4Space = !AddrSurfInfoIn.flags.tcCompatible &&
 					 !AddrSurfInfoIn.flags.fmask &&
 					 config->info.samples <= 1 &&
@@ -673,22 +678,20 @@ static int gfx6_compute_surface(ADDR_HANDLE addrlib,
 
 		/* Keep the depth mip-tail compatible with texturing. */
 		AddrSurfInfoIn.flags.noStencil = 1;
 	}
 
 	/* Set preferred macrotile parameters. This is usually required
 	 * for shared resources. This is for 2D tiling only. */
 	if (AddrSurfInfoIn.tileMode >= ADDR_TM_2D_TILED_THIN1 &&
 	    surf->u.legacy.bankw && surf->u.legacy.bankh &&
 	    surf->u.legacy.mtilea && surf->u.legacy.tile_split) {
-		assert(!(surf->flags & RADEON_SURF_FMASK));
-
 		/* If any of these parameters are incorrect, the calculation
 		 * will fail. */
 		AddrTileInfoIn.banks = surf->u.legacy.num_banks;
 		AddrTileInfoIn.bankWidth = surf->u.legacy.bankw;
 		AddrTileInfoIn.bankHeight = surf->u.legacy.bankh;
 		AddrTileInfoIn.macroAspectRatio = surf->u.legacy.mtilea;
 		AddrTileInfoIn.tileSplitBytes = surf->u.legacy.tile_split;
 		AddrTileInfoIn.pipeConfig = surf->u.legacy.pipe_config + 1; /* +1 compared to GB_TILE_MODE */
 		AddrSurfInfoIn.flags.opt4Space = 0;
 		AddrSurfInfoIn.pTileInfo = &AddrTileInfoIn;
@@ -821,20 +824,81 @@ static int gfx6_compute_surface(ADDR_HANDLE addrlib,
 
 				/* For 2D modes only. */
 				if (AddrSurfInfoOut.tileMode >= ADDR_TM_2D_TILED_THIN1) {
 					surf->u.legacy.stencil_tile_split =
 						AddrSurfInfoOut.pTileInfo->tileSplitBytes;
 				}
 			}
 		}
 	}
 
+	/* Compute FMASK. */
+	if (config->info.samples >= 2 && AddrSurfInfoIn.flags.color) {
+		ADDR_COMPUTE_FMASK_INFO_INPUT fin = {0};
+		ADDR_COMPUTE_FMASK_INFO_OUTPUT fout = {0};
+		ADDR_TILEINFO fmask_tile_info = {};
+
+		fin.size = sizeof(fin);
+		fout.size = sizeof(fout);
+
+		fin.tileMode = AddrSurfInfoOut.tileMode;
+		fin.pitch = AddrSurfInfoOut.pitch;
+		fin.height = config->info.height;
+		fin.numSlices = AddrSurfInfoIn.numSlices;
+		fin.numSamples = AddrSurfInfoIn.numSamples;
+		fin.numFrags = AddrSurfInfoIn.numFrags;
+		fin.tileIndex = AddrSurfInfoOut.tileIndex;
+		fout.pTileInfo = &fmask_tile_info;
+
+		r = AddrComputeFmaskInfo(addrlib, &fin, &fout);
+		if (r)
+			return r;
+
+		surf->u.legacy.fmask.size = fout.fmaskBytes;
+		surf->u.legacy.fmask.alignment = fout.baseAlign;
+		surf->u.legacy.fmask.tile_swizzle = 0;
+
+		surf->u.legacy.fmask.slice_tile_max =
+			(fout.pitch * fout.height) / 64;
+		if (surf->u.legacy.fmask.slice_tile_max)
+		    surf->u.legacy.fmask.slice_tile_max -= 1;
+
+		surf->u.legacy.fmask.tiling_index = fout.tileIndex;
+		surf->u.legacy.fmask.bankh = fout.pTileInfo->bankHeight;
+		surf->u.legacy.fmask.pitch_in_pixels = fout.pitch;
+
+		/* Compute tile swizzle for FMASK. */
+		if (config->info.fmask_surf_index &&
+		    !(surf->flags & RADEON_SURF_SHAREABLE)) {
+			ADDR_COMPUTE_BASE_SWIZZLE_INPUT xin = {0};
+			ADDR_COMPUTE_BASE_SWIZZLE_OUTPUT xout = {0};
+
+			xin.size = sizeof(ADDR_COMPUTE_BASE_SWIZZLE_INPUT);
+			xout.size = sizeof(ADDR_COMPUTE_BASE_SWIZZLE_OUTPUT);
+
+			/* This counter starts from 1 instead of 0. */
+			xin.surfIndex = p_atomic_inc_return(config->info.fmask_surf_index);
+			xin.tileIndex = fout.tileIndex;
+			xin.macroModeIndex = fout.macroModeIndex;
+			xin.pTileInfo = fout.pTileInfo;
+			xin.tileMode = fin.tileMode;
+
+			int r = AddrComputeBaseSwizzle(addrlib, &xin, &xout);
+			if (r != ADDR_OK)
+				return r;
+
+			assert(xout.tileSwizzle <=
+			       u_bit_consecutive(0, sizeof(surf->tile_swizzle) * 8));
+			surf->u.legacy.fmask.tile_swizzle = xout.tileSwizzle;
+		}
+	}
+
 	/* Recalculate the whole DCC miptree size including disabled levels.
 	 * This is what addrlib does, but calling addrlib would be a lot more
 	 * complicated.
 	 */
 	if (surf->dcc_size && config->info.levels > 1) {
 		/* The smallest miplevels that are never compressed by DCC
 		 * still read the DCC buffer via TC if the base level uses DCC,
 		 * and for some reason the DCC buffer needs to be larger if
 		 * the miptree uses non-zero tile_swizzle. Otherwise there are
 		 * VM faults.
@@ -1195,22 +1259,20 @@ static int gfx9_compute_miptree(ADDR_HANDLE addrlib,
 static int gfx9_compute_surface(ADDR_HANDLE addrlib,
 				const struct radeon_info *info,
 				const struct ac_surf_config *config,
 				enum radeon_surf_mode mode,
 				struct radeon_surf *surf)
 {
 	bool compressed;
 	ADDR2_COMPUTE_SURFACE_INFO_INPUT AddrSurfInfoIn = {0};
 	int r;
 
-	assert(!(surf->flags & RADEON_SURF_FMASK));
-
 	AddrSurfInfoIn.size = sizeof(ADDR2_COMPUTE_SURFACE_INFO_INPUT);
 
 	compressed = surf->blk_w == 4 && surf->blk_h == 4;
 
 	/* The format must be set correctly for the allocation of compressed
 	 * textures to work. In other cases, setting the bpp is sufficient. */
 	if (compressed) {
 		switch (surf->bpe) {
 		case 8:
 			AddrSurfInfoIn.format = ADDR_FMT_BC1;
@@ -1420,19 +1482,19 @@ static int gfx9_compute_surface(ADDR_HANDLE addrlib,
 	return 0;
 }
 
 int ac_compute_surface(ADDR_HANDLE addrlib, const struct radeon_info *info,
 		       const struct ac_surf_config *config,
 		       enum radeon_surf_mode mode,
 		       struct radeon_surf *surf)
 {
 	int r;
 
-	r = surf_config_sanity(config);
+	r = surf_config_sanity(config, surf->flags);
 	if (r)
 		return r;
 
 	if (info->chip_class >= GFX9)
 		return gfx9_compute_surface(addrlib, info, config, mode, surf);
 	else
 		return gfx6_compute_surface(addrlib, info, config, mode, surf);
 }
diff --git a/src/amd/common/ac_surface.h b/src/amd/common/ac_surface.h
index 37df859e6de..d0249684ad2 100644
--- a/src/amd/common/ac_surface.h
+++ b/src/amd/common/ac_surface.h
@@ -72,20 +72,30 @@ enum radeon_micro_mode {
 struct legacy_surf_level {
     uint64_t                    offset;
     uint32_t                    slice_size_dw; /* in dwords; max = 4GB / 4. */
     uint32_t                    dcc_offset; /* relative offset within DCC mip tree */
     uint32_t                    dcc_fast_clear_size;
     unsigned                    nblk_x:15;
     unsigned                    nblk_y:15;
     enum radeon_surf_mode       mode:2;
 };
 
+struct legacy_surf_fmask {
+    uint64_t size;
+    unsigned alignment;
+    unsigned tile_swizzle;
+    unsigned slice_tile_max; /* max 4M */
+    uint8_t tiling_index;    /* max 31 */
+    uint8_t bankh;           /* max 8 */
+    uint16_t pitch_in_pixels;
+};
+
 struct legacy_surf_layout {
     unsigned                    bankw:4;  /* max 8 */
     unsigned                    bankh:4;  /* max 8 */
     unsigned                    mtilea:4; /* max 8 */
     unsigned                    tile_split:13;         /* max 4K */
     unsigned                    stencil_tile_split:13; /* max 4K */
     unsigned                    pipe_config:5;      /* max 17 */
     unsigned                    num_banks:5;        /* max 16 */
     unsigned                    macro_tile_index:4; /* max 15 */
 
@@ -94,20 +104,21 @@ struct legacy_surf_layout {
      * compatibility. If either is true, the corresponding plane cannot be
      * sampled from.
      */
     unsigned                    depth_adjusted:1;
     unsigned                    stencil_adjusted:1;
 
     struct legacy_surf_level    level[RADEON_SURF_MAX_LEVELS];
     struct legacy_surf_level    stencil_level[RADEON_SURF_MAX_LEVELS];
     uint8_t                     tiling_index[RADEON_SURF_MAX_LEVELS];
     uint8_t                     stencil_tiling_index[RADEON_SURF_MAX_LEVELS];
+    struct legacy_surf_fmask    fmask;
 };
 
 /* Same as addrlib - AddrResourceType. */
 enum gfx9_resource_type {
     RADEON_RESOURCE_1D = 0,
     RADEON_RESOURCE_2D,
     RADEON_RESOURCE_3D,
 };
 
 struct gfx9_surf_flags {
@@ -215,21 +226,21 @@ struct radeon_surf {
 
 struct ac_surf_info {
 	uint32_t width;
 	uint32_t height;
 	uint32_t depth;
 	uint8_t samples;
 	uint8_t levels;
 	uint8_t num_channels; /* heuristic for displayability */
 	uint16_t array_size;
 	uint32_t *surf_index; /* Set a monotonic counter for tile swizzling. */
-	uint32_t *fmask_surf_index; /* GFX9+ */
+	uint32_t *fmask_surf_index;
 };
 
 struct ac_surf_config {
 	struct ac_surf_info info;
 	unsigned is_3d : 1;
 	unsigned is_cube : 1;
 };
 
 ADDR_HANDLE amdgpu_addr_create(const struct radeon_info *info,
 			       const struct amdgpu_gpu_info *amdinfo,
diff --git a/src/amd/vulkan/radv_image.c b/src/amd/vulkan/radv_image.c
index bfe497caa30..9df59e759aa 100644
--- a/src/amd/vulkan/radv_image.c
+++ b/src/amd/vulkan/radv_image.c
@@ -719,72 +719,34 @@ radv_init_metadata(struct radv_device *device,
 	radv_query_opaque_metadata(device, image, metadata);
 }
 
 /* The number of samples can be specified independently of the texture. */
 static void
 radv_image_get_fmask_info(struct radv_device *device,
 			  struct radv_image *image,
 			  unsigned nr_samples,
 			  struct radv_fmask_info *out)
 {
-	/* FMASK is allocated like an ordinary texture. */
-	struct radeon_surf fmask = {};
-	struct ac_surf_info info = image->info;
-	memset(out, 0, sizeof(*out));
-
 	if (device->physical_device->rad_info.chip_class >= GFX9) {
 		out->alignment = image->surface.u.gfx9.fmask_alignment;
 		out->size = image->surface.u.gfx9.fmask_size;
+		out->tile_swizzle = image->surface.u.gfx9.fmask_tile_swizzle;
 		return;
 	}
 
-	fmask.blk_w = image->surface.blk_w;
-	fmask.blk_h = image->surface.blk_h;
-	info.samples = 1;
-	fmask.flags = image->surface.flags | RADEON_SURF_FMASK;
-
-	if (!image->shareable) {
-		info.fmask_surf_index = &device->fmask_mrt_offset_counter;
-		info.surf_index = &device->fmask_mrt_offset_counter;
-	}
-
-	/* Force 2D tiling if it wasn't set. This may occur when creating
-	 * FMASK for MSAA resolve on R6xx. On R6xx, the single-sample
-	 * destination buffer must have an FMASK too. */
-	fmask.flags = RADEON_SURF_CLR(fmask.flags, MODE);
-	fmask.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
-
-	switch (nr_samples) {
-	case 2:
-	case 4:
-		fmask.bpe = 1;
-		break;
-	case 8:
-		fmask.bpe = 4;
-		break;
-	default:
-		return;
-	}
-
-	device->ws->surface_init(device->ws, &info, &fmask);
-	assert(fmask.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);
-
-	out->slice_tile_max = (fmask.u.legacy.level[0].nblk_x * fmask.u.legacy.level[0].nblk_y) / 64;
-	if (out->slice_tile_max)
-		out->slice_tile_max -= 1;
-
-	out->tile_mode_index = fmask.u.legacy.tiling_index[0];
-	out->pitch_in_pixels = fmask.u.legacy.level[0].nblk_x;
-	out->bank_height = fmask.u.legacy.bankh;
-	out->tile_swizzle = fmask.tile_swizzle;
-	out->alignment = MAX2(256, fmask.surf_alignment);
-	out->size = fmask.surf_size;
+	out->slice_tile_max = image->surface.u.legacy.fmask.slice_tile_max;
+	out->tile_mode_index = image->surface.u.legacy.fmask.tiling_index;
+	out->pitch_in_pixels = image->surface.u.legacy.fmask.pitch_in_pixels;
+	out->bank_height = image->surface.u.legacy.fmask.bankh;
+	out->tile_swizzle = image->surface.u.legacy.fmask.tile_swizzle;
+	out->alignment = image->surface.u.legacy.fmask.alignment;
+	out->size = image->surface.u.legacy.fmask.size;
 
 	assert(!out->tile_swizzle || !image->shareable);
 }
 
 static void
 radv_image_alloc_fmask(struct radv_device *device,
 		       struct radv_image *image)
 {
 	radv_image_get_fmask_info(device, image, image->info.samples, &image->fmask);
 
diff --git a/src/gallium/drivers/radeonsi/si_texture.c b/src/gallium/drivers/radeonsi/si_texture.c
index 17f87a3039b..e072fbd0b4d 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -844,68 +844,34 @@ static void si_texture_destroy(struct pipe_screen *screen,
 }
 
 static const struct u_resource_vtbl si_texture_vtbl;
 
 /* The number of samples can be specified independently of the texture. */
 void si_texture_get_fmask_info(struct si_screen *sscreen,
 			       struct r600_texture *rtex,
 			       unsigned nr_samples,
 			       struct r600_fmask_info *out)
 {
-	/* FMASK is allocated like an ordinary texture. */
-	struct pipe_resource templ = rtex->buffer.b.b;
-	struct radeon_surf fmask = {};
-	unsigned flags, bpe;
-
-	memset(out, 0, sizeof(*out));
-
 	if (sscreen->info.chip_class >= GFX9) {
 		out->alignment = rtex->surface.u.gfx9.fmask_alignment;
 		out->size = rtex->surface.u.gfx9.fmask_size;
 		out->tile_swizzle = rtex->surface.u.gfx9.fmask_tile_swizzle;
 		return;
 	}
 
-	templ.nr_samples = 1;
-	flags = rtex->surface.flags | RADEON_SURF_FMASK;
-
-	switch (nr_samples) {
-	case 2:
-	case 4:
-		bpe = 1;
-		break;
-	case 8:
-		bpe = 4;
-		break;
-	default:
-		PRINT_ERR("Invalid sample count for FMASK allocation.\n");
-		return;
-	}
-
-	if (sscreen->ws->surface_init(sscreen->ws, &templ, flags, bpe,
-				      RADEON_SURF_MODE_2D, &fmask)) {
-		PRINT_ERR("Got error in surface_init while allocating FMASK.\n");
-		return;
-	}
-
-	assert(fmask.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);
-
-	out->slice_tile_max = (fmask.u.legacy.level[0].nblk_x * fmask.u.legacy.level[0].nblk_y) / 64;
-	if (out->slice_tile_max)
-		out->slice_tile_max -= 1;
-
-	out->tile_mode_index = fmask.u.legacy.tiling_index[0];
-	out->pitch_in_pixels = fmask.u.legacy.level[0].nblk_x;
-	out->bank_height = fmask.u.legacy.bankh;
-	out->tile_swizzle = fmask.tile_swizzle;
-	out->alignment = MAX2(256, fmask.surf_alignment);
-	out->size = fmask.surf_size;
+	out->slice_tile_max = rtex->surface.u.legacy.fmask.slice_tile_max;
+	out->tile_mode_index = rtex->surface.u.legacy.fmask.tiling_index;
+	out->pitch_in_pixels = rtex->surface.u.legacy.fmask.pitch_in_pixels;
+	out->bank_height = rtex->surface.u.legacy.fmask.bankh;
+	out->tile_swizzle = rtex->surface.u.legacy.fmask.tile_swizzle;
+	out->alignment = rtex->surface.u.legacy.fmask.alignment;
+	out->size = rtex->surface.u.legacy.fmask.size;
 }
 
 static void si_texture_allocate_fmask(struct si_screen *sscreen,
 				      struct r600_texture *rtex)
 {
 	si_texture_get_fmask_info(sscreen, rtex,
 				    rtex->buffer.b.b.nr_samples, &rtex->fmask);
 
 	rtex->fmask.offset = align64(rtex->size, rtex->fmask.alignment);
 	rtex->size = rtex->fmask.offset + rtex->fmask.size;
diff --git a/src/gallium/winsys/radeon/drm/radeon_drm_surface.c b/src/gallium/winsys/radeon/drm/radeon_drm_surface.c
index 77fb7757c20..58114888966 100644
--- a/src/gallium/winsys/radeon/drm/radeon_drm_surface.c
+++ b/src/gallium/winsys/radeon/drm/radeon_drm_surface.c
@@ -236,17 +236,65 @@ static int radeon_winsys_surface_init(struct radeon_winsys *rws,
        r = radeon_surface_best(ws->surf_man, &surf_drm);
        if (r)
           return r;
     }
 
     r = radeon_surface_init(ws->surf_man, &surf_drm);
     if (r)
         return r;
 
     surf_drm_to_winsys(ws, surf_ws, &surf_drm);
+
+    /* Compute FMASK. */
+    if (ws->gen == DRV_SI &&
+        tex->nr_samples >= 2 &&
+        !(flags & (RADEON_SURF_Z_OR_SBUFFER | RADEON_SURF_FMASK))) {
+        /* FMASK is allocated like an ordinary texture. */
+        struct pipe_resource templ = *tex;
+        struct radeon_surf fmask = {};
+        unsigned fmask_flags, bpe;
+
+        templ.nr_samples = 1;
+        fmask_flags = flags | RADEON_SURF_FMASK;
+
+        switch (tex->nr_samples) {
+        case 2:
+        case 4:
+            bpe = 1;
+            break;
+        case 8:
+            bpe = 4;
+            break;
+        default:
+            fprintf(stderr, "radeon: Invalid sample count for FMASK allocation.\n");
+            return -1;
+        }
+
+        if (radeon_winsys_surface_init(rws, &templ, fmask_flags, bpe,
+                                       RADEON_SURF_MODE_2D, &fmask)) {
+            fprintf(stderr, "Got error in surface_init while allocating FMASK.\n");
+            return -1;
+        }
+
+        assert(fmask.u.legacy.level[0].mode == RADEON_SURF_MODE_2D);
+
+        surf_ws->u.legacy.fmask.size = fmask.surf_size;
+        surf_ws->u.legacy.fmask.alignment = MAX2(256, fmask.surf_alignment);
+        surf_ws->u.legacy.fmask.tile_swizzle = fmask.tile_swizzle;
+
+        surf_ws->u.legacy.fmask.slice_tile_max =
+            (fmask.u.legacy.level[0].nblk_x * fmask.u.legacy.level[0].nblk_y) / 64;
+        if (surf_ws->u.legacy.fmask.slice_tile_max)
+            surf_ws->u.legacy.fmask.slice_tile_max -= 1;
+
+        surf_ws->u.legacy.fmask.tiling_index = fmask.u.legacy.tiling_index[0];
+        surf_ws->u.legacy.fmask.bankh = fmask.u.legacy.bankh;
+        surf_ws->u.legacy.fmask.pitch_in_pixels = fmask.u.legacy.level[0].nblk_x;
+    }
+
     return 0;
 }
 
 void radeon_surface_init_functions(struct radeon_drm_winsys *ws)
 {
     ws->base.surface_init = radeon_winsys_surface_init;
 }
-- 
2.17.0



More information about the mesa-dev mailing list