[Piglit] [PATCH] Add a test of isinf() and isnan() functionality.

Paul Berry stereotype441 at gmail.com
Fri Oct 7 13:26:55 PDT 2011


On 7 October 2011 12:28, Ian Romanick <idr at freedesktop.org> wrote:

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

> At the very least, you can initialize its value in the shader:
>
> uniform float z = 0.0;
>
>
Ok, I will do this and make a comment to explain that z is present to defeat
constant folding.


>
>  +       "uniform float u_inf;\n"
>> +       "uniform float u_minus_inf;\n"
>> +       "uniform float u_nan;\n"
>> +       "uniform float ref;\n"
>> +       "uniform int mode;\n"
>> +       "%s" /* Either vs_boilerplate or fs_boilerplate */
>>
>
> Yuck.  There's no reason to concatenate the shader strings in the
> application code.  There are two better ways to do this in GLSL:
>
> 1. Multiple compilation units.
>
> 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'd just do:
>
>        piglit_compile_shader_text_**varags(GL_FRAGMENT_SHADER,
>                                shader_template,
>                                fs_boilerplate,
>                                NULL);
>
> Or something like that.
>
> One way that I'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 "generic" shader target that you could compile to, this
> would be even easier.


Ok, fair point.  I'll restructure the test using multiple compilation units.


>
>
>  +       "void main()\n"
>> +       "{\n"
>> +       "  do_common_shader_operations();**\n"
>> +       "  float value = %s;\n" /* Expression to be tested */
>>
>
> In the do_test style, this would just become
>
>    float value = do_test();
>
>
>  +       "  if (mode == 0) {\n"
>>
>
> I'd like to see an enum or some #defines in the C code to explain the
> values of mode.


Ok, fair point.


>
>
>  +       "    output_result(vec4(value,\n"
>> +       "                       isinf(value) ? 1 : 0,\n"
>> +       "                       isnan(value) ? 1 : 0,\n"
>> +       "                       (sign(value) + 1.0) / 2.0));\n"
>> +       "  } else if (mode == 1) {\n"
>> +       "    output_result(vec4(value>  0 ? 1 : 0,\n"
>> +       "                       value - ref,\n"
>> +       "                       0.0,\n"
>> +       "                       0.0));\n"
>> +       "  } else {\n"
>> +       "    /* Ensure all uniforms are used */\n"
>> +       "    output_result(vec4(z + u_inf + u_minus_inf + u_nan));\n"
>> +       "  }\n"
>> +       "}\n";
>> +
>> +static const char vs_boilerplate[] =
>> +       "flat out vec4 data;\n"
>> +       "void do_common_shader_operations()\**n"
>> +       "{\n"
>> +       "  gl_Position = gl_Vertex;\n"
>> +       "}\n"
>> +       "void output_result(vec4 result)\n"
>> +       "{\n"
>> +       "  data = result;\n"
>> +       "}\n";
>> +
>> +static const char fs_boilerplate[] =
>> +       "void do_common_shader_operations()\**n"
>> +       "{\n"
>> +       "}\n"
>> +       "void output_result(vec4 result)\n"
>> +       "{\n"
>> +       "  gl_FragColor = result;\n"
>> +       "}\n";
>>
>
> Also yuck.  Since this test will require GLSL 1.30 and OpenGL 3.0, you can
> just make a fragment shader output called result.
>
> out vec4 result;
>
> Mesa doesn't have glBindFragDataLocation yet, but you can use explicit
> attribute locations.  Something like:
>
> #version 130
> #extension GL_ARB_explicit_attrib_**location: enable
>
> #if defined GL_ARB_explicit_attrib_**location
> layout(location = 0)
> #endif
>    out vec4 result;
>
> In the application, you'll have to call glBindFragDataLocation if
> GL_ARB_explicit_attrib_**location isn't supported.
>

Ok, I think I see why you had a "yuck" reaction to the output_result()
function above, but I'm having a "yuck" 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's
revisit this question after I've done the rework and see if it's still
objectionable to you.


>
> The other alternative, if we really care about GLSL 1.30 without OpenGL
> 3.0, is
>
> #define result gl_FragColor
>

>
>  +
>> +void
>> +setup_fbo()
>> +{
>> +       piglit_require_extension("GL_**ARB_framebuffer_object");
>> +       piglit_require_extension("GL_**ARB_texture_float");
>> +
>> +       GLuint fb = 0;
>> +       GLuint color_rb = 0;
>> +       GLenum fb_status;
>> +
>> +       glGenFramebuffers(1,&fb);
>> +       glBindFramebuffer(GL_**FRAMEBUFFER, fb);
>> +
>> +       /* Bind color attachment. */
>> +       glGenRenderbuffers(1,&color_**rb);
>> +       glBindRenderbuffer(GL_**RENDERBUFFER, color_rb);
>> +       glRenderbufferStorage(GL_**RENDERBUFFER, GL_RGBA32F,
>> +                             piglit_width, piglit_height);
>> +       glFramebufferRenderbuffer(GL_**DRAW_FRAMEBUFFER,
>> GL_COLOR_ATTACHMENT0,
>> +                                 GL_RENDERBUFFER, color_rb);
>> +       piglit_check_gl_error(0, PIGLIT_FAIL);
>> +
>> +       fb_status = glCheckFramebufferStatus(GL_**FRAMEBUFFER);
>> +       if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
>> +               printf("error: FBO incomplete (status = 0x%04x)\n",
>> fb_status);
>> +               piglit_report_result(PIGLIT_**SKIP);
>> +       }
>> +
>> +       glBindFramebuffer(GL_DRAW_**FRAMEBUFFER, fb);
>> +       glBindFramebuffer(GL_READ_**FRAMEBUFFER, fb);
>> +}
>> +
>> +void
>> +setup_xfb()
>> +{
>> +       piglit_require_extension("GL_**EXT_transform_feedback");
>>
>
> Even though you're requiring GL_EXT_transform_feedback, you're using the
> function names from OpenGL 3.0.  This will fail on any system that supports
> the EXT but doesn't support OpenGL 3.0.  I think it's best to just require
> OpenGL 3.0 here.
>
> The other option is to require "any" of the transform feedback flavors and
> have piglit_ wrapper functions.
>
>
I think I'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.


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


>  +
>> +       piglit_UseProgram(0);
>> +       piglit_DeleteProgram(prog);
>> +
>> +       return pass;
>> +}
>> +
>> +enum piglit_result
>> +piglit_display()
>> +{
>> +       int i;
>> +       bool pass = true;
>> +
>> +       printf("    expression    expect isinf isnan sign>0?");
>> +       if (precise)
>> +               printf("      value        delta");
>> +       printf("\n");
>> +
>> +       for (i = 0; i<  sizeof(expressions)/sizeof(***expressions); ++i)
>> {
>> +               pass = test_expr(expressions[i].**expression,
>> +                                expressions[i].expected_**behavior)&&
>>  pass;
>>
>> +       }
>> +
>> +       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
>> +}
>>
>
I'll send out a v2 patch once I've reworked the test.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/piglit/attachments/20111007/5726ea4a/attachment-0001.html>


More information about the Piglit mailing list