summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>2020-04-24 11:58:12 +0200
committerMarge Bot <eric+marge@anholt.net>2020-05-05 09:41:14 +0000
commit64662dd5baeec19a618156b52df7a7e7adba94cf (patch)
tree0b5a37062667688298a5dbe0032b4f43a05a586e
parent7983d97174de10670fce5a422ce6c1cb5e783b88 (diff)
radeonsi: add workaround for issue 2647
For unknown reasons pixel shaders in KSP game get executed with infinite interpolation coefficients and this causes an infinite loop in the shader. This commit adds a hacky workaround that kills pixel shaders if invalid interp coeffs are detected and enables it for KSP. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/2174 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/2647 Reviewed-by: Marek Olšák <marek.olsak@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4700>
-rw-r--r--src/amd/llvm/ac_nir_to_llvm.c26
-rw-r--r--src/amd/llvm/ac_shader_abi.h3
-rw-r--r--src/gallium/drivers/radeonsi/si_debug_options.h1
-rw-r--r--src/gallium/drivers/radeonsi/si_pipe.c7
-rw-r--r--src/gallium/drivers/radeonsi/si_pipe.h1
-rw-r--r--src/gallium/drivers/radeonsi/si_shader_llvm.c7
-rw-r--r--src/util/00-mesa-defaults.conf4
7 files changed, 45 insertions, 4 deletions
diff --git a/src/amd/llvm/ac_nir_to_llvm.c b/src/amd/llvm/ac_nir_to_llvm.c
index 2a495eb76e4..42cd952b69f 100644
--- a/src/amd/llvm/ac_nir_to_llvm.c
+++ b/src/amd/llvm/ac_nir_to_llvm.c
@@ -51,6 +51,7 @@ struct ac_nir_context {
struct hash_table *defs;
struct hash_table *phis;
struct hash_table *vars;
+ struct hash_table *verified_interp;
LLVMValueRef main_function;
LLVMBasicBlockRef continue_block;
@@ -3511,13 +3512,26 @@ static LLVMValueRef load_interpolated_input(struct ac_nir_context *ctx,
unsigned bitsize)
{
LLVMValueRef attr_number = LLVMConstInt(ctx->ac.i32, index, false);
+ LLVMValueRef interp_param_f;
- interp_param = LLVMBuildBitCast(ctx->ac.builder,
+ interp_param_f = LLVMBuildBitCast(ctx->ac.builder,
interp_param, ctx->ac.v2f32, "");
LLVMValueRef i = LLVMBuildExtractElement(
- ctx->ac.builder, interp_param, ctx->ac.i32_0, "");
+ ctx->ac.builder, interp_param_f, ctx->ac.i32_0, "");
LLVMValueRef j = LLVMBuildExtractElement(
- ctx->ac.builder, interp_param, ctx->ac.i32_1, "");
+ ctx->ac.builder, interp_param_f, ctx->ac.i32_1, "");
+
+ /* Workaround for issue 2647: kill threads with infinite interpolation coeffs */
+ if (ctx->verified_interp &&
+ !_mesa_hash_table_search(ctx->verified_interp, interp_param)) {
+ LLVMValueRef args[2];
+ args[0] = i;
+ args[1] = LLVMConstInt(ctx->ac.i32, S_NAN | Q_NAN | N_INFINITY | P_INFINITY, false);
+ LLVMValueRef cond = ac_build_intrinsic(&ctx->ac, "llvm.amdgcn.class.f32", ctx->ac.i1,
+ args, 2, AC_FUNC_ATTR_READNONE);
+ ac_build_kill_if_false(&ctx->ac, LLVMBuildNot(ctx->ac.builder, cond, ""));
+ _mesa_hash_table_insert(ctx->verified_interp, interp_param, interp_param);
+ }
LLVMValueRef values[4];
assert(bitsize == 16 || bitsize == 32);
@@ -5253,6 +5267,10 @@ void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
ctx.vars = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
+ if (ctx.abi->kill_ps_if_inf_interp)
+ ctx.verified_interp = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
func = (struct nir_function *)exec_list_get_head(&nir->functions);
nir_index_ssa_defs(func->impl);
@@ -5287,6 +5305,8 @@ void ac_nir_translate(struct ac_llvm_context *ac, struct ac_shader_abi *abi,
ralloc_free(ctx.defs);
ralloc_free(ctx.phis);
ralloc_free(ctx.vars);
+ if (ctx.abi->kill_ps_if_inf_interp)
+ ralloc_free(ctx.verified_interp);
}
bool
diff --git a/src/amd/llvm/ac_shader_abi.h b/src/amd/llvm/ac_shader_abi.h
index 18f85a7911c..ea3717413d2 100644
--- a/src/amd/llvm/ac_shader_abi.h
+++ b/src/amd/llvm/ac_shader_abi.h
@@ -186,6 +186,9 @@ struct ac_shader_abi {
/* Whether bounds checks are required */
bool robust_buffer_access;
+
+ /* Check for Inf interpolation coeff */
+ bool kill_ps_if_inf_interp;
};
#endif /* AC_SHADER_ABI_H */
diff --git a/src/gallium/drivers/radeonsi/si_debug_options.h b/src/gallium/drivers/radeonsi/si_debug_options.h
index 83c7425e094..bf4329ad803 100644
--- a/src/gallium/drivers/radeonsi/si_debug_options.h
+++ b/src/gallium/drivers/radeonsi/si_debug_options.h
@@ -7,5 +7,6 @@ OPT_BOOL(halt_shaders, false, "Halt shaders at the start (will hang)")
OPT_BOOL(vs_fetch_always_opencode, false,
"Always open code vertex fetches (less efficient, purely for testing)")
OPT_BOOL(prim_restart_tri_strips_only, false, "Only enable primitive restart for triangle strips")
+OPT_BOOL(no_infinite_interp, false, "Kill PS with infinite interp coeff")
#undef OPT_BOOL
diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c
index 86511428376..f3457924e77 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.c
+++ b/src/gallium/drivers/radeonsi/si_pipe.c
@@ -67,6 +67,7 @@ static const struct debug_named_value debug_options[] = {
{"w64ge", DBG(W64_GE), "Use Wave64 for vertex, tessellation, and geometry shaders."},
{"w64ps", DBG(W64_PS), "Use Wave64 for pixel shaders."},
{"w64cs", DBG(W64_CS), "Use Wave64 for computes shaders."},
+ {"noinfinterp", DBG(KILL_PS_INF_INTERP), "Kill PS with infinite interp coeff"},
/* Shader compiler options (with no effect on the shader cache): */
{"checkir", DBG(CHECK_IR), "Enable additional sanity checks on shader IR"},
@@ -879,7 +880,7 @@ static void si_disk_cache_create(struct si_screen *sscreen)
disk_cache_format_hex_id(cache_id, sha1, 20 * 2);
/* These flags affect shader compilation. */
-#define ALL_FLAGS (DBG(GISEL))
+#define ALL_FLAGS (DBG(GISEL) | DBG(KILL_PS_INF_INTERP))
uint64_t shader_debug_flags = sscreen->debug_flags & ALL_FLAGS;
/* Add the high bits of 32-bit addresses, which affects
@@ -996,6 +997,10 @@ static struct pipe_screen *radeonsi_screen_create_impl(struct radeon_winsys *ws,
#include "si_debug_options.h"
}
+ if (sscreen->options.no_infinite_interp) {
+ sscreen->debug_flags |= DBG(KILL_PS_INF_INTERP);
+ }
+
si_disk_cache_create(sscreen);
/* Determine the number of shader compiler threads. */
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index e4104cf8d78..6b934c1dff4 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -160,6 +160,7 @@ enum
DBG_W64_GE,
DBG_W64_PS,
DBG_W64_CS,
+ DBG_KILL_PS_INF_INTERP,
/* Shader compiler options (with no effect on the shader cache): */
DBG_CHECK_IR,
diff --git a/src/gallium/drivers/radeonsi/si_shader_llvm.c b/src/gallium/drivers/radeonsi/si_shader_llvm.c
index b510b637788..d26b80423fd 100644
--- a/src/gallium/drivers/radeonsi/si_shader_llvm.c
+++ b/src/gallium/drivers/radeonsi/si_shader_llvm.c
@@ -441,6 +441,13 @@ bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *nir)
ctx->abi.interp_at_sample_force_center =
ctx->shader->key.mono.u.ps.interpolate_at_sample_force_center;
+
+ ctx->abi.kill_ps_if_inf_interp =
+ (ctx->screen->debug_flags & DBG(KILL_PS_INF_INTERP)) &&
+ (ctx->shader->selector->info.uses_persp_center ||
+ ctx->shader->selector->info.uses_persp_centroid ||
+ ctx->shader->selector->info.uses_persp_sample);
+
} else if (nir->info.stage == MESA_SHADER_COMPUTE) {
if (nir->info.cs.user_data_components_amd) {
ctx->abi.user_data = ac_get_arg(&ctx->ac, ctx->cs_user_data);
diff --git a/src/util/00-mesa-defaults.conf b/src/util/00-mesa-defaults.conf
index d2a82b2a19a..acda91f6c78 100644
--- a/src/util/00-mesa-defaults.conf
+++ b/src/util/00-mesa-defaults.conf
@@ -629,6 +629,10 @@ TODO: document the other workarounds.
<application name="Peace, Death!" executable="runner" sha1="5b909f3d21799773370adf084f649848f098234e">
<option name="radeonsi_sync_compile" value="true" />
</application>
+ <!-- https://gitlab.freedesktop.org/mesa/mesa/issues/2647 -->
+ <application name="Kerbal Space Program" executable="KSP.x86_64">
+ <option name="radeonsi_no_infinite_interp" value="true" />
+ </application>
</device>
<device driver="virtio_gpu">
<!-- Some Valve games do a final blit to a BRGA_sRGB surface. On a GLES