On 7 October 2011 12:28, Ian Romanick <span dir="ltr">&lt;<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div><div></div><div class="h5">On 10/06/2011 08:45 AM, Paul Berry wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
isinf() and isnan() are difficult to test, since the GLSL 1.30 spec<br>
does not define when an implemenation is required to generate infinite<br>
or NaN values; in fact, it explicitly allows for implementations that<br>
do not even have a representation of infinity or NaN.<br>
<br>
This test verifies that if the implementation does generate infinite<br>
or NaN values, they behave in a consistent way, and that when it<br>
claims that a value is finite, it truly is finite.<br>
<br>
Tested on the nVidia proprietary Linux driver, which passes all<br>
variants of the test except the &quot;vs_xfb&quot; variant (which is skipped<br>
because the driver doesn&#39;t have the correct extension string to<br>
indicate that it is capable of performing transform feedback).<br>
---<br>
  tests/all.tests                                  |    3 +<br>
  tests/spec/glsl-1.30/<u></u>execution/CMakeLists.gl.txt |    1 +<br>
  tests/spec/glsl-1.30/<u></u>execution/isinf-and-isnan.c |  554 ++++++++++++++++++++++<br>
  3 files changed, 558 insertions(+), 0 deletions(-)<br>
  create mode 100644 tests/spec/glsl-1.30/<u></u>execution/isinf-and-isnan.c<br>
<br>
diff --git a/tests/all.tests b/tests/all.tests<br>
index 40bc92c..aca2c7f 100644<br>
--- a/tests/all.tests<br>
+++ b/tests/all.tests<br>
@@ -853,6 +853,9 @@ spec[&#39;glsl-1.30&#39;][&#39;linker&#39;] = Group()<br>
  spec[&#39;glsl-1.30&#39;][&#39;linker&#39;][&#39;<u></u>clipping&#39;] = Group()<br>
  add_plain_test(spec[&#39;glsl-1.<u></u>30&#39;][&#39;linker&#39;][&#39;clipping&#39;], &#39;mixing-clip-distance-and-<u></u>clip-vertex-disallowed&#39;)<br>
  add_plain_test(spec[&#39;glsl-1.<u></u>30&#39;][&#39;execution&#39;][&#39;clipping&#39;], &#39;max-clip-distances&#39;)<br>
+for arg in [&#39;vs_basic&#39;, &#39;vs_xfb&#39;, &#39;vs_fbo&#39;, &#39;fs_basic&#39;, &#39;fs_fbo&#39;]:<br>
+       test_name = &#39;isinf-and-isnan &#39; + arg<br>
+       spec[&#39;glsl-1.30&#39;][&#39;execution&#39;]<u></u>[test_name] = PlainExecTest(test_name + &#39; -auto&#39;)<br>
  spec[&#39;glsl-1.30&#39;][&#39;execution&#39;]<u></u>[&#39;clipping&#39;][&#39;clip-plane-<u></u>transformation pos&#39;] = \<br>
      concurrent_test(&#39;clip-plane-<u></u>transformation pos&#39;)<br>
<br>
diff --git a/tests/spec/glsl-1.30/<u></u>execution/CMakeLists.gl.txt b/tests/spec/glsl-1.30/<u></u>execution/CMakeLists.gl.txt<br>
index e569968..1a920ca 100644<br>
--- a/tests/spec/glsl-1.30/<u></u>execution/CMakeLists.gl.txt<br>
+++ b/tests/spec/glsl-1.30/<u></u>execution/CMakeLists.gl.txt<br>
@@ -16,3 +16,4 @@ link_libraries (<br>
  add_executable (fs-textureSize-2D fs-textureSize-2D.c)<br>
  add_executable (fs-texelFetch-2D fs-texelFetch-2D.c)<br>
  add_executable (fs-texelFetchOffset-2D fs-texelFetchOffset-2D.c)<br>
+add_executable (isinf-and-isnan isinf-and-isnan.c)<br>
diff --git a/tests/spec/glsl-1.30/<u></u>execution/isinf-and-isnan.c b/tests/spec/glsl-1.30/<u></u>execution/isinf-and-isnan.c<br>
new file mode 100644<br>
index 0000000..601d36d<br>
--- /dev/null<br>
+++ b/tests/spec/glsl-1.30/<u></u>execution/isinf-and-isnan.c<br>
@@ -0,0 +1,554 @@<br>
+/*<br>
+ * Copyright © 2011 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the &quot;Software&quot;),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER<br>
+ * DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+/**<br>
+ * \file isinf-and-isnan.c<br>
+ *<br>
+ * Test that isinf() and isnan() built-in functions behave properly.<br>
+ *<br>
+ * The GLSL 1.30 spec does not define when an implementation is required to<br>
+ * generate infinite or NaN values; in fact, it explicitly allows for<br>
+ * implementations that do not even have a representation of infinity or Nan.<br>
+ * Therefore, we cannot check that infinities and NaNs are created when we<br>
+ * expect them.  However, we can test: (a) that isnan() and isinf() return<br>
+ * false for finite values, (b) that isinf() and isnan() behave consistently<br>
+ * with each other, and (c) that when a floating-point value is read out the<br>
+ * shader (using transform feedback or a floating point framebuffer) the<br>
+ * behavior of isnan() and isinf() behave consistently with the value that is<br>
+ * read out.<br>
+ *<br>
+ * This test operates by generating several expressions, some of which are<br>
+ * likely to produce infinities, some of which are likely to produce NaN, and<br>
+ * some of which are expected to produce finite values.  For each expression,<br>
+ * it does the following:<br>
+ * - evaluates isinf(value) in the shader<br>
+ * - evaluates isnan(value) in the shader<br>
+ * - evaluates sign(value) in the shader<br>
+ * - evaluates (value&gt;  0) in the shader<br>
+ * - reads the value out of the shader (using transform feedback or a floating<br>
+ *   point framebuffer)<br>
+ * - feeds that value back into the shader (using a uniform); the shader<br>
+ *   subtracts this uniform from the originally computed value to produce a<br>
+ *   delta.<br>
+ *<br>
+ * And then it performs the following checks:<br>
+ * - If the value was expected to be finite, verifies that isinf() and isnan()<br>
+ *   returned false.<br>
+ * - If the value was expected to be +Inf or -Inf, verifies that the sign is<br>
+ *   correct, using both sign(value) and (value&gt;  0).  This check is skipped<br>
+ *   if isnan(value) is true, since it&#39;s possible that a conformant<br>
+ *   implementation might generate NaN instead of infinity, and NaN does not<br>
+ *   have a well-defined sign.<br>
+ * - Checks that isinf() and isnan() didn&#39;t both return true.<br>
+ * - Checks that the C isinf() and isnan() functions give the same result as<br>
+ *   the shader&#39;s isinf() and isnan() functions.<br>
+ * - If the value is finite, checks that the delta is zero (to within<br>
+ *   tolerance).<br>
+ *<br>
+ * The last two checks are only performed when using a floating point<br>
+ * framebuffer or transform feedback, because those are the only ways to get<br>
+ * infinities and NaNs out of the shader and into C code.<br>
+ *<br>
+ * Note: the reason for the final check is to verify that a value claimed by<br>
+ * the shader to be finite is truly behaving like a finite number.  Without<br>
+ * it, an implementation could pass all these tests by simply having isinf()<br>
+ * and isnan() return false, and converting infinities and NaNs to finite<br>
+ * values when they exit the shader.<br>
+ *<br>
+ * The output of the test is a table whose columns are:<br>
+ * - The expression being tested (this expression may refer to the uniforms<br>
+ *   z=0, u_inf=+Inf, u_minus_inf=-Inf, and u_nan=NaN).<br>
+ * - The expected behavior of the expression (&quot;finite&quot;, &quot;+Inf&quot;, &quot;-Inf&quot;, or<br>
+ *   &quot;NaN&quot;, indicating how the expression would be expected to evaluate on a<br>
+ *   fully IEEE 754 compliant architecture)<br>
+ * - isinf(value), as computed by the shader<br>
+ * - isnan(value), as computed by the shader<br>
+ * - sign(value), as computed by the shader<br>
+ * - (value&gt;  0), as computed by the shader<br>
+ * - value, as read out of the shader using transform feedback or a<br>
+ *   floating-point framebuffer<br>
+ * - delta, the difference between the computed value and the value that was<br>
+ *   fed back into the shader.<br>
+ * - A pass/fail indication.<br>
+ *<br>
+ * The test must be invoked with one of the following command-line arguments:<br>
+ * - vs_basic: test the VS without reading values out of the shader.<br>
+ * - fs_basic: test the FS without reading values out of the shader.<br>
+ * - vs_fbo: test the VS, using a floating-point framebuffer to read values<br>
+ *   out of the shader.<br>
+ * - vs_xfb: test the VS, using transform feedback to read values out of the<br>
+ *   shader.<br>
+ * - fs_fbo: test the FS, using a floating-point framebuffer to read values<br>
+ *   out of the shader.<br>
+ */<br>
+<br>
+#include &quot;piglit-util.h&quot;<br>
+<br>
+int piglit_width = 100;<br>
+int piglit_height = 100;<br>
+int piglit_window_mode = GLUT_RGB | GLUT_ALPHA | GLUT_DOUBLE;<br>
+<br>
+GLint stock_vs;<br>
+GLint stock_fs;<br>
+GLuint xfb_buffer;<br>
+<br>
+/**<br>
+ * True if we are using a floating-point framebuffer to read data out of the<br>
+ * shader.<br>
+ */<br>
+bool use_fbo = false;<br>
+<br>
+/**<br>
+ * True if we are using transform feedback to read data out of the shader.<br>
+ */<br>
+bool use_xfb = false;<br>
+<br>
+/**<br>
+ * True if we are testing the fragment shader, false if we are testing the<br>
+ * vertex shader.<br>
+ */<br>
+bool use_fs;<br>
+<br>
+/**<br>
+ * True if we are reading data out of the shader using a mechanism that<br>
+ * preserves the full 32-bit floating point value, so we can do additional<br>
+ * checks.<br>
+ */<br>
+bool precise;<br>
+<br>
+static const char stock_vs_text[] =<br>
+       &quot;#version 130\n&quot;<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  gl_Position = gl_Vertex;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char stock_fs_text[] =<br>
+       &quot;#version 130\n&quot;<br>
+       &quot;flat in vec4 data;\n&quot;<br>
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  gl_FragColor = data;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char shader_template[] =<br>
+       &quot;#version 130\n&quot;<br>
+       &quot;uniform float z;\n&quot;<br>
</blockquote>
<br></div></div>
Why is z a uniform?  Is this just to defeat constant folding?  If so, a comment to that effect is in order. <br></blockquote><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">

<br>
At the very least, you can initialize its value in the shader:<br>
<br>
uniform float z = 0.0;<div class="im"><br></div></blockquote><div><br>Ok, I will do this and make a comment to explain that z is present to defeat constant folding.<br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div class="im">
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+       &quot;uniform float u_inf;\n&quot;<br>
+       &quot;uniform float u_minus_inf;\n&quot;<br>
+       &quot;uniform float u_nan;\n&quot;<br>
+       &quot;uniform float ref;\n&quot;<br>
+       &quot;uniform int mode;\n&quot;<br>
+       &quot;%s&quot; /* Either vs_boilerplate or fs_boilerplate */<br>
</blockquote>
<br></div>
Yuck.  There&#39;s no reason to concatenate the shader strings in the application code.  There are two better ways to do this in GLSL:<br>
<br>
1. Multiple compilation units.<br>
<br>
2. Multiple source strings passed to glShaderSource.  This makes things a bit more difficult with our piglit wrapper functions, but that may mean that we need a different set of warpper functions.  A varargs version of piglit_compile_shader_text might be in order.  Then you&#39;d just do:<br>

<br>
        piglit_compile_shader_text_<u></u>varags(GL_FRAGMENT_SHADER,<br>
                                shader_template,<br>
                                fs_boilerplate,<br>
                                NULL);<br>
<br>
Or something like that.<br>
<br>
One way that I&#39;ve seen tests like this structured is to have a boilerplate main function for each shader target.  Each flavor of main is designed to call a do_test function that does the real work.  Then you just need a bunch of do_test function snippets that you compile and like with the per-shader main.  If GLSL had a &quot;generic&quot; shader target that you could compile to, this would be even easier.</blockquote>
<div><br>Ok, fair point.  I&#39;ll restructure the test using multiple compilation units.<br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div class="im"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+       &quot;void main()\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  do_common_shader_operations();<u></u>\n&quot;<br>
+       &quot;  float value = %s;\n&quot; /* Expression to be tested */<br>
</blockquote>
<br></div>
In the do_test style, this would just become<br>
<br>
    float value = do_test();<div class="im"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+       &quot;  if (mode == 0) {\n&quot;<br>
</blockquote>
<br></div>
I&#39;d like to see an enum or some #defines in the C code to explain the values of mode.</blockquote><div><br>Ok, fair point.<br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div><div></div><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+       &quot;    output_result(vec4(value,\n&quot;<br>
+       &quot;                       isinf(value) ? 1 : 0,\n&quot;<br>
+       &quot;                       isnan(value) ? 1 : 0,\n&quot;<br>
+       &quot;                       (sign(value) + 1.0) / 2.0));\n&quot;<br>
+       &quot;  } else if (mode == 1) {\n&quot;<br>
+       &quot;    output_result(vec4(value&gt;  0 ? 1 : 0,\n&quot;<br>
+       &quot;                       value - ref,\n&quot;<br>
+       &quot;                       0.0,\n&quot;<br>
+       &quot;                       0.0));\n&quot;<br>
+       &quot;  } else {\n&quot;<br>
+       &quot;    /* Ensure all uniforms are used */\n&quot;<br>
+       &quot;    output_result(vec4(z + u_inf + u_minus_inf + u_nan));\n&quot;<br>
+       &quot;  }\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char vs_boilerplate[] =<br>
+       &quot;flat out vec4 data;\n&quot;<br>
+       &quot;void do_common_shader_operations()\<u></u>n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  gl_Position = gl_Vertex;\n&quot;<br>
+       &quot;}\n&quot;<br>
+       &quot;void output_result(vec4 result)\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  data = result;\n&quot;<br>
+       &quot;}\n&quot;;<br>
+<br>
+static const char fs_boilerplate[] =<br>
+       &quot;void do_common_shader_operations()\<u></u>n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;}\n&quot;<br>
+       &quot;void output_result(vec4 result)\n&quot;<br>
+       &quot;{\n&quot;<br>
+       &quot;  gl_FragColor = result;\n&quot;<br>
+       &quot;}\n&quot;;<br>
</blockquote>
<br></div></div>
Also yuck.  Since this test will require GLSL 1.30 and OpenGL 3.0, you can just make a fragment shader output called result.<br>
<br>
out vec4 result;<br>
<br>
Mesa doesn&#39;t have glBindFragDataLocation yet, but you can use explicit attribute locations.  Something like:<br>
<br>
#version 130<br>
#extension GL_ARB_explicit_attrib_<u></u>location: enable<br>
<br>
#if defined GL_ARB_explicit_attrib_<u></u>location<br>
layout(location = 0)<br>
#endif<br>
    out vec4 result;<br>
<br>
In the application, you&#39;ll have to call glBindFragDataLocation if GL_ARB_explicit_attrib_<u></u>location isn&#39;t supported.<br></blockquote><div><br>Ok, I think I see why you had a &quot;yuck&quot; reaction to the output_result() function above, but I&#39;m having a &quot;yuck&quot; reaction of my own to the preprocessor stuff above, and to having a run-time decision of whether to call glBindFragDataLocation based on whether GL_ARB_explicit_attrib_location is supported.  I think I can make the gl_FragColor approach look a lot cleaner when I rework the test to use multiple compilation units.  Let&#39;s revisit this question after I&#39;ve done the rework and see if it&#39;s still objectionable to you.<br>
 </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
The other alternative, if we really care about GLSL 1.30 without OpenGL 3.0, is<br>
<br>
#define result gl_FragColor <br></blockquote><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div><div></div><div class="h5"><br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+void<br>
+setup_fbo()<br>
+{<br>
+       piglit_require_extension(&quot;GL_<u></u>ARB_framebuffer_object&quot;);<br>
+       piglit_require_extension(&quot;GL_<u></u>ARB_texture_float&quot;);<br>
+<br>
+       GLuint fb = 0;<br>
+       GLuint color_rb = 0;<br>
+       GLenum fb_status;<br>
+<br>
+       glGenFramebuffers(1,&amp;fb);<br>
+       glBindFramebuffer(GL_<u></u>FRAMEBUFFER, fb);<br>
+<br>
+       /* Bind color attachment. */<br>
+       glGenRenderbuffers(1,&amp;color_<u></u>rb);<br>
+       glBindRenderbuffer(GL_<u></u>RENDERBUFFER, color_rb);<br>
+       glRenderbufferStorage(GL_<u></u>RENDERBUFFER, GL_RGBA32F,<br>
+                             piglit_width, piglit_height);<br>
+       glFramebufferRenderbuffer(GL_<u></u>DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,<br>
+                                 GL_RENDERBUFFER, color_rb);<br>
+       piglit_check_gl_error(0, PIGLIT_FAIL);<br>
+<br>
+       fb_status = glCheckFramebufferStatus(GL_<u></u>FRAMEBUFFER);<br>
+       if (fb_status != GL_FRAMEBUFFER_COMPLETE) {<br>
+               printf(&quot;error: FBO incomplete (status = 0x%04x)\n&quot;, fb_status);<br>
+               piglit_report_result(PIGLIT_<u></u>SKIP);<br>
+       }<br>
+<br>
+       glBindFramebuffer(GL_DRAW_<u></u>FRAMEBUFFER, fb);<br>
+       glBindFramebuffer(GL_READ_<u></u>FRAMEBUFFER, fb);<br>
+}<br>
+<br>
+void<br>
+setup_xfb()<br>
+{<br>
+       piglit_require_extension(&quot;GL_<u></u>EXT_transform_feedback&quot;);<br>
</blockquote>
<br></div></div>
Even though you&#39;re requiring GL_EXT_transform_feedback, you&#39;re using the function names from OpenGL 3.0.  This will fail on any system that supports the EXT but doesn&#39;t support OpenGL 3.0.  I think it&#39;s best to just require OpenGL 3.0 here.<br>

<br>
The other option is to require &quot;any&quot; of the transform feedback flavors and have piglit_ wrapper functions.<br>
<br></blockquote><div><br>I think I&#39;ll go with the approach of just requiring OpenGL 3.0.  My efforts to make the test work without OpenGL 3.0 seem misguided to me now.<br> 
<br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+       glGenBuffers(1,&amp;xfb_buffer);<div><div></div><div class="h5"><br>
+}<br>
+<br>
+void<br>
+print_usage_and_exit(char *prog_name)<br>
+{<br>
+       printf(&quot;Usage: %s&lt;mode&gt;\n&quot;<br>
+              &quot;  where&lt;mode&gt;  is one of:\n&quot;<br>
+              &quot;    vs_basic\n&quot;<br>
+              &quot;    fs_basic\n&quot;<br>
+              &quot;    vs_fbo\n&quot;<br>
+              &quot;    vs_xfb\n&quot;<br>
+              &quot;    fs_fbo\n&quot;, prog_name);<br>
+       exit(1);<br>
+}<br>
+<br>
+void<br>
+piglit_init(int argc, char **argv)<br>
+{<br>
+       if (argc != 2)<br>
+               print_usage_and_exit(argv[0]);<br>
+       if (strcmp(argv[1], &quot;vs_basic&quot;) == 0) {<br>
+               use_fs = false;<br>
+       } else if (strcmp(argv[1], &quot;fs_basic&quot;) == 0) {<br>
+               use_fs = true;<br>
+       } else if (strcmp(argv[1], &quot;vs_fbo&quot;) == 0) {<br>
+               use_fs = false;<br>
+               use_fbo = true;<br>
+       } else if (strcmp(argv[1], &quot;vs_xfb&quot;) == 0) {<br>
+               use_fs = false;<br>
+               use_xfb = true;<br>
+       } else if (strcmp(argv[1], &quot;fs_fbo&quot;) == 0) {<br>
+               use_fs = true;<br>
+               use_fbo = true;<br>
+       } else {<br>
+               print_usage_and_exit(argv[0]);<br>
+       }<br>
+       precise = use_fbo || use_xfb;<br>
+<br>
+       piglit_require_GLSL();<br>
+       piglit_require_GLSL_version(<u></u>130);<br>
+<br>
+       if (use_fbo) {<br>
+               setup_fbo();<br>
+       }<br>
+       if (use_xfb) {<br>
+               setup_xfb();<br>
+       }<br>
+<br>
+       stock_vs = piglit_compile_shader_text(GL_<u></u>VERTEX_SHADER,<br>
+                                             stock_vs_text);<br>
+       stock_fs = piglit_compile_shader_text(GL_<u></u>FRAGMENT_SHADER,<br>
+                                             stock_fs_text);<br>
+}<br>
+<br>
+/**<br>
+ * enum indicating how the expression would be expected to behave on a fully<br>
+ * IEEE 754 compliant architecture.  Note: since OpenGL implementations are<br>
+ * not required to respect all of IEEE 754&#39;s rules for infinities and NaN&#39;s,<br>
+ * we don&#39;t necessarily check all of these behaviors.<br>
+ */<br>
+enum behavior<br>
+{<br>
+       B_NAN    = 0, /* Expected to evaluate to NaN */<br>
+       B_FINITE = 1, /* Expected to evaluate to a finite value */<br>
+       B_POSINF = 2, /* Expected to evaluate to +Infinity */<br>
+       B_NEGINF = 3, /* Expected to evaluate to -Infinity */<br>
+};<br>
+<br>
+struct expression_table_element<br>
+{<br>
+       char *expression;<br>
+       int expected_behavior;<br>
+};<br>
+<br>
+struct expression_table_element expressions[] = {<br>
+       { &quot;1000.0&quot;, B_FINITE },<br>
+       { &quot;1000.0+z&quot;, B_FINITE },<br>
+       { &quot;-1000.0&quot;, B_FINITE },<br>
+       { &quot;-1000.0+z&quot;, B_FINITE },<br>
+       { &quot;u_inf&quot;, B_POSINF },<br>
+       { &quot;exp(1000.0)&quot;, B_POSINF },<br>
+       { &quot;exp(1000.0+z)&quot;, B_POSINF },<br>
+       { &quot;u_minus_inf&quot;, B_NEGINF },<br>
+       { &quot;-exp(1000.0)&quot;, B_NEGINF },<br>
+       { &quot;-exp(1000.0+z)&quot;, B_NEGINF },<br>
+       { &quot;u_nan&quot;, B_NAN },<br>
+       { &quot;0/0&quot;, B_NAN },<br>
+       { &quot;z/z&quot;, B_NAN },<br>
+       { &quot;u_inf/u_minus_inf&quot;, B_NAN },<br>
+       { &quot;z*u_inf&quot;, B_NAN },<br>
+       { &quot;u_inf+u_minus_inf&quot;, B_NAN },<br>
+       { &quot;log(-1.0)&quot;, B_NAN },<br>
+       { &quot;log(-1.0+z)&quot;, B_NAN },<br>
+       { &quot;sqrt(-1.0)&quot;, B_NAN },<br>
+       { &quot;sqrt(-1.0+z)&quot;, B_NAN },<br>
+};<br>
+<br>
+/**<br>
+ * Draw using the shader, and then read back values using either (a) the<br>
+ * floating-point framebuffer, (b) transform feedback, or (c) pixel reads from<br>
+ * the window.  Note that pixel reads from the window are only accurate to one<br>
+ * part in 255, so the caller must be careful not to rely on high precision in<br>
+ * case (c).<br>
+ */<br>
+void draw_and_readback(float *readback)<br>
+{<br>
+       if (use_xfb) {<br>
+               glBufferData(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, 4096, NULL,<br>
+                            GL_DYNAMIC_COPY);<br>
+               glBindBufferBase(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, 0, xfb_buffer);<br>
+               glEnable(GL_RASTERIZER_<u></u>DISCARD);<br>
+               glBeginTransformFeedback(GL_<u></u>TRIANGLES);<br>
+       }<br>
+<br>
+       piglit_draw_rect(-1, -1, 2, 2);<br>
+<br>
+       if (use_xfb) {<br>
+               glEndTransformFeedback();<br>
+               memcpy(readback,<br>
+                      glMapBuffer(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, GL_READ_ONLY),<br>
+                      4*sizeof(float));<br>
+               glUnmapBuffer(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER);<br>
+       } else {<br>
+               glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, readback);<br>
+       }<br>
+}<br>
+<br>
+/**<br>
+ * Test the given expression, to make sure its behavior is self-consistent and<br>
+ * consistent with the expected behavior.<br>
+ */<br>
+bool test_expr(char *expression, int expected_behavior)<br>
+{<br>
+       char shader_text[4096];<br>
+       GLint shader;<br>
+       GLint prog;<br>
+       float readback[4];<br>
+       float value;<br>
+       bool isinf_in_shader;<br>
+       bool isnan_in_shader;<br>
+       int sign_in_shader;<br>
+       float delta;<br>
+       bool greater_than_zero;<br>
+       bool pass = true;<br>
+       char *expected_behavior_string;<br>
+<br>
+       /* Create and link a program specifically to test this expression */<br>
+       prog = piglit_CreateProgram();<br>
+       if (use_fs) {<br>
+               sprintf(shader_text, shader_template, fs_boilerplate,<br>
+                       expression);<br>
+               shader = piglit_compile_shader_text(GL_<u></u>FRAGMENT_SHADER,<br>
+                                                   shader_text);<br>
+               piglit_AttachShader(prog, stock_vs);<br>
+               piglit_AttachShader(prog, shader);<br>
+       } else {<br>
+               sprintf(shader_text, shader_template, vs_boilerplate,<br>
+                       expression);<br>
+               shader = piglit_compile_shader_text(GL_<u></u>VERTEX_SHADER,<br>
+                                                   shader_text);<br>
+               piglit_AttachShader(prog, shader);<br>
+               piglit_AttachShader(prog, stock_fs);<br>
+       }<br>
+       if (use_xfb) {<br>
+               static const char *var_name = &quot;data&quot;;<br>
+               glTransformFeedbackVaryings(<u></u>prog, 1,&amp;var_name,<br>
+                                           GL_SEPARATE_ATTRIBS);<br>
+               glBindBuffer(GL_TRANSFORM_<u></u>FEEDBACK_BUFFER, xfb_buffer);<br>
+       }<br>
+       piglit_LinkProgram(prog);<br>
+       piglit_DeleteShader(shader);<br>
+       piglit_UseProgram(prog);<br>
+<br>
+       /* Set up uniforms */<br>
+       piglit_Uniform1f(piglit_<u></u>GetUniformLocation(prog, &quot;z&quot;), 0.0);<br>
+       piglit_Uniform1f(piglit_<u></u>GetUniformLocation(prog, &quot;u_inf&quot;), 1.0/0.0);<br>
+       piglit_Uniform1f(piglit_<u></u>GetUniformLocation(prog, &quot;u_minus_inf&quot;),<br>
+                        -1.0/0.0);<br>
+       piglit_Uniform1f(piglit_<u></u>GetUniformLocation(prog, &quot;u_nan&quot;), 0.0/0.0);<br>
+<br>
+       /* Use one draw call to read out value, isinf(value), isnan(value),<br>
+        * and sign(value).<br>
+        */<br>
+       piglit_Uniform1f(piglit_<u></u>GetUniformLocation(prog, &quot;ref&quot;), 0.0);<br>
+       piglit_Uniform1i(piglit_<u></u>GetUniformLocation(prog, &quot;mode&quot;), 0);<br>
+       draw_and_readback(readback);<br>
+       value = readback[0];<br>
+       isinf_in_shader = readback[1]&gt;  0.5;<br>
+       isnan_in_shader = readback[2]&gt;  0.5;<br>
+       sign_in_shader = (int) (2.0*readback[3] + 0.5) - 1;<br>
+<br>
+       /* Use a second draw call to feed value back into the shader, and read<br>
+        * out (value&gt;  0) and delta.<br>
+        */<br>
+       piglit_Uniform1f(piglit_<u></u>GetUniformLocation(prog, &quot;ref&quot;), value);<br>
+       piglit_Uniform1i(piglit_<u></u>GetUniformLocation(prog, &quot;mode&quot;), 1);<br>
+       draw_and_readback(readback);<br>
+       greater_than_zero = readback[0]&gt;  0.5;<br>
+       delta = readback[1];<br>
+<br>
+       /* Check that the behavior was as expected */<br>
+       switch (expected_behavior) {<br>
+       case B_FINITE:<br>
+               expected_behavior_string = &quot;finite&quot;;<br>
+               if (isinf_in_shader || isnan_in_shader) {<br>
+                       /* Expected finite, got Inf or NaN */<br>
+                       pass = false;<br>
+               }<br>
+               break;<br>
+       case B_POSINF:<br>
+               expected_behavior_string = &quot;+Inf&quot;;<br></div></div>
+               if (!isnan_in_shader&amp;&amp;  sign_in_shader != 1.0) {<div class="im"><br>
+                       /* Expected positive or NaN, got&lt;= 0 */<br>
+                       pass = false;<br>
+               }<br>
+               break;<br>
+       case B_NEGINF:<br>
+               expected_behavior_string = &quot;-Inf&quot;;<br></div>
+               if (!isnan_in_shader&amp;&amp;  sign_in_shader != -1.0) {<div class="im"><br>
+                       /* Expected negative or NaN, got&gt;= 0 */<br>
+                       pass = false;<br>
+               }<br>
+               break;<br>
+       default:<br>
+               expected_behavior_string = &quot;NaN&quot;;<br>
+               break;<br>
+       }<br>
+<br>
+       /* Do other sanity checks */<br></div>
+       if (isnan_in_shader&amp;&amp;  isinf_in_shader) {<div><div></div><div class="h5"><br>
+               /* No value can be simultaneously Inf and NaN */<br>
+               pass = false;<br>
+       }<br>
+       if (!isnan_in_shader) {<br>
+               if (sign_in_shader == -1 || sign_in_shader == 0) {<br>
+                       if (greater_than_zero) {<br>
+                               /* sign(value) inconsistent with (value&gt;0) */<br>
+                               pass = false;<br>
+                       }<br>
+               } else if (sign_in_shader == 1) {<br>
+                       if (!greater_than_zero) {<br>
+                               /* sign(value) inconsistent with (value&gt;0) */<br>
+                               pass = false;<br>
+                       }<br>
+               } else {<br>
+                       /* Illegal return value for sign() */<br>
+                       pass = false;<br>
+               }<br>
+       }<br>
+<br>
+       /* If we are using a high-precision technique to read data out of the<br>
+        * shader (fbo or xfb), check the behavior of isinf and isnan against<br>
+        * their C counterparts, and verify that delta ~= 0 for finite values.<br>
+        */<br>
+       if (precise) {<br>
+               bool isinf_in_c = !!isinf(value);<br>
+               bool isnan_in_c = !!isnan(value);<br>
+               if (isinf_in_shader != isinf_in_c ||<br>
+                   isnan_in_shader != isnan_in_c) {<br>
+                       /* Result of isinf() and isnan() in the shader did not<br>
+                        * match the result in C code.<br>
+                        */<br>
+                       pass = false;<br>
+               }<br></div></div>
+               if (!isinf_in_shader&amp;&amp;  !isnan_in_shader) {<div class="im"><br>
+                       float threshold = fabs(value * 1e-6);<br>
+                       if (isinf(delta) || isnan(delta) ||<br>
+                           fabs(delta)&gt;  threshold) {<br>
+                               /* The shader and C code agree that the value<br>
+                                * was finite, but it isn&#39;t behaving as a nice<br>
+                                * finite value should.<br>
+                                */<br>
+                               pass = false;<br>
+                       }<br>
+               }<br>
+       }<br>
+<br>
+       /* Output a line for the results table */<br>
+       printf(&quot;%17s %6s %5s %5s %4d %5s &quot;,<br>
+              expression,<br>
+              expected_behavior_string,<br>
+              isinf_in_shader ? &quot;true&quot; : &quot;false&quot;,<br>
+              isnan_in_shader ? &quot;true&quot; : &quot;false&quot;,<br>
+              sign_in_shader,<br>
+              greater_than_zero ? &quot;true&quot; : &quot;false&quot;);<br>
+       if (precise) {<br>
+               printf(&quot;%12f %12f &quot;, value, delta);<br>
+       }<br>
+       printf(&quot;%s\n&quot;, pass ? &quot;OK&quot; : &quot;FAIL&quot;);<br>
</div></blockquote>
<br>
We should probably only log messages for failure or when piglit_automatic is not set.<br>
<br></blockquote><div><br>Normally I would agree, but considering the amount of slop the GLSL spec allows in what generates NaN/Inf and what doesn&#39;t, it&#39;s really useful in diagnosing a failure to click on the test in the Piglit result window and see the behavior of both the passing and failing test cases. <br>
 </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
+<br>
+       piglit_UseProgram(0);<br>
+       piglit_DeleteProgram(prog);<br>
+<br>
+       return pass;<br>
+}<br>
+<br>
+enum piglit_result<br>
+piglit_display()<br>
+{<br>
+       int i;<br>
+       bool pass = true;<br>
+<br>
+       printf(&quot;    expression    expect isinf isnan sign&gt;0?&quot;);<br>
+       if (precise)<br>
+               printf(&quot;      value        delta&quot;);<br>
+       printf(&quot;\n&quot;);<br>
+<br>
+       for (i = 0; i&lt;  sizeof(expressions)/sizeof(*<u></u>expressions); ++i) {<br>
+               pass = test_expr(expressions[i].<u></u>expression,<br></div>
+                                expressions[i].expected_<u></u>behavior)&amp;&amp;  pass;<div class="im"><br>
+       }<br>
+<br>
+       return pass ? PIGLIT_PASS : PIGLIT_FAIL;<br>
+}<br>
</div></blockquote>
</blockquote></div><br>I&#39;ll send out a v2 patch once I&#39;ve reworked the test.<br>