[Mesa-dev] [PATCH 3/3] radeonsi: fix border color translation for integer textures

Nicolai Hähnle nhaehnle at gmail.com
Tue Sep 26 14:46:10 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

This fixes the extremely unlikely case that an application uses
0x80000000 or 0x3f800000 as border color for an integer texture and
helps in the also, but perhaps slightly less, unlikely case that 1 is
used as a border color.
---
 src/gallium/drivers/radeonsi/si_descriptors.c | 37 ++++++++++++--------
 src/gallium/drivers/radeonsi/si_pipe.h        |  2 ++
 src/gallium/drivers/radeonsi/si_state.c       | 50 +++++++++++++++++++--------
 3 files changed, 60 insertions(+), 29 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_descriptors.c b/src/gallium/drivers/radeonsi/si_descriptors.c
index 27239c25389..db77b1cb982 100644
--- a/src/gallium/drivers/radeonsi/si_descriptors.c
+++ b/src/gallium/drivers/radeonsi/si_descriptors.c
@@ -372,20 +372,34 @@ void si_set_mutable_tex_desc_fields(struct si_screen *sscreen,
 		unsigned pitch = base_level_info->nblk_x * block_width;
 		unsigned index = si_tile_mode_index(tex, base_level, is_stencil);
 
 		state[3] &= C_008F1C_TILING_INDEX;
 		state[3] |= S_008F1C_TILING_INDEX(index);
 		state[4] &= C_008F20_PITCH_GFX6;
 		state[4] |= S_008F20_PITCH_GFX6(pitch - 1);
 	}
 }
 
+static void si_set_sampler_state_desc(struct si_sampler_state *sstate,
+				      struct si_sampler_view *sview,
+				      struct r600_texture *tex,
+				      uint32_t *desc)
+{
+	if (sview && sview->is_integer)
+		memcpy(desc, sstate->integer_val, 4*4);
+	else if (tex && tex->upgraded_depth &&
+		 (!sview || !sview->is_stencil_sampler))
+		memcpy(desc, sstate->upgraded_depth_val, 4*4);
+	else
+		memcpy(desc, sstate->val, 4*4);
+}
+
 static void si_set_sampler_view_desc(struct si_context *sctx,
 				     struct si_sampler_view *sview,
 				     struct si_sampler_state *sstate,
 				     uint32_t *desc)
 {
 	struct pipe_sampler_view *view = &sview->base;
 	struct r600_texture *rtex = (struct r600_texture *)view->texture;
 	bool is_buffer = rtex->resource.b.b.target == PIPE_BUFFER;
 
 	if (unlikely(!is_buffer && sview->dcc_incompatible)) {
@@ -415,27 +429,24 @@ static void si_set_sampler_view_desc(struct si_context *sctx,
 					       is_separate_stencil,
 					       desc);
 	}
 
 	if (!is_buffer && rtex->fmask.size) {
 		memcpy(desc + 8, sview->fmask_state, 8*4);
 	} else {
 		/* Disable FMASK and bind sampler state in [12:15]. */
 		memcpy(desc + 8, null_texture_descriptor, 4*4);
 
-		if (sstate) {
-			if (!is_buffer && rtex->upgraded_depth &&
-			    !sview->is_stencil_sampler)
-				memcpy(desc + 12, sstate->upgraded_depth_val, 4*4);
-			else
-				memcpy(desc + 12, sstate->val, 4*4);
-		}
+		if (sstate)
+			si_set_sampler_state_desc(sstate, sview,
+						  is_buffer ? NULL : rtex,
+						  desc + 12);
 	}
 }
 
 static void si_set_sampler_view(struct si_context *sctx,
 				unsigned shader,
 				unsigned slot, struct pipe_sampler_view *view,
 				bool disallow_early_out)
 {
 	struct si_sampler_views *views = &sctx->samplers[shader].views;
 	struct si_sampler_view *rview = (struct si_sampler_view*)view;
@@ -463,22 +474,22 @@ static void si_set_sampler_view(struct si_context *sctx,
 		si_sampler_view_add_buffer(sctx, view->texture,
 					   RADEON_USAGE_READ,
 					   rview->is_stencil_sampler, true);
 	} else {
 		pipe_sampler_view_reference(&views->views[slot], NULL);
 		memcpy(desc, null_texture_descriptor, 8*4);
 		/* Only clear the lower dwords of FMASK. */
 		memcpy(desc + 8, null_texture_descriptor, 4*4);
 		/* Re-set the sampler state if we are transitioning from FMASK. */
 		if (views->sampler_states[slot])
-			memcpy(desc + 12,
-			       views->sampler_states[slot]->val, 4*4);
+			si_set_sampler_state_desc(views->sampler_states[slot], NULL, NULL,
+						  desc + 12);
 
 		views->enabled_mask &= ~(1u << slot);
 	}
 
 	sctx->descriptors_dirty |= 1u << si_sampler_and_image_descriptors_idx(shader);
 }
 
 static bool color_needs_decompression(struct r600_texture *rtex)
 {
 	return rtex->fmask.size ||
@@ -855,26 +866,22 @@ static void si_bind_sampler_states(struct pipe_context *ctx,
 
 		struct r600_texture *tex = NULL;
 
 		if (sview && sview->base.texture &&
 		    sview->base.texture->target != PIPE_BUFFER)
 			tex = (struct r600_texture *)sview->base.texture;
 
 		if (tex && tex->fmask.size)
 			continue;
 
-		if (tex && tex->upgraded_depth && !sview->is_stencil_sampler)
-			memcpy(desc->list + desc_slot * 16 + 12,
-			       sstates[i]->upgraded_depth_val, 4*4);
-		else
-			memcpy(desc->list + desc_slot * 16 + 12,
-			       sstates[i]->val, 4*4);
+		si_set_sampler_state_desc(sstates[i], sview, tex,
+					  desc->list + desc_slot * 16 + 12);
 
 		sctx->descriptors_dirty |= 1u << si_sampler_and_image_descriptors_idx(shader);
 	}
 }
 
 /* BUFFER RESOURCES */
 
 static void si_init_buffer_resources(struct si_buffer_resources *buffers,
 				     struct si_descriptors *descs,
 				     unsigned num_buffers,
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 80f38ea29bb..46c89e2f38a 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -150,30 +150,32 @@ struct si_blend_color {
 struct si_sampler_view {
 	struct pipe_sampler_view	base;
         /* [0..7] = image descriptor
          * [4..7] = buffer descriptor */
 	uint32_t			state[8];
 	uint32_t			fmask_state[8];
 	const struct legacy_surf_level	*base_level_info;
 	ubyte				base_level;
 	ubyte				block_width;
 	bool is_stencil_sampler;
+	bool is_integer;
 	bool dcc_incompatible;
 };
 
 #define SI_SAMPLER_STATE_MAGIC 0x34f1c35a
 
 struct si_sampler_state {
 #ifdef DEBUG
 	unsigned			magic;
 #endif
 	uint32_t			val[4];
+	uint32_t			integer_val[4];
 	uint32_t			upgraded_depth_val[4];
 };
 
 struct si_cs_shader_state {
 	struct si_compute		*program;
 	struct si_compute		*emitted_program;
 	unsigned			offset;
 	bool				initialized;
 	bool				uses_scratch;
 };
diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c
index 2a27ea0c503..75042b6dfd3 100644
--- a/src/gallium/drivers/radeonsi/si_state.c
+++ b/src/gallium/drivers/radeonsi/si_state.c
@@ -3854,20 +3854,26 @@ si_create_sampler_view_custom(struct pipe_context *ctx,
 						state->u.tex.first_level,
 						state->format);
 
 	si_make_texture_descriptor(sctx->screen, tmp, true,
 				   state->target, pipe_format, state_swizzle,
 				   first_level, last_level,
 				   state->u.tex.first_layer, last_layer,
 				   width, height, depth,
 				   view->state, view->fmask_state);
 
+	unsigned num_format = G_008F14_NUM_FORMAT_GFX6(view->state[1]);
+	view->is_integer =
+		num_format == V_008F14_IMG_NUM_FORMAT_USCALED ||
+		num_format == V_008F14_IMG_NUM_FORMAT_SSCALED ||
+		num_format == V_008F14_IMG_NUM_FORMAT_UINT ||
+		num_format == V_008F14_IMG_NUM_FORMAT_SINT;
 	view->base_level_info = &surflevel[base_level];
 	view->base_level = base_level;
 	view->block_width = util_format_get_blockwidth(pipe_format);
 	return &view->base;
 }
 
 static struct pipe_sampler_view *
 si_create_sampler_view(struct pipe_context *ctx,
 		       struct pipe_resource *texture,
 		       const struct pipe_sampler_view *state)
@@ -3890,38 +3896,50 @@ static bool wrap_mode_uses_border_color(unsigned wrap, bool linear_filter)
 {
 	return wrap == PIPE_TEX_WRAP_CLAMP_TO_BORDER ||
 	       wrap == PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER ||
 	       (linear_filter &&
 	        (wrap == PIPE_TEX_WRAP_CLAMP ||
 		 wrap == PIPE_TEX_WRAP_MIRROR_CLAMP));
 }
 
 static uint32_t si_translate_border_color(struct si_context *sctx,
 					  const struct pipe_sampler_state *state,
-					  const union pipe_color_union *color)
+					  const union pipe_color_union *color,
+					  bool is_integer)
 {
 	bool linear_filter = state->min_img_filter != PIPE_TEX_FILTER_NEAREST ||
 			     state->mag_img_filter != PIPE_TEX_FILTER_NEAREST;
 
-	if ((color->f[0] == 0 && color->f[1] == 0 &&
-	     color->f[2] == 0 && color->f[3] == 0) ||
-	    (!wrap_mode_uses_border_color(state->wrap_s, linear_filter) &&
-	     !wrap_mode_uses_border_color(state->wrap_t, linear_filter) &&
-	     !wrap_mode_uses_border_color(state->wrap_r, linear_filter)))
+	if (!wrap_mode_uses_border_color(state->wrap_s, linear_filter) &&
+	    !wrap_mode_uses_border_color(state->wrap_t, linear_filter) &&
+	    !wrap_mode_uses_border_color(state->wrap_r, linear_filter))
 		return S_008F3C_BORDER_COLOR_TYPE(V_008F3C_SQ_TEX_BORDER_COLOR_TRANS_BLACK);
 
-	if (color->f[0] == 0 && color->f[1] == 0 &&
-	    color->f[2] == 0 && color->f[3] == 1)
-		return S_008F3C_BORDER_COLOR_TYPE(V_008F3C_SQ_TEX_BORDER_COLOR_OPAQUE_BLACK);
-	if (color->f[0] == 1 && color->f[1] == 1 &&
-	    color->f[2] == 1 && color->f[3] == 1)
-		return S_008F3C_BORDER_COLOR_TYPE(V_008F3C_SQ_TEX_BORDER_COLOR_OPAQUE_WHITE);
+#define simple_border_types(elt) \
+do { \
+	if (color->elt[0] == 0 && color->elt[1] == 0 &&                         \
+	    color->elt[2] == 0 && color->elt[3] == 0)                           \
+		return S_008F3C_BORDER_COLOR_TYPE(V_008F3C_SQ_TEX_BORDER_COLOR_TRANS_BLACK); \
+	if (color->elt[0] == 0 && color->elt[1] == 0 &&                         \
+	    color->elt[2] == 0 && color->elt[3] == 1)                           \
+		return S_008F3C_BORDER_COLOR_TYPE(V_008F3C_SQ_TEX_BORDER_COLOR_OPAQUE_BLACK); \
+	if (color->elt[0] == 1 && color->elt[1] == 1 &&                         \
+	    color->elt[2] == 1 && color->elt[3] == 1)                           \
+		return S_008F3C_BORDER_COLOR_TYPE(V_008F3C_SQ_TEX_BORDER_COLOR_OPAQUE_WHITE); \
+} while (false)
+
+	if (is_integer)
+		simple_border_types(ui);
+	else
+		simple_border_types(f);
+
+#undef simple_border_types
 
 	int i;
 
 	/* Check if the border has been uploaded already. */
 	for (i = 0; i < sctx->border_color_count; i++)
 		if (memcmp(&sctx->border_color_table[i], color,
 			   sizeof(*color)) == 0)
 			break;
 
 	if (i >= SI_MAX_BORDER_COLORS) {
@@ -3977,36 +3995,40 @@ static void *si_create_sampler_state(struct pipe_context *ctx,
 			  S_008F34_MAX_LOD(S_FIXED(CLAMP(state->max_lod, 0, 15), 8)) |
 			  S_008F34_PERF_MIP(max_aniso_ratio ? max_aniso_ratio + 6 : 0));
 	rstate->val[2] = (S_008F38_LOD_BIAS(S_FIXED(CLAMP(state->lod_bias, -16, 16), 8)) |
 			  S_008F38_XY_MAG_FILTER(eg_tex_filter(state->mag_img_filter, max_aniso)) |
 			  S_008F38_XY_MIN_FILTER(eg_tex_filter(state->min_img_filter, max_aniso)) |
 			  S_008F38_MIP_FILTER(si_tex_mipfilter(state->min_mip_filter)) |
 			  S_008F38_MIP_POINT_PRECLAMP(0) |
 			  S_008F38_DISABLE_LSB_CEIL(sctx->b.chip_class <= VI) |
 			  S_008F38_FILTER_PREC_FIX(1) |
 			  S_008F38_ANISO_OVERRIDE(sctx->b.chip_class >= VI));
-	rstate->val[3] = si_translate_border_color(sctx, state, &state->border_color);
+	rstate->val[3] = si_translate_border_color(sctx, state, &state->border_color, false);
+
+	/* Create sampler resource for integer textures. */
+	memcpy(rstate->integer_val, rstate->val, sizeof(rstate->val));
+	rstate->integer_val[3] = si_translate_border_color(sctx, state, &state->border_color, true);
 
 	/* Create sampler resource for upgraded depth textures. */
 	memcpy(rstate->upgraded_depth_val, rstate->val, sizeof(rstate->val));
 
 	for (unsigned i = 0; i < 4; ++i) {
 		/* Use channel 0 on purpose, so that we can use OPAQUE_WHITE
 		 * when the border color is 1.0. */
 		clamped_border_color.f[i] = CLAMP(state->border_color.f[0], 0, 1);
 	}
 
 	if (memcmp(&state->border_color, &clamped_border_color, sizeof(clamped_border_color)) == 0)
 		rstate->upgraded_depth_val[3] |= S_008F3C_UPGRADED_DEPTH(1);
 	else
 		rstate->upgraded_depth_val[3] =
-			si_translate_border_color(sctx, state, &clamped_border_color) |
+			si_translate_border_color(sctx, state, &clamped_border_color, false) |
 			S_008F3C_UPGRADED_DEPTH(1);
 
 	return rstate;
 }
 
 static void si_set_sample_mask(struct pipe_context *ctx, unsigned sample_mask)
 {
 	struct si_context *sctx = (struct si_context *)ctx;
 
 	if (sctx->sample_mask.sample_mask == (uint16_t)sample_mask)
-- 
2.11.0



More information about the mesa-dev mailing list