7 Replies Latest reply on Sep 1, 2011 4:23 AM by spectral

    SIMD & conditional expressions

      Optimization questions with float4 ?


      I have some code that currently use 'float' and would like to use 'float4'. But, there is a condition into this function. Is there a solution for this kind of case ?

      I join the code, but how will react the 'sqrt' with a negative value or zero value ! Do you think that there is a faster way to do this (Less instruction, lesss divergence) ?




      float fresnel_dielectric(float cosi, float eta) { cosi = clamp(cosi, -1.f, 1.f); float c = fabs(cosi); float g = eta * eta - 1 + c * c; if (g > 0) { g = sqrt(g); float A = (g - c) / (g + c); float B = (c * (g + c) - 1) / (c * (g - c) + 1); return 0.5f * A * A * (1 + B * B); } return 1.f; // TIR (no refracted component) } float4 fresnel_dielectric4(float cosi, float4 eta) { cosi = clamp(cosi, -1.f, 1.f); float c = fabs(cosi); float4 g = eta * eta - 1 + c * c; g = sqrt(g); float4 A = (g - c) / (g + c); float4 B = (c * (g + c) - 1) / (c * (g - c) + 1); float4 fresnel 0.5f * A * A * (1 + B * B); return (float4)((g.x > 0) ? fresnel.x : 1.f, (g.x > 0) ? fresnel.x : 1.f, (g.x > 0) ? fresnel.x : 1.f, (g.x > 0) ? fresnel.x : 1.f) }

        • SIMD & conditional expressions


          why can't you check each element in g(float4 ) just like you are doing for the non-vectorized version?

          You can use ternary/select operators instead of if-else. They don't cause a conditional clause switch.

            • SIMD & conditional expressions

              Thanks but,

              I don't want to check each element, it request 4 operations !

              I already use the ternary operator in the last line of 'fresnel_dielectric4'.

              But I can't for 'g' ... because :

              a) what give sqrt(X) if x < 0 ?

              b) I also want to compute 'fresnel' in a SIMD way (Mainly for CPU)

              Right ?

                • SIMD & conditional expressions

                  OpenCL's sqrt should behave as c99's sqrt which says:

                  The sqrt functions compute the nonnegative square root of x. A domain error occurs if the argument is less than zero.

                  So if you cannot guarantee positive number in sqrt, i guess checking them individually is a must.


                    • SIMD & conditional expressions

                      It is why I afraid of this :-P

                      Because it require to extract SIMD data into a float, then check it for x,y,z,w...

                      Finally using SIMD can be more expensive than not using it !

                      • SIMD & conditional expressions

                        as of your code, maybe you could create two new variables float4 g_m_c = g-c; and float4 g_p_c = g+c; and set A = g_m_c/g_p_c; and B = mad(c,g_p_c,-1)/mad(c,g_m_c,1); (you forgot a '=' before 0.5f when declaring fresnel). I don't know if it would increase performance.

                        why you test the 'x' components 4 times? Shouldn't you test 'x', 'y', 'z' and 'w' components of g?

                        about cosi, do you really need a clamp?

                        about eta, what range of values should it take?

                  • SIMD & conditional expressions

                    You're after the relational operators (see opencl spec 9.6.5), and the select operator.  See below.

                    They work just like the trinary operator except that all paths are evaluated explicitly and you can use any width of input.

                    It shouldn't matter that any result is NaN along the way since it is just discarded.  SIMD processors have to be used in this way for parallelism, so they should behave as you'd expec.  i.e. the processor isn't going to crack a sad just because you gave it invalid data in one path.

                    The compiler might already be doing the select conversion for you, fwiw (well, if your code was correct, you only ever test for g.x and only ever use use freshnel.x in your result).


                    int4 cmp = isgreater(g, (float4)0); g = sqrt(g); float4 A = (g-c) / ( g + c); etc. float4 fresnel = 0.5f * A * A ...; and finally return select((float4)1, fresnel, cmp);