Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: On Mon, Jul 7, 2014 at 6:57 AM, Abdiel Janulgue abdiel.janul...@linux.intel.com wrote: v2: Check that the base type is float (Ian Romanick) Signed-off-by: Abdiel Janulgue abdiel.janul...@linux.intel.com --- src/glsl/opt_algebraic.cpp | 34 ++ 1 file changed, 34 insertions(+) diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index ac7514a..2ad561c 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -614,6 +614,40 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) break; + case ir_binop_min: + case ir_binop_max: + if (ir-type-base_type != GLSL_TYPE_FLOAT) + break; + /* Replace min(max) operations and its commutative combinations with + * a saturate operation + */ + for (int op = 0; op 2; op++) { + ir_expression *minmax = op_expr[op]; + ir_constant *outer_const = op_const[(op == 0) ? 1 : 0]; We use (1 - op) in other places in opt_algebraic. (Same comment below) + ir_expression_operation op_cond = (ir-operation == ir_binop_max) ? +ir_binop_min : ir_binop_max; + + if (!minmax || !outer_const || (minmax-operation != op_cond)) +continue; + + /* Found a min/max operation. Now try to see if its operands + * meet our conditions that we can do just a single saturate operation + */ + for (int minmax_op = 0; minmax_op 2; minmax_op++) { +ir_rvalue *inner_val_a = minmax-operands[minmax_op]; +ir_rvalue *inner_val_b = minmax-operands[(minmax_op == 0) ? 1 : 0]; + +if (!inner_val_a || !inner_val_b) + continue; + +/* Found a min (max(x, 0), 1.0) */ This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
On Mon, Jul 7, 2014 at 11:00 PM, Erik Faye-Lund kusmab...@gmail.com wrote: On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? Under standard IEEE rules, wouldn't the NaN propagate through all of these expressions? The GLSL 4.40 spec says Operations and built-in functions that operate on a NaN are not required to return a NaN as the result. So it seems like we have a lot of flexibility here. Is there some text I'm missing? ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
On Tue, Jul 8, 2014 at 8:22 AM, Matt Turner matts...@gmail.com wrote: On Mon, Jul 7, 2014 at 11:00 PM, Erik Faye-Lund kusmab...@gmail.com wrote: On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? Under standard IEEE rules, wouldn't the NaN propagate through all of these expressions? The GLSL 4.40 spec says Operations and built-in functions that operate on a NaN are not required to return a NaN as the result. So it seems like we have a lot of flexibility here. Is there some text I'm missing? I think the point about flexibility is a bit weak or even misunderstood: surely this applies to the built-ins used, not what we generate after optimizing. So if we chose to do that, we'd need to prevent min and max from propagating NaN even when issued stand-alone, which might negatively impact performance in some ISAs. As to why I reacted, I was just remembering that I read somewhere (one of Humus' low-level shader optimization paper, IIRC) that the HLSL compiler refused to do some similar optimizations for NaN-reasons. Checking the spec a bit closer, though: - min(x, y) is defined as Returns y if y x, otherwise it returns x - max(x, y) is defined as Returns y if x y, otherwise it returns x. All comparisons with NaN should AFAIK fail, making both the first and second comparison return NaN, if NaN were to be properly supported. So my initial analysis was wrong. However, all of the following permutations of the same logic would still be inconsistent. min(max(0.0, x), 1.0) max(min(1.0, x), 0.0) min(1.0, max(0.0, x)) max(0.0, min(1.0, x)) min(1.0, max(x, 0.0)) max(0.0, min(x, 1.0)) I don't understand the code well enough to figure out if the patch optimizes these, though. ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
On 08.07.2014 09:47, Erik Faye-Lund wrote: On Tue, Jul 8, 2014 at 8:22 AM, Matt Turner matts...@gmail.com wrote: On Mon, Jul 7, 2014 at 11:00 PM, Erik Faye-Lund kusmab...@gmail.com wrote: On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? Under standard IEEE rules, wouldn't the NaN propagate through all of these expressions? The GLSL 4.40 spec says Operations and built-in functions that operate on a NaN are not required to return a NaN as the result. So it seems like we have a lot of flexibility here. Is there some text I'm missing? I think the point about flexibility is a bit weak or even misunderstood: surely this applies to the built-ins used, not what we generate after optimizing. So if we chose to do that, we'd need to prevent min and max from propagating NaN even when issued stand-alone, which might negatively impact performance in some ISAs. As to why I reacted, I was just remembering that I read somewhere (one of Humus' low-level shader optimization paper, IIRC) that the HLSL compiler refused to do some similar optimizations for NaN-reasons. Checking the spec a bit closer, though: - min(x, y) is defined as Returns y if y x, otherwise it returns x - max(x, y) is defined as Returns y if x y, otherwise it returns x. All comparisons with NaN should AFAIK fail, making both the first and second comparison return NaN, if NaN were to be properly supported. So my initial analysis was wrong. However, all of the following permutations of the same logic would still be inconsistent. min(max(0.0, x), 1.0) max(min(1.0, x), 0.0) min(1.0, max(0.0, x)) max(0.0, min(1.0, x)) min(1.0, max(x, 0.0)) max(0.0, min(x, 1.0)) I don't understand the code well enough to figure out if the patch optimizes these, though. The code actually goes through all 8 commutative variations and tries to optimize if it spots one of these conditions. ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
Am 08.07.2014 08:22, schrieb Matt Turner: On Mon, Jul 7, 2014 at 11:00 PM, Erik Faye-Lund kusmab...@gmail.com wrote: On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? Under standard IEEE rules, wouldn't the NaN propagate through all of these expressions? not under ieee754-2008 rules, no. min/max return the other number if one of them is a NaN. This is enforced by d3d10 so at least d3d10 capable hardware is going to honor that. http://msdn.microsoft.com/en-us/library/windows/desktop/cc308050%28v=vs.85%29.aspx The order of min/max though indeed matters. The GLSL 4.40 spec says Operations and built-in functions that operate on a NaN are not required to return a NaN as the result. So it seems like we have a lot of flexibility here. Is there some text I'm missing? ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
On Tue, Jul 8, 2014 at 5:44 PM, Roland Scheidegger srol...@vmware.com wrote: Am 08.07.2014 08:22, schrieb Matt Turner: On Mon, Jul 7, 2014 at 11:00 PM, Erik Faye-Lund kusmab...@gmail.com wrote: On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? Under standard IEEE rules, wouldn't the NaN propagate through all of these expressions? not under ieee754-2008 rules, no. min/max return the other number if one of them is a NaN. I'm not entirely sure what IEEE754-2008 has to say about min/max, as GLSL already defines those operations (and states that IEEE754 compliance isn't required). I was referring to the definition of the less-than comparison-operator, which GLSL seems to lean on. And that seems to always evaluate to 'false'. This is enforced by d3d10 so at least d3d10 capable hardware is going to honor that. http://msdn.microsoft.com/en-us/library/windows/desktop/cc308050%28v=vs.85%29.aspx The order of min/max though indeed matters. Right, this is very useful information, thanks. This makes me think that the perhaps the dependence on the less-than definition could be considered a spec-bug. A quick test reveals that NVIDIA's Windows driver implement both min(0.5, NaN) and min(NaN, 0.5) as returning 0.5. So I'd say: raise an issue with Khronos, and implement DX10 rules. ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
Am 08.07.2014 18:03, schrieb Erik Faye-Lund: On Tue, Jul 8, 2014 at 5:44 PM, Roland Scheidegger srol...@vmware.com wrote: Am 08.07.2014 08:22, schrieb Matt Turner: On Mon, Jul 7, 2014 at 11:00 PM, Erik Faye-Lund kusmab...@gmail.com wrote: On Mon, Jul 7, 2014 at 7:18 PM, Matt Turner matts...@gmail.com wrote: This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Hmm, but are optimizing both of these to saturate OK? Shouldn't min(max(NaN, 0.0), 1.0) give 0.0, whereas max(min(NaN, 1.0), 0.0) give 1.0? Under standard IEEE rules, wouldn't the NaN propagate through all of these expressions? not under ieee754-2008 rules, no. min/max return the other number if one of them is a NaN. I'm not entirely sure what IEEE754-2008 has to say about min/max, as GLSL already defines those operations (and states that IEEE754 compliance isn't required). I was referring to the definition of the less-than comparison-operator, which GLSL seems to lean on. And that seems to always evaluate to 'false'. Oh right I didn't notice min/max are defined that way. I guess that's due to older specs - pre glsl 4 NaN support wasn't really required and just about anything involving NaNs or Infs was ok to give undefined results anyway (and some hw indeed didn't have NaN support). Even current glsl version is not very strict there, still saying things like NaNs are not required to be generated and Operations and built-in functions that operate on a NaN are not required to return a NaN as the result. I am not entirely sure why the spec wasn't tightened up a bit, but maybe some glsl 4+ capable hw exists which doesn't implement d3d10 rules. This is enforced by d3d10 so at least d3d10 capable hardware is going to honor that. https://urldefense.proofpoint.com/v1/url?u=http://msdn.microsoft.com/en-us/library/windows/desktop/cc308050%28v%3Dvs.85%29.aspxk=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0Ar=F4msKE2WxRzA%2BwN%2B25muztFm5TSPwE8HKJfWfR2NgfY%3D%0Am=9dVgmTYumlj5DwQp2o0tjv4fTQpBhA%2FCDiMURzjOadM%3D%0As=f153cbe35b73f7fdb09fc50f8cfab56651bf346257838bc32ad35a721110fe67 The order of min/max though indeed matters. Right, this is very useful information, thanks. This makes me think that the perhaps the dependence on the less-than definition could be considered a spec-bug. A quick test reveals that NVIDIA's Windows driver implement both min(0.5, NaN) and min(NaN, 0.5) as returning 0.5. So I'd say: raise an issue with Khronos, and implement DX10 rules I agree that this looks like a bug, at the very least (given the very lax NaN requirements in general) I think it should allow the d3d10 result if it doesn't do already (it is not obvious to me if the glsl less-than operator really needs to adhere to ieee754 spec wrt NaNs). Roland ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
[Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
v2: Check that the base type is float (Ian Romanick) Signed-off-by: Abdiel Janulgue abdiel.janul...@linux.intel.com --- src/glsl/opt_algebraic.cpp | 34 ++ 1 file changed, 34 insertions(+) diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index ac7514a..2ad561c 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -614,6 +614,40 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) break; + case ir_binop_min: + case ir_binop_max: + if (ir-type-base_type != GLSL_TYPE_FLOAT) + break; + /* Replace min(max) operations and its commutative combinations with + * a saturate operation + */ + for (int op = 0; op 2; op++) { + ir_expression *minmax = op_expr[op]; + ir_constant *outer_const = op_const[(op == 0) ? 1 : 0]; + ir_expression_operation op_cond = (ir-operation == ir_binop_max) ? +ir_binop_min : ir_binop_max; + + if (!minmax || !outer_const || (minmax-operation != op_cond)) +continue; + + /* Found a min/max operation. Now try to see if its operands + * meet our conditions that we can do just a single saturate operation + */ + for (int minmax_op = 0; minmax_op 2; minmax_op++) { +ir_rvalue *inner_val_a = minmax-operands[minmax_op]; +ir_rvalue *inner_val_b = minmax-operands[(minmax_op == 0) ? 1 : 0]; + +if (!inner_val_a || !inner_val_b) + continue; + +/* Found a min (max(x, 0), 1.0) */ +if (outer_const-is_one() inner_val_a-is_zero()) + return saturate(inner_val_b); + } + } + + break; + case ir_unop_rcp: if (op_expr[0] op_expr[0]-operation == ir_unop_rcp) return op_expr[0]-operands[0]; -- 1.9.1 ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [v2 PATCH 09/16] glsl: Optimize clamp(x, 0, 1) as saturate(x)
On Mon, Jul 7, 2014 at 6:57 AM, Abdiel Janulgue abdiel.janul...@linux.intel.com wrote: v2: Check that the base type is float (Ian Romanick) Signed-off-by: Abdiel Janulgue abdiel.janul...@linux.intel.com --- src/glsl/opt_algebraic.cpp | 34 ++ 1 file changed, 34 insertions(+) diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp index ac7514a..2ad561c 100644 --- a/src/glsl/opt_algebraic.cpp +++ b/src/glsl/opt_algebraic.cpp @@ -614,6 +614,40 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) break; + case ir_binop_min: + case ir_binop_max: + if (ir-type-base_type != GLSL_TYPE_FLOAT) + break; + /* Replace min(max) operations and its commutative combinations with + * a saturate operation + */ + for (int op = 0; op 2; op++) { + ir_expression *minmax = op_expr[op]; + ir_constant *outer_const = op_const[(op == 0) ? 1 : 0]; We use (1 - op) in other places in opt_algebraic. (Same comment below) + ir_expression_operation op_cond = (ir-operation == ir_binop_max) ? +ir_binop_min : ir_binop_max; + + if (!minmax || !outer_const || (minmax-operation != op_cond)) +continue; + + /* Found a min/max operation. Now try to see if its operands + * meet our conditions that we can do just a single saturate operation + */ + for (int minmax_op = 0; minmax_op 2; minmax_op++) { +ir_rvalue *inner_val_a = minmax-operands[minmax_op]; +ir_rvalue *inner_val_b = minmax-operands[(minmax_op == 0) ? 1 : 0]; + +if (!inner_val_a || !inner_val_b) + continue; + +/* Found a min (max(x, 0), 1.0) */ This comment tripped me up for a second. This really means that you've found either - min(max(x, 0.0), 1.0); or - max(min(x, 1.0), 0.0) Change the comment to something that says either of these are acceptable. (Also make the spacing consistent. There's a space after the min. And Make the floating point literals consistent with .0 on both) ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev