[Piglit] [PATCH 3/6] Ported floating point exceptions test from Glean to Piglit.
Laura Ekstrand
laura at jlekstrand.net
Mon Oct 13 14:21:36 PDT 2014
---
tests/spec/gl-1.0/CMakeLists.gl.txt | 1 +
tests/spec/gl-1.0/fpexceptions.c | 629 ++++++++++++++++++++++++++++++++++++
2 files changed, 630 insertions(+)
create mode 100644 tests/spec/gl-1.0/fpexceptions.c
diff --git a/tests/spec/gl-1.0/CMakeLists.gl.txt b/tests/spec/gl-1.0/CMakeLists.gl.txt
index f5f8c48..8726cf2 100644
--- a/tests/spec/gl-1.0/CMakeLists.gl.txt
+++ b/tests/spec/gl-1.0/CMakeLists.gl.txt
@@ -21,5 +21,6 @@ piglit_add_executable (gl-1.0-rendermode-feedback rendermode-feedback.c)
piglit_add_executable (gl-1.0-swapbuffers-behavior swapbuffers-behavior.c)
piglit_add_executable (gl-1.0-polygon-line-aa polygon-line-aa.c)
piglit_add_executable (gl-1.0-blend-func blend.c)
+piglit_add_executable (gl-1.0-fpexceptions fpexceptions.c)
# vim: ft=cmake:
diff --git a/tests/spec/gl-1.0/fpexceptions.c b/tests/spec/gl-1.0/fpexceptions.c
new file mode 100644
index 0000000..3ea9435
--- /dev/null
+++ b/tests/spec/gl-1.0/fpexceptions.c
@@ -0,0 +1,629 @@
+ /*
+ * BEGIN_COPYRIGHT -*- glean -*-
+ *
+ * Copyright (C) 1999 Allen Akin All Rights Reserved.
+ *
+ * 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 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 ALLEN AKIN 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.
+ *
+ * END_COPYRIGHT
+
+ * Authors: Brian Paul, Keith Whitwell, Laura Ekstrand
+ */
+
+/*
+ * Copyright 2014 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.
+ */
+
+ /**
+ * Test for floating point exceptions caused by +/-infinity, Nan,
+ * divide by zero, etc in a number of circumstances.
+ * TODO: Get rid of fixed pipeline stuff, but this test is really pretty fast.
+ */
+
+#include "piglit-util-gl.h"
+
+#include <math.h> /* For HUGE_VAL */
+
+#define INCLUDE_FPU_CONTROL 0
+#if INCLUDE_FPU_CONTROL
+#include <fpu_control.h>
+#endif
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+ config.supports_gl_compat_version = 13;
+
+ config.window_visual = PIGLIT_GL_VISUAL_RGBA | PIGLIT_GL_VISUAL_DOUBLE;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+void
+piglit_init(int argc, char **argv) {
+ /* Nothing to init. */
+
+} /* piglit_init */
+
+/* No idea if this actually works. */
+/* This might be useful at some point */
+void
+enable_exceptions(bool enable)
+{
+#if INCLUDE_FPU_CONTROL
+ const fpu_control_t bits =
+ _FPU_MASK_IM |
+ _FPU_MASK_DM |
+ _FPU_MASK_ZM |
+ _FPU_MASK_OM |
+ _FPU_MASK_UM;
+
+ if (enable) {
+ /* generate FP exceptions */
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask &= ~bits;
+ _FPU_SETCW(mask);
+ }
+ else {
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask |= bits;
+ _FPU_SETCW(mask);
+ }
+#else
+ (void) enable;
+#endif
+}
+
+
+
+/*
+ * XXX any endian issues with this???
+ * Works on x86 / little endian
+ */
+union fi {
+ float f;
+ struct {
+ unsigned mantissa:23;
+ unsigned exponent:8;
+ unsigned sign:1;
+ } bits;
+ unsigned ui;
+};
+
+
+static void
+make_float(float *dest, unsigned sign, unsigned exponent, unsigned mantissa)
+{
+ union fi *destfi = (union fi *) dest;
+ destfi->bits.sign = sign;
+ destfi->bits.exponent = exponent;
+ destfi->bits.mantissa = mantissa;
+}
+
+static void
+make_denorm_float(float *dest, int sign, int mantissa)
+{
+ make_float(dest, sign, 0, mantissa);
+}
+
+static void
+make_pos_inf_float(float *dest)
+{
+ make_float(dest, 0, 255, 0); /* or HUGE_VALF? */
+}
+
+static void
+make_neg_inf_float(float *dest)
+{
+ make_float(dest, 1, 255, 0); /* or -HUGE_VALF? */
+}
+
+static void
+make_signaling_nan_float(float *dest)
+{
+ make_float(dest, 0, 255, 1);
+}
+
+static void
+make_quiet_nan_float(float *dest)
+{
+ make_float(dest, 0, 255, 1 << 22);
+}
+
+static void
+make_denorm_double(double *dest, int sign, int mantissa)
+{
+ /* XXX to do */
+}
+
+static void
+make_pos_inf_double(double *dest)
+{
+ *dest = HUGE_VAL;
+}
+
+static void
+make_neg_inf_double(double *dest)
+{
+ *dest = -HUGE_VAL;
+}
+
+static void
+make_signaling_nan_double(double *dest)
+{
+ /* XXX to do */
+}
+
+static void
+make_quiet_nan_double(double *dest)
+{
+ /* XXX to do */
+}
+
+
+/* Uncomment to test float production */
+#if 0
+static void
+print_float(float f)
+{
+ union fi fi, fi2;
+ int iexp, imnt, isgn;
+
+ fi.f = f;
+ printf("float %f (%e)\n\tuint 0x%x\n\tsign %d exponent %d mantissa 0x%x\n",
+ fi.f, fi.f, fi.ui, fi.bits.sign, fi.bits.exponent, fi.bits.mantissa);
+
+ switch (fi.bits.exponent) {
+ case 0:
+ if (fi.bits.mantissa == 0)
+ printf("\t%szero\n", fi.bits.sign ? "-" : "+");
+ else {
+ printf("\tdenormalized float\n");
+
+ iexp = -126 - 23; /* -149 */
+ imnt = (int)fi.bits.mantissa;
+ isgn = fi.bits.sign ? -1 : 1;
+ fi2.f = isgn * imnt * ldexp(1.0, iexp);
+
+ printf("\trecombining: %d * 0x%x * 2.0^%d == %f (%e)\n",
+ isgn, imnt, iexp, fi2.f, fi2.f);
+ printf("\trecombined: sign %d exponent %d mantissa 0x%x\n",
+ fi2.bits.sign, fi2.bits.exponent, fi2.bits.mantissa);
+ }
+ break;
+
+ case 255:
+ if (fi.bits.mantissa & (1<<22))
+ printf("\tQNaN (Quiet NaN/indeterminate value)\n");
+ else if (fi.bits.mantissa)
+ printf("\tSNaN (Signalling NaN/invalid value)\n");
+ else
+ printf("\t%sinf\n", fi.bits.sign ? "-" : "+");
+ break;
+
+ default:
+ iexp = fi.bits.exponent - (127 + 23);
+ imnt = (1<<23) + (int)fi.bits.mantissa;
+ isgn = fi.bits.sign ? -1 : 1;
+ fi2.f = isgn * imnt * ldexp(1.0, iexp);
+
+ printf("\trecombining: %d * 0x%x * 2.0^%d == %f\n",
+ isgn, imnt, iexp, fi2.f);
+
+ printf("\trecombined: sign %d exponent %d mantissa 0x%x\n",
+ fi2.bits.sign, fi2.bits.exponent, fi2.bits.mantissa);
+ break;
+ }
+
+ /* Let's look and see what would happen if we interpret all these
+ * cases as normal floats:
+ */
+ iexp = fi.bits.exponent - (127 + 23);
+ imnt = (1<<23) + (int)fi.bits.mantissa;
+ isgn = fi.bits.sign ? -1 : 1;
+ fi2.f = isgn * imnt * ldexp(1.0, iexp);
+
+ printf("\tvalue if treated as normalized: %f (%e)\n",
+ fi2.f, fi2.f);
+}
+
+
+/* Examine some interesting floats
+ */
+int main()
+{
+ float f;
+ int i;
+
+ for (i = -3; i < 10; i++) {
+ printf("%d:\n ", i);
+ print_float(ldexp(1.0, i));
+ }
+
+ for (f = -4 ; f < 4; f += 1)
+ print_float(f);
+
+ for (f = -.01 ; f < .01; f += .002)
+ print_float(f);
+
+ f = 1.0/0;
+ print_float(f);
+
+ f += 1.0;
+ print_float(f);
+
+ /* Explicitly make a denormal - I've no idea how to create these
+ * with regular calculations:
+ */
+ make_float(&f, 0, 0, 0x1000);
+ print_float(f);
+
+ /* It seems you can just specify them!
+ */
+ f = 5.739719e-42;
+ print_float(f);
+
+ /* A little, non-denormalized float
+ */
+ make_float(&f, 0, 1, 0x1);
+ print_float(f);
+
+ /* A negative little, non-denormalized float
+ */
+ make_float(&f, 1, 1, 0x1);
+ print_float(f);
+
+ /* A big float
+ */
+ make_float(&f, 0, 254, ~0);
+ print_float(f);
+
+ make_float(&f, 1, 254, ~0);
+ print_float(f);
+
+ /* Littlest and biggest denormals:
+ */
+ make_float(&f, 0, 0, 1);
+ print_float(f);
+ make_float(&f, 0, 0, ~0);
+ print_float(f);
+
+
+ make_float(&f, 1, 0, 1);
+ print_float(f);
+ make_float(&f, 1, 0, ~0);
+ print_float(f);
+
+}
+#endif
+
+enum mode {
+ MODE_INFINITY,
+ MODE_NAN,
+ MODE_DIVZERO,
+ MODE_DENORM,
+ MODE_OVERFLOW
+};
+
+bool
+test_vertices(enum mode m)
+{
+ bool pass = true;
+ int i;
+
+ /* Make three nice vertices */
+ float v[3][4];
+ for (i = 0; i < 3; i++) {
+ v[i][0] = 0.0;
+ v[i][1] = 0.0;
+ v[i][2] = 0.0;
+ v[i][3] = 1.0;
+ }
+
+ /* Set problematic values */
+ switch (m) {
+ case MODE_INFINITY:
+ make_pos_inf_float(&v[1][0]);
+ make_neg_inf_float(&v[2][1]);
+ break;
+ case MODE_NAN:
+ make_signaling_nan_float(&v[1][0]);
+ make_quiet_nan_float(&v[2][1]);
+ break;
+ case MODE_DIVZERO:
+ v[0][3] = 0.0;
+ v[1][3] = 0.0;
+ v[2][3] = 0.0;
+ break;
+ case MODE_DENORM:
+ make_denorm_float(&v[0][0], 0, 1);
+ make_denorm_float(&v[1][1], 1, 1);
+ break;
+ default:
+ ; /* nothing */
+ }
+
+ /* Send the vertices to GL, using them in multiple ways */
+ /* As geometry */
+ glBegin(GL_POLYGON);
+ glVertex4fv(v[0]);
+ glVertex4fv(v[1]);
+ glVertex4fv(v[2]);
+ glEnd();
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ /* As colors */
+ glBegin(GL_POLYGON);
+ glColor4fv(v[0]); glVertex2f(-1, -1);
+ glColor4fv(v[1]); glVertex2f( 1, -1);
+ glColor4fv(v[2]); glVertex2f( 0, 1);
+ glEnd();
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ /* As lighting normals */
+ glEnable(GL_LIGHTING);
+ glBegin(GL_POLYGON);
+ glNormal3fv(v[0]); glVertex2f(-1, -1);
+ glNormal3fv(v[1]); glVertex2f( 1, -1);
+ glNormal3fv(v[2]); glVertex2f( 0, 1);
+ glEnd();
+ glDisable(GL_LIGHTING);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ /* As texture coordinates */
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_POLYGON);
+ glTexCoord4fv(v[0]); glVertex2f(-1, -1);
+ glTexCoord4fv(v[1]); glVertex2f( 1, -1);
+ glTexCoord4fv(v[2]); glVertex2f( 0, 1);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ return pass;
+}
+
+
+bool
+test_transformation(enum mode m)
+{
+ bool pass = true;
+ int i;
+ float mat[16];
+
+ /* Create an identity matrix */
+ for (i = 0; i < 15; i++)
+ mat[i] = 0.0;
+ mat[0] = mat[5] = mat[10] = mat[15] = 1.0;
+
+ /* Set problematic values */
+ switch (m) {
+ case MODE_INFINITY:
+ make_pos_inf_float(&mat[0]); /* X scale */
+ make_neg_inf_float(&mat[13]); /* Y translate */
+ break;
+ case MODE_NAN:
+ make_signaling_nan_float(&mat[0]); /* X scale */
+ make_quiet_nan_float(&mat[13]); /* Y translate */
+ break;
+ case MODE_DIVZERO:
+ /* all zero matrix */
+ mat[0] = mat[5] = mat[10] = mat[15] = 0.0;
+ break;
+ case MODE_DENORM:
+ make_denorm_float(&mat[0], 0, 1);
+ make_denorm_float(&mat[13], 1, 1);
+ break;
+ default:
+ ; /* nothing */
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ /* Send matrix to GL */
+ glLoadMatrixf(mat);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ /* Vertices */
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+ glEnd();
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ glPopMatrix();
+
+ return pass;
+}
+
+
+bool
+test_clipping(enum mode m)
+{
+ bool pass = true;
+ /* TODO: Implement MODE_NAN and MODE_DENORM */
+ double plane[4];
+
+ /* Start w/ nice values */
+ plane[0] = plane[1] = plane[2] = plane[3] = 0.0;
+
+ /* Set problematic values */
+ switch (m) {
+ case MODE_INFINITY:
+ make_pos_inf_double(&plane[0]);
+ make_neg_inf_double(&plane[3]);
+ break;
+ /*
+ * case MODE_NAN:
+ * make_signaling_nan_double(&plane[0]);
+ * make_quiet_nan_double(&plane[3]);
+ * break;
+ */
+ case MODE_DIVZERO:
+ /* nothing */
+ break;
+ /*
+ * case MODE_DENORM:
+ * make_denorm_double(&plane[0], 0, 1);
+ * make_denorm_double(&plane[3], 1, 1);
+ * break;
+ */
+ case MODE_OVERFLOW:
+ plane[0] = 1.0e300;
+ plane[3] = 1.0e-300;
+ break;
+ default:
+ ; /* nothing */
+ }
+
+ /* Send plane to GL to use for clipping */
+ glClipPlane(GL_CLIP_PLANE0, plane);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+ glEnable(GL_CLIP_PLANE0);
+
+ /* Some vertex positions */
+ glBegin(GL_POLYGON);
+ glVertex2f(-1, -1);
+ glVertex2f( 1, -1);
+ glVertex2f( 0, 1);
+ glEnd();
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ glDisable(GL_CLIP_PLANE0);
+
+ return pass;
+}
+
+
+/**
+ * Pass large doubles to OpenGL and see what
+ * happens when converted to float.
+ */
+bool
+test_float_overflow(void)
+{
+ bool pass = true;
+ int i;
+ GLdouble v[3][4];
+ GLdouble mat[16];
+
+ /* Make some nice vertices */
+ for (i = 0; i < 3; i++) {
+ v[i][0] = 0.0;
+ v[i][1] = 0.0;
+ v[i][2] = 0.0;
+ v[i][3] = 1.0;
+ }
+
+ /* Set problematic values */
+ v[0][0] = 1.0e300;
+ v[0][1] = -1.0e300;
+ v[1][0] = 1.0e-300;
+ v[1][1] = 1.0e-300;
+
+ /* Create a problematic matrix */
+ /* Identity * a scalar value of 1e100 */
+ for (i = 0; i < 15; i++)
+ mat[i] = 0.0;
+ mat[0] = mat[5] = mat[10] = mat[15] = 1.0e100;
+
+ /*
+ * Why are these functions the double version?
+ *
+ * Answer: Because the GL driver may not support double precision and may
+ * automatically convert the doubles to floats.
+ * (See glLoadMatrix in OpenGL 2.1 Reference Pages)
+ */
+
+ /* Send matrix to GL */
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixd(mat);
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ /* Send vertices to GL */
+ glBegin(GL_POLYGON);
+ glVertex4dv(v[0]);
+ glVertex4dv(v[1]);
+ glVertex4dv(v[2]);
+ glEnd();
+ pass &= piglit_check_gl_error(GL_NO_ERROR);
+
+ glPopMatrix();
+
+ return pass;
+}
+
+enum piglit_result
+piglit_display(void)
+{
+ bool pass = true;
+
+ /*
+ * These tests are supposed to succeed. GL is not supposed to
+ * throw errors for these things.
+ * Original Glean test passes in every case.
+ */
+ pass &= test_vertices(MODE_INFINITY);
+ pass &= test_vertices(MODE_NAN);
+ pass &= test_vertices(MODE_DIVZERO);
+ pass &= test_vertices(MODE_DENORM);
+
+ pass &= test_transformation(MODE_INFINITY);
+ pass &= test_transformation(MODE_NAN);
+ pass &= test_transformation(MODE_DIVZERO);
+ pass &= test_transformation(MODE_DENORM);
+
+ pass &= test_clipping(MODE_INFINITY);
+ pass &= test_clipping(MODE_NAN);
+ pass &= test_clipping(MODE_DIVZERO);
+ pass &= test_clipping(MODE_DENORM);
+ pass &= test_clipping(MODE_OVERFLOW);
+
+ pass &= test_float_overflow();
+
+ if (!piglit_automatic)
+ piglit_present_results();
+
+ return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+} /* piglit_display */
--
2.1.0
More information about the Piglit
mailing list