radv: fix passing clip distances from VS to FS

Submitted by Samuel Pitoiset on Aug. 29, 2018, 6:59 p.m.

Details

Message ID 20180829185910.4531-1-samuel.pitoiset@gmail.com
State New
Headers show
Series "radv: fix passing clip distances from VS to FS" ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Samuel Pitoiset Aug. 29, 2018, 6:59 p.m.
CTS doesn't test input clip distances with the fragment shader
stage, which explains why it was broken. I wrote a simple test
locally that does pass now. I'm quite sure that cull distances
are broken as well but that can be fixed later.

This fixes a crash with GTA V and DXVK.

Cc: mesa-stable@lists.freedesktop.org
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107477
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
---
 src/amd/vulkan/radv_nir_to_llvm.c | 41 ++++++++++++++++++++++++++++---
 src/amd/vulkan/radv_pipeline.c    | 15 +++++++++++
 src/amd/vulkan/radv_shader.h      |  1 +
 src/amd/vulkan/radv_shader_info.c | 11 +++++++++
 4 files changed, 65 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/amd/vulkan/radv_nir_to_llvm.c b/src/amd/vulkan/radv_nir_to_llvm.c
index 4940e3230f..80d991c904 100644
--- a/src/amd/vulkan/radv_nir_to_llvm.c
+++ b/src/amd/vulkan/radv_nir_to_llvm.c
@@ -2098,9 +2098,10 @@  handle_fs_input_decl(struct radv_shader_context *ctx,
 	int idx = variable->data.location;
 	unsigned attrib_count = glsl_count_attribute_slots(variable->type, false);
 	LLVMValueRef interp = NULL;
+	uint64_t mask;
 
 	variable->data.driver_location = idx * 4;
-	ctx->input_mask |= ((1ull << attrib_count) - 1) << variable->data.location;
+	mask = ((1ull << attrib_count) - 1) << variable->data.location;
 
 	if (glsl_get_base_type(glsl_without_array(variable->type)) == GLSL_TYPE_FLOAT) {
 		unsigned interp_type;
@@ -2121,6 +2122,16 @@  handle_fs_input_decl(struct radv_shader_context *ctx,
 	for (unsigned i = 0; i < attrib_count; ++i)
 		ctx->inputs[ac_llvm_reg_index_soa(idx + i, 0)] = interp;
 
+	if (idx == VARYING_SLOT_CLIP_DIST0) {
+		/* Do not account for the number of attribute slots because
+		 * we only want to know if clip distances are present.
+		 */
+		mask = 1ull << VARYING_SLOT_CLIP_DIST0;
+		if (attrib_count > 4)
+			mask |= 1ull << VARYING_SLOT_CLIP_DIST1;
+	}
+
+	ctx->input_mask |= mask;
 }
 
 static void
@@ -2179,7 +2190,8 @@  handle_fs_inputs(struct radv_shader_context *ctx,
 			continue;
 
 		if (i >= VARYING_SLOT_VAR0 || i == VARYING_SLOT_PNTC ||
-		    i == VARYING_SLOT_PRIMITIVE_ID || i == VARYING_SLOT_LAYER) {
+		    i == VARYING_SLOT_PRIMITIVE_ID || i == VARYING_SLOT_LAYER ||
+		    i == VARYING_SLOT_CLIP_DIST0 || i == VARYING_SLOT_CLIP_DIST1) {
 			interp_param = *inputs;
 			interp_fs_input(ctx, index, interp_param, ctx->abi.prim_mask,
 					inputs);
@@ -2238,7 +2250,21 @@  scan_shader_output_decl(struct radv_shader_context *ctx,
 				attrib_count = 2;
 			else
 				attrib_count = 1;
-			mask_attribs = 1ull << idx;
+
+			mask_attribs = 1ull << VARYING_SLOT_CLIP_DIST0;
+
+			/* Use CLIP_DIST1 when the number of components is > 4
+			 * because we have to export two parameters. Also it's
+			 * only for VS->PS because other stages don't need it.
+			 */
+			if (((stage == MESA_SHADER_VERTEX &&
+			     !ctx->options->key.vs.as_ls &&
+			     !ctx->options->key.vs.as_es &&
+			     !ctx->is_gs_copy_shader) ||
+			    (stage == MESA_SHADER_TESS_EVAL &&
+			     !ctx->options->key.tes.as_es)) &&
+			    shader->info.clip_distance_array_size > 4)
+				mask_attribs |= 1ull << VARYING_SLOT_CLIP_DIST1;
 		}
 	}
 
@@ -2569,6 +2595,8 @@  handle_vs_outputs_post(struct radv_shader_context *ctx,
 
 		if (i != VARYING_SLOT_LAYER &&
 		    i != VARYING_SLOT_PRIMITIVE_ID &&
+		    i != VARYING_SLOT_CLIP_DIST0 &&
+		    i != VARYING_SLOT_CLIP_DIST1 &&
 		    i < VARYING_SLOT_VAR0)
 			continue;
 
@@ -2590,6 +2618,13 @@  handle_vs_outputs_post(struct radv_shader_context *ctx,
 				ctx->shader_info->info.gs.output_usage_mask[i];
 		}
 
+		if (i == VARYING_SLOT_CLIP_DIST0 ||
+		    i == VARYING_SLOT_CLIP_DIST1) {
+			/* The output usage mask is wrong for clip distances.
+			 * Use all channels. */
+			output_usage_mask = 0xf;
+		}
+
 		radv_export_param(ctx, param_count, values, output_usage_mask);
 
 		outinfo->vs_output_param_offset[i] = param_count++;
diff --git a/src/amd/vulkan/radv_pipeline.c b/src/amd/vulkan/radv_pipeline.c
index e63c481d1e..21a8b0c5e9 100644
--- a/src/amd/vulkan/radv_pipeline.c
+++ b/src/amd/vulkan/radv_pipeline.c
@@ -3052,6 +3052,21 @@  radv_pipeline_generate_ps_inputs(struct radeon_cmdbuf *cs,
 		ps_offset++;
 	}
 
+	if (ps->info.info.ps.has_clipdist) {
+		unsigned vs_offset = outinfo->vs_output_param_offset[VARYING_SLOT_CLIP_DIST0];
+
+		if (vs_offset != AC_EXP_PARAM_UNDEFINED) {
+			ps_input_cntl[ps_offset] = offset_to_ps_input(vs_offset, true);
+			++ps_offset;
+		}
+
+		vs_offset = outinfo->vs_output_param_offset[VARYING_SLOT_CLIP_DIST1];
+		if (vs_offset != AC_EXP_PARAM_UNDEFINED) {
+			ps_input_cntl[ps_offset] = offset_to_ps_input(vs_offset, true);
+			++ps_offset;
+		}
+	}
+
 	for (unsigned i = 0; i < 32 && (1u << i) <= ps->info.fs.input_mask; ++i) {
 		unsigned vs_offset;
 		bool flat_shade;
diff --git a/src/amd/vulkan/radv_shader.h b/src/amd/vulkan/radv_shader.h
index 03760b689c..c60185cd93 100644
--- a/src/amd/vulkan/radv_shader.h
+++ b/src/amd/vulkan/radv_shader.h
@@ -174,6 +174,7 @@  struct radv_shader_info {
 		bool has_pcoord;
 		bool prim_id_input;
 		bool layer_input;
+		bool has_clipdist;
 	} ps;
 	struct {
 		bool uses_grid_size;
diff --git a/src/amd/vulkan/radv_shader_info.c b/src/amd/vulkan/radv_shader_info.c
index 8026cca46c..a9b36d8ba8 100644
--- a/src/amd/vulkan/radv_shader_info.c
+++ b/src/amd/vulkan/radv_shader_info.c
@@ -127,6 +127,14 @@  gather_intrinsic_store_deref_info(const nir_shader *nir,
 		unsigned comp = var->data.location_frac;
 		unsigned const_offset = 0;
 
+		if (idx == VARYING_SLOT_CLIP_DIST0 ||
+		    idx == VARYING_SLOT_CLIP_DIST1) {
+			/* FIXME: Gathering the output usage mask for clip distances
+			 * is currently broken, we will always use 0xf.
+			 */
+			return;
+		}
+
 		get_deref_offset(nir_instr_as_deref(instr->src[0].ssa->parent_instr), &const_offset);
 
 		switch (nir->info.stage) {
@@ -354,6 +362,9 @@  gather_info_input_decl_ps(const nir_shader *nir, const nir_variable *var,
 	case VARYING_SLOT_LAYER:
 		info->ps.layer_input = true;
 		break;
+	case VARYING_SLOT_CLIP_DIST0:
+		info->ps.has_clipdist = true;
+		break;
 	default:
 		break;
 	}