oizma / angleproject

Automatically exported from code.google.com/p/angleproject
Other
0 stars 0 forks source link

ANGLE mis-translates some ternary operations #20

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Attempt to compile the shader below on OSX

What is the expected output? 

It should compile

What do you see instead?

It gets an error at line 45 

The issue is some parens have been moved in such a way to change precedence.

This line:

  result +=
      clamp((hand_radius_2 - length_2(Z - r_h)) / threshold, 0.0, 1.0) *
          (Z.y < r_h.y ? 1.0 : 0.0) * right_hand_color +
      clamp((hand_radius_2 - length_2(Z - l_h)) / threshold, 0.0, 1.0) *
          (Z.y < l_h.y ? 1.0 : 0.0) * left_hand_color;

Is translated to this

(result += 
  (
    (
      (clamp
        (
          (
            (hand_radius_2 - length_2
               (
                 (Z - r_h)
               )
            ) / threshold
          ), 0.0, 1.0
        ) * 
        (
          (Z[1] < r_h[1])
        ) ? (1.0) : (0.0)
      ) * right_hand_color
    ) + 
    (
      (clamp
        (
          (
            (hand_radius_2 - length_2
              (
                (Z - l_h)
              )
            ) / threshold
          ), 0.0, 1.0
        ) * 
        (
          (Z[1] < l_h[1])
        ) ? (1.0) : (0.0)
      ) * left_hand_color
    )
  )
);

Notice that the ternary parts have changed precedence.

Here's the entire shader:
---------------------------------------
precision highp float;
varying vec2 v_texCoord;

uniform float theta;
uniform float num;

float length_2(vec2 v) {
  return dot(v, v);
}

// Draw the balls in a single arc.
// Returns 1 if the pixel is within a ball, 0 if it isn't, and a value in
// between for pixels right on the edge, for antialiasing.
float drawBallsInArc(float pi,
                     vec4 offset,
                     vec2 source_hand,
                     vec2 dest_hand,
                     float height_factor,
                     float baseline,
                     float ball_radius_2,
                     float hand_throw_offset,
                     vec2 Z,
                     float threshold) {
  // Map theta from its current range of [0, 2 * num * pi) onto [0, (num - 1))
  // by scaling, adding offset, and modding, then map that to [0, 1) by scaling.
  // The first mapping tells us where in the repeating cycle we are, and the
  // second mapping simplifies the calculation of the parabola.

  // The vector offset is used to distinguish between balls in the same arc, but
  // out of phase.  At the beginning of this function, all the operations are
  // vectorized to save instructions; we get to calculate 4 ball positions for
  // the price of 1.

  // The reason for the (num - 1) in the expression below is that with num
  // balls, each ball spends (num - 1) beats in the air, then one in the hand.
  // So (num - 1) is the length of time a parabola takes.

  vec4 time = mod(theta / pi + offset, (num - 1.0)) / (num - 1.0);
  float dx = dest_hand.x - source_hand.x;
  vec4 x = time * dx + source_hand.x - hand_throw_offset;
  vec4 y = time * (1.0 - time);
  y = y * height_factor + baseline;
  vec4 ZX = vec4(Z.x);
  vec4 ZY = vec4(Z.y);
  vec4 len_2 = (ZX - x) * (ZX - x) + (ZY - y) * (ZY - y);

  // This antialiasing fuzzes the balls just a bit larger than they would
  // otherwise be.
  vec4 temp = clamp((len_2 - ball_radius_2) / threshold, 0.0, 1.0);

  // One minus the product of all entries in temp.
  temp.xy = temp.xy * temp.zw;
  return 1.0 - temp.x * temp.y;
}

vec4 drawAirborneBalls(float pi,
                         vec4 offset,
                         vec2 right_hand,
                         vec2 left_hand,
                         float height_factor,
                         float baseline,
                         float ball_radius_2,
                         float hand_swing_radius,
                         vec2 Z,
                         float threshold) {
  float value =
      // balls going right to left
      (drawBallsInArc(pi, offset, right_hand, left_hand, height_factor,
          baseline, ball_radius_2, hand_swing_radius, Z, threshold) +
      // balls going left to right
      drawBallsInArc(pi, offset + 1.0, left_hand, right_hand, height_factor,
          baseline, ball_radius_2, -hand_swing_radius, Z, threshold));
  return vec4(value, value, value, value);
}

/**
 * pixelShaderMain - pixel shader
 */

void main() {
  float pi = 3.14159265;
  float baseline = -1.4;
  vec2 right_hand = vec2(0.8, baseline);
  vec2 left_hand = vec2(-0.8, baseline);
  float hand_swing_radius = 0.25;
  float hand_radius = 0.15;
  float hand_radius_2 = hand_radius * hand_radius;
  float ball_radius = 0.08;
  float ball_radius_2 = ball_radius * ball_radius;

  vec4 right_hand_color = vec4(1, 0, 0, 1);
  vec4 left_hand_color = vec4(0, 0, 1, 1);
  vec4 background_color = vec4(0, 0, 0, 0);

  float threshold = 0.002; // Used in clamp for antialiasing.

  float height_factor = num * 0.75;

  vec2 Z = v_texCoord;

  // Coerce to the range [0, 2 * Pi * num].
  vec2 r_h = hand_swing_radius * vec2(-cos(theta), sin(theta)) + right_hand;
  vec2 l_h = hand_swing_radius * vec2(-cos(theta), -sin(theta)) + left_hand;

  // Initialize color of pixel to background_color.  Background color has an
  // alpha of 0.  Color of objects each have alpha 1, so multiplying by
  // (1-alpha) before adding the color ensures that nothing gets overdrawn.
  // It's kind of like a rudimentary z-buffer.
  vec4 result = background_color;

  // Draw the hands.  The antialiasing here fuzzes the hands just a little bit
  // smaller than they would otherwise be.  That's the opposite of what we do
  // for the balls, just because it happens to be cheaper here to do smaller and
  // cheaper in drawBallsInArc to do larger.
  float temp = (Z.y < r_h.y ? 1.0 : 0.0); // TODO(luchen): figure out why ternary fails
  float temp2 = (Z.y < l_h.y ? 1.0 : 0.0);
  result +=
      clamp((hand_radius_2 - length_2(Z - r_h)) / threshold, 0.0, 1.0) *
          (Z.y < r_h.y ? 1.0 : 0.0) * right_hand_color +
      clamp((hand_radius_2 - length_2(Z - l_h)) / threshold, 0.0, 1.0) *
          (Z.y < l_h.y ? 1.0 : 0.0) * left_hand_color;
  // Draw the ball in the hand.  There is always a ball in exactly one hand, and
  // which hand that is alternates.
  vec2 hand;
  if (mod(floor(theta / pi), 2.0) > 0.5) {
    hand = r_h;
  } else {
    hand = l_h;
  }

  // The antialiasing here fuzzes the balls just a bit bigger than they would
  // otherwise be.  This is more work than making them smaller [the extra
  // subtraction in the "1 - clamp..." below], but inverting it in
  // drawBallsInArc would be more expensive, and they have to match so that the
  // balls are all the same size.
  result += (1.0 - result.a) *
      (1.0 - clamp((length_2(Z - hand) - ball_radius_2) / threshold, 0.0, 1.0));

  // Draw airborne balls.
  vec4 offset = vec4(0, 2, 4, 6);
  result += (1.0 - result.a) * drawAirborneBalls(pi,
                                               offset,
                                               right_hand,
                                               left_hand,
                                               height_factor,
                                               baseline,
                                               ball_radius_2,
                                               hand_swing_radius,
                                               Z,
                                               threshold);

  // For each up-to-4 pairs of balls you want to add, increment offset by
  // (8, 8, 8, 8) and call drawAirborneBalls again.
  offset += 8.0;
  result += (1.0 - result.a) * drawAirborneBalls(pi,
                                               offset,
                                               right_hand,
                                               left_hand,
                                               height_factor,
                                               baseline,
                                               ball_radius_2,
                                               hand_swing_radius,
                                               Z,
                                               threshold);

  gl_FragColor = result;
}

Original issue reported on code.google.com by g...@chromium.org on 22 Jul 2010 at 9:25

GoogleCodeExporter commented 9 years ago
Fixed in r352.

Original comment by alokp@chromium.org on 5 Aug 2010 at 8:32