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

Ian Romanick idr at freedesktop.org
Fri Oct 7 12:28:56 PDT 2011


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;

> +	"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.

> +	"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.

> +	"    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.

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.

> +
> +	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.

> +
> +	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;
> +}


More information about the Piglit mailing list