summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Olšák <marek.olsak@amd.com>2015-10-10 22:05:58 +0200
committerMarek Olšák <marek.olsak@amd.com>2015-10-17 21:40:03 +0200
commit529c5e77402012aa0c0a11ee71a1a65e51edb496 (patch)
tree9f77a16ce5121379847fef4beb465e97a38d5a53
parenta2197cac7fd6ce3f897a89121f5e499d28a3888e (diff)
gallivm: implement the correct version of LRP
The previous version has precision issues. This can be a problem with tessellation. Sadly, I can't find the article where I read it anymore. I'm not sure if the unsafe-fp-math flag would be enough to revert this. v2: added the comment
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
index 0ad78b0ace2..3d5e2cb316b 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_action.c
@@ -538,12 +538,19 @@ lrp_emit(
struct lp_build_tgsi_context * bld_base,
struct lp_build_emit_data * emit_data)
{
- LLVMValueRef tmp;
- tmp = lp_build_emit_llvm_binary(bld_base, TGSI_OPCODE_SUB,
- emit_data->args[1],
- emit_data->args[2]);
- emit_data->output[emit_data->chan] = lp_build_emit_llvm_ternary(bld_base,
- TGSI_OPCODE_MAD, emit_data->args[0], tmp, emit_data->args[2]);
+ struct lp_build_context *bld = &bld_base->base;
+ LLVMValueRef inv, a, b;
+
+ /* This uses the correct version: (1 - t)*a + t*b
+ *
+ * An alternative version is "a + t*(b-a)". The problem is this version
+ * doesn't return "b" for t = 1, because "a + (b-a)" isn't equal to "b"
+ * because of the floating-point rounding.
+ */
+ inv = lp_build_sub(bld, bld_base->base.one, emit_data->args[0]);
+ a = lp_build_mul(bld, emit_data->args[1], emit_data->args[0]);
+ b = lp_build_mul(bld, emit_data->args[2], inv);
+ emit_data->output[emit_data->chan] = lp_build_add(bld, a, b);
}
/* TGSI_OPCODE_MAD */