[Mesa-dev] [PATCH 1/6] glsl: Optimize pow(x, 2) into x * x.
Ian Romanick
idr at freedesktop.org
Wed Mar 12 13:50:05 PDT 2014
On 03/12/2014 01:29 AM, Erik Faye-Lund wrote:
> On Wed, Mar 12, 2014 at 1:32 AM, Eric Anholt <eric at anholt.net> wrote:
>> Erik Faye-Lund <kusmabite at gmail.com> writes:
>>
>>> On Wed, Mar 12, 2014 at 12:00 AM, Eric Anholt <eric at anholt.net> wrote:
>>>> Erik Faye-Lund <kusmabite at gmail.com> writes:
>>>>
>>>>> On Tue, Mar 11, 2014 at 7:27 PM, Eric Anholt <eric at anholt.net> wrote:
>>>>>> Erik Faye-Lund <kusmabite at gmail.com> writes:
>>>>>>
>>>>>>> On Tue, Mar 11, 2014 at 2:50 PM, Erik Faye-Lund <kusmabite at gmail.com> wrote:
>>>>>>>> On Mon, Mar 10, 2014 at 11:54 PM, Matt Turner <mattst88 at gmail.com> wrote:
>>>>>>>>> Cuts two instructions out of SynMark's Gl32VSInstancing benchmark.
>>>>>>>>> ---
>>>>>>>>> src/glsl/opt_algebraic.cpp | 8 ++++++++
>>>>>>>>> 1 file changed, 8 insertions(+)
>>>>>>>>>
>>>>>>>>> diff --git a/src/glsl/opt_algebraic.cpp b/src/glsl/opt_algebraic.cpp
>>>>>>>>> index 5c49a78..8494bd9 100644
>>>>>>>>> --- a/src/glsl/opt_algebraic.cpp
>>>>>>>>> +++ b/src/glsl/opt_algebraic.cpp
>>>>>>>>> @@ -528,6 +528,14 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
>>>>>>>>> if (is_vec_two(op_const[0]))
>>>>>>>>> return expr(ir_unop_exp2, ir->operands[1]);
>>>>>>>>>
>>>>>>>>> + if (is_vec_two(op_const[1])) {
>>>>>>>>> + ir_variable *x = new(ir) ir_variable(ir->operands[1]->type, "x",
>>>>>>>>> + ir_var_temporary);
>>>>>>>>> + base_ir->insert_before(x);
>>>>>>>>> + base_ir->insert_before(assign(x, ir->operands[0]));
>>>>>>>>> + return mul(x, x);
>>>>>>>>> + }
>>>>>>>>> +
>>>>>>>>
>>>>>>>> Is this safe? Since many GPUs implement pow(x, y) as exp2(log2(x) *
>>>>>>>> y), this will give different results for if y comes from a uniform vs
>>>>>>>> if it's a constant, no?
>>>>>>
>>>>>> Yes, but that wouldn't be covered by the "invariant" keyword.
>>>>>>
>>>>>>> To be a bit more clear: I don't think this is valid for expressions
>>>>>>> writing to variables marked as invariant (or expressions taking part
>>>>>>> in the calculations that leads up to invariant variable writes).
>>>>>>>
>>>>>>> I can't find anything allowing variance like this in the invariance
>>>>>>> section of the GLSL 3.30 specifications. In particular, the list
>>>>>>> following "To guarantee invariance of a particular output variable
>>>>>>> across two programs, the following must also be true" doesn't seem to
>>>>>>> require the values to be passed from the same source, only that the
>>>>>>> same values are passed. And in this case, the value 2.0 is usually
>>>>>>> exactly representable no matter what path it took there.
>>>>>>>
>>>>>>> Perhaps I'm being a bit too pedantic here, though.
>>>>>>
>>>>>> This file would do the same thing on the same expression tree in two
>>>>>> different programs, so "invariant" is fine (we've probably got other
>>>>>> problems with invariant, though). The keyword you're probably thinking
>>>>>> of is "precise", which isn't in GLSL we implement yet.
>>>>>
>>>>> Are you saying that this only rewrites "x = pow(y, 2.0)" and not
>>>>> "const float e = 2.0; x = pow(y, e);"? If so, my point is moot,
>>>>> indeed. But if that's *not* the case, then I think we're in trouble
>>>>> still.
>>>>
>>>> The second would also get rewritten, because other passes will move the
>>>> 2.0 into the pow.
>>>>
>>>> I thought I understood your objection, but now I don't. I think you'll
>>>> have to lay out the pair of shaders involving the invariant keyword that
>>>> you think that would be broken by this pass.
>>>
>>> My understanding is that
>>> ---8<---
>>> invariant varying float v;
>>> attribute float a;
>>> const float e = 2.0;
>>> void main()
>>> {
>>> v = pow(a, e);
>>> }
>>> ---8<---
>>> and
>>> ---8<---
>>> invariant varying float v;
>>> attribute float a;
>>> uniform float e;
>>> void main()
>>> {
>>> v = pow(a, e);
>>> }
>>> ---8<---
>>> ...should produce the exact same result, as long as the latter is
>>> passed 2.0 as the uniform e.
>>>
>>> Because v is marked as invariant, the expressions writing to v are the
>>> same, and the values passed in are the same.
>>>
>>> If we rewrite the first one to do "a * a", we get a different result
>>> on implementations that do "exp2(log2(a) * 2.0)" for the latter, due
>>> to floating-point normalization in the intermediate steps.
>>
>> I don't think that's what the spec authors intended from the keyword. I
>> think what they intended was that if you had uniform float e in both
>> cases, but different code for setting *other* lvalues, that you'd still
>> get the same result in v.
>
> I think that *might* be correct, but it doesn't seem to be what's
> actually defined. Invariance comes from ESSL, and FWIW, I was one of
> the spec authors in this case. But I don't remember the details down
> to this level, and the spec doesn't seem to clarify either.
>
> However, since constant expressions are given some slack wrt how it's
> evaluated, I'm inclined to think that you're right about the spirit of
> the spec.
>
> AFAIR, we introduced "invariant" to get rid of ftransform (since we'd
> already gotten rid of fixed-function state), so that multi-pass
> rendering algorthms could be guaranteed that all passes ended up
> covering the exact same fragments at the exact same depth coordinate.
> And in cases like that, the inputs would really be of the same kind
> all the time, I guess.
I believe the intention was to prevent inter-expression optimizations
from causing different shaders from producing different results.
Relative to this example, you can imagine:
attribute float a, b;
uniform c;
void main()
{
a = pow(c, 3.0);
b = pow(c, 5.0);
}
//----------
attribute float a, b;
uniform c;
void main()
{
a = pow(c, 9.0);
b = pow(c, 5.0);
}
In the first shader, we might flatten the calculate of a and b to
multiplies. a would be c * c * c, and b would be a * c * c. The second
shader might generate two POW instructions. The invariant keyword would
(hypothetically) force the calculation of b to be the same in both.
If you had a similar situation involving the calculation of gl_Position,
you could get mis-aligned geometry.
Right now we do barely more than ignore the invariant keyword. I don't
feel like this (or the other proposed) optimization is going to make
this worth. I was chatting with Matt on IRC, and I feel like we should
revisit our poor treatment of invariance when we start implementing the
precise keyword with tessellation shaders.
FWIW... there are zero occurances of invariant in shader-db. It's hard
to get excited about doing work to support a feature that doesn't see
much (if any!) use. :(
> So yeah, perhaps. But I wouldn't feel safe about optimizations like
> this without a clarification from Khronos.
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list