Add more structure constructor tests.
[piglit/hramrach.git] / tests / glean / tfpexceptions.cpp
blob2038007a75467a2a17b8bd2b4d49f0671a031b70
1 // BEGIN_COPYRIGHT -*- glean -*-
2 //
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
4 //
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
12 // conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
16 // Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
26 //
27 // END_COPYRIGHT
29 // Authors: Brian Paul, Keith Whitwell
31 #include "tfpexceptions.h"
32 #include <cassert>
33 #include <cmath>
35 #define INCLUDE_FPU_CONTROL 0
36 #if INCLUDE_FPU_CONTROL
37 #include <fpu_control.h>
38 #endif
41 namespace GLEAN {
44 // This might be useful at some point
45 void
46 FPExceptionsTest::enableExceptions(bool enable)
48 #if INCLUDE_FPU_CONTROL
49 const fpu_control_t bits =
50 _FPU_MASK_IM |
51 _FPU_MASK_DM |
52 _FPU_MASK_ZM |
53 _FPU_MASK_OM |
54 _FPU_MASK_UM;
56 if (enable) {
57 /* generate FP exceptions */
58 fpu_control_t mask;
59 _FPU_GETCW(mask);
60 mask &= ~bits;
61 _FPU_SETCW(mask);
63 else {
64 fpu_control_t mask;
65 _FPU_GETCW(mask);
66 mask |= bits;
67 _FPU_SETCW(mask);
69 #else
70 (void) enable;
71 #endif
76 // XXX any endian issues with this???
77 // Works on x86 / little endian
78 union fi {
79 float f;
80 struct {
81 unsigned mantissa:23;
82 unsigned exponent:8;
83 unsigned sign:1;
84 } bits;
85 unsigned ui;
89 static void
90 make_float(float *dest, unsigned sign, unsigned exponent, unsigned mantissa)
92 union fi *destfi = (union fi *) dest;
93 destfi->bits.sign = sign;
94 destfi->bits.exponent = exponent;
95 destfi->bits.mantissa = mantissa;
98 static void
99 make_denorm_float(float *dest, int sign, int mantissa)
101 make_float(dest, sign, 0, mantissa);
104 static void
105 make_pos_inf_float(float *dest)
107 make_float(dest, 0, 255, 0); // or HUGE_VALF?
110 static void
111 make_neg_inf_float(float *dest)
113 make_float(dest, 1, 255, 0); // or -HUGE_VALF?
116 static void
117 make_signaling_nan_float(float *dest)
119 make_float(dest, 0, 255, 1);
122 static void
123 make_quiet_nan_float(float *dest)
125 make_float(dest, 0, 255, 1 << 22);
128 static void
129 make_denorm_double(double * /*dest*/, int /*sign*/, int /*mantissa*/)
131 // XXX to do
134 static void
135 make_pos_inf_double(double *dest)
137 *dest = HUGE_VAL;
140 static void
141 make_neg_inf_double(double *dest)
143 *dest = -HUGE_VAL;
146 static void
147 make_signaling_nan_double(double * /*dest*/)
149 // XXX to do
152 static void
153 make_quiet_nan_double(double * /*dest*/)
155 // XXX to do
159 static void
160 print_float(float f)
162 union fi fi, fi2;
163 int iexp, imnt, isgn;
165 fi.f = f;
166 printf("float %f (%e)\n\tuint 0x%x\n\tsign %d exponent %d mantissa 0x%x\n",
167 fi.f, fi.f, fi.ui, fi.bits.sign, fi.bits.exponent, fi.bits.mantissa);
169 switch (fi.bits.exponent) {
170 case 0:
171 if (fi.bits.mantissa == 0)
172 printf("\t%szero\n", fi.bits.sign ? "-" : "+");
173 else {
174 printf("\tdenormalized float\n");
176 iexp = -126 - 23; /* -149 */
177 imnt = (int)fi.bits.mantissa;
178 isgn = fi.bits.sign ? -1 : 1;
179 fi2.f = isgn * imnt * ldexp(1.0, iexp);
181 printf("\trecombining: %d * 0x%x * 2.0^%d == %f (%e)\n",
182 isgn, imnt, iexp, fi2.f, fi2.f);
183 printf("\trecombined: sign %d exponent %d mantissa 0x%x\n",
184 fi2.bits.sign, fi2.bits.exponent, fi2.bits.mantissa);
186 break;
188 case 255:
189 if (fi.bits.mantissa & (1<<22))
190 printf("\tQNaN (Quiet NaN/indeterminate value)\n");
191 else if (fi.bits.mantissa)
192 printf("\tSNaN (Signalling NaN/invalid value)\n");
193 else
194 printf("\t%sinf\n", fi.bits.sign ? "-" : "+");
195 break;
197 default:
198 iexp = fi.bits.exponent - (127 + 23);
199 imnt = (1<<23) + (int)fi.bits.mantissa;
200 isgn = fi.bits.sign ? -1 : 1;
201 fi2.f = isgn * imnt * ldexp(1.0, iexp);
203 printf("\trecombining: %d * 0x%x * 2.0^%d == %f\n",
204 isgn, imnt, iexp, fi2.f);
206 printf("\trecombined: sign %d exponent %d mantissa 0x%x\n",
207 fi2.bits.sign, fi2.bits.exponent, fi2.bits.mantissa);
208 break;
211 /* Let's look and see what would happen if we interpret all these
212 * cases as normal floats:
214 iexp = fi.bits.exponent - (127 + 23);
215 imnt = (1<<23) + (int)fi.bits.mantissa;
216 isgn = fi.bits.sign ? -1 : 1;
217 fi2.f = isgn * imnt * ldexp(1.0, iexp);
219 printf("\tvalue if treated as normalized: %f (%e)\n",
220 fi2.f, fi2.f);
224 /* Examine some interesting floats
226 #if 0
227 int main()
229 float f;
230 int i;
232 for (i = -3; i < 10; i++) {
233 printf("%d:\n ", i);
234 print_float(ldexp(1.0, i));
237 for (f = -4 ; f < 4; f += 1)
238 print_float(f);
240 for (f = -.01 ; f < .01; f += .002)
241 print_float(f);
243 f = 1.0/0;
244 print_float(f);
246 f += 1.0;
247 print_float(f);
249 /* Explicitly make a denormal - I've no idea how to create these
250 * with regular calculations:
252 make_float(&f, 0, 0, 0x1000);
253 print_float(f);
255 /* It seems you can just specify them!
257 f = 5.739719e-42;
258 print_float(f);
260 /* A little, non-denormalized float
262 make_float(&f, 0, 1, 0x1);
263 print_float(f);
265 /* A negative little, non-denormalized float
267 make_float(&f, 1, 1, 0x1);
268 print_float(f);
270 /* A big float
272 make_float(&f, 0, 254, ~0);
273 print_float(f);
275 make_float(&f, 1, 254, ~0);
276 print_float(f);
278 /* Littlest and biggest denormals:
280 make_float(&f, 0, 0, 1);
281 print_float(f);
282 make_float(&f, 0, 0, ~0);
283 print_float(f);
286 make_float(&f, 1, 0, 1);
287 print_float(f);
288 make_float(&f, 1, 0, ~0);
289 print_float(f);
292 #endif
295 bool
296 FPExceptionsTest::testVertices(Mode m)
298 float v[3][4];
299 // nice coords
300 for (int i = 0; i < 3; i++) {
301 v[i][0] = 0.0;
302 v[i][1] = 0.0;
303 v[i][2] = 0.0;
304 v[i][3] = 1.0;
307 // set problematic values
308 switch (m) {
309 case MODE_INFINITY:
310 make_pos_inf_float(&v[1][0]);
311 make_neg_inf_float(&v[2][1]);
312 break;
313 case MODE_NAN:
314 make_signaling_nan_float(&v[1][0]);
315 make_quiet_nan_float(&v[2][1]);
316 break;
317 case MODE_DIVZERO:
318 v[0][3] = 0.0;
319 v[1][3] = 0.0;
320 v[2][3] = 0.0;
321 break;
322 case MODE_DENORM:
323 make_denorm_float(&v[0][0], 0, 1);
324 make_denorm_float(&v[1][1], 1, 1);
325 break;
326 default:
327 ; // nothing
330 // vertex positions
331 glBegin(GL_POLYGON);
332 glVertex4fv(v[0]);
333 glVertex4fv(v[1]);
334 glVertex4fv(v[2]);
335 glEnd();
337 // colors
338 glBegin(GL_POLYGON);
339 glColor4fv(v[0]); glVertex2f(-1, -1);
340 glColor4fv(v[1]); glVertex2f( 1, -1);
341 glColor4fv(v[2]); glVertex2f( 0, 1);
342 glEnd();
344 // normals
345 glEnable(GL_LIGHTING);
346 glBegin(GL_POLYGON);
347 glNormal3fv(v[0]); glVertex2f(-1, -1);
348 glNormal3fv(v[1]); glVertex2f( 1, -1);
349 glNormal3fv(v[2]); glVertex2f( 0, 1);
350 glEnd();
351 glDisable(GL_LIGHTING);
353 // texcoords
354 glEnable(GL_TEXTURE_2D);
355 glBegin(GL_POLYGON);
356 glTexCoord4fv(v[0]); glVertex2f(-1, -1);
357 glTexCoord4fv(v[1]); glVertex2f( 1, -1);
358 glTexCoord4fv(v[2]); glVertex2f( 0, 1);
359 glEnd();
360 glDisable(GL_TEXTURE_2D);
362 return true;
366 bool
367 FPExceptionsTest::testTransformation(Mode m)
369 float mat[16];
371 // identity
372 for (int i = 0; i < 15; i++)
373 mat[i] = 0.0;
374 mat[0] = mat[5] = mat[10] = mat[15] = 1.0;
376 // set problematic values
377 switch (m) {
378 case MODE_INFINITY:
379 make_pos_inf_float(&mat[0]); // X scale
380 make_neg_inf_float(&mat[13]); // Y translate
381 break;
382 case MODE_NAN:
383 make_signaling_nan_float(&mat[0]); // X scale
384 make_quiet_nan_float(&mat[13]); // Y translate
385 break;
386 case MODE_DIVZERO:
387 // all zero matrix
388 mat[0] = mat[5] = mat[10] = mat[15] = 0.0;
389 break;
390 case MODE_DENORM:
391 make_denorm_float(&mat[0], 0, 1);
392 make_denorm_float(&mat[13], 1, 1);
393 break;
394 default:
395 ; // nothing
398 glMatrixMode(GL_MODELVIEW);
399 glPushMatrix();
400 glLoadMatrixf(mat);
402 // vertex positions
403 glBegin(GL_POLYGON);
404 glVertex2f(-1, -1);
405 glVertex2f( 1, -1);
406 glVertex2f( 0, 1);
407 glEnd();
409 glPopMatrix();
411 return true;
415 bool
416 FPExceptionsTest::testClipping(Mode m)
418 double plane[4];
420 // start w/ nice values
421 plane[0] = plane[1] = plane[2] = plane[3] = 0.0;
423 // set problematic values
424 switch (m) {
425 case MODE_INFINITY:
426 make_pos_inf_double(&plane[0]);
427 make_neg_inf_double(&plane[3]);
428 break;
429 case MODE_NAN:
430 make_signaling_nan_double(&plane[0]);
431 make_quiet_nan_double(&plane[3]);
432 break;
433 case MODE_DIVZERO:
434 // nothing
435 break;
436 case MODE_DENORM:
437 make_denorm_double(&plane[0], 0, 1);
438 make_denorm_double(&plane[3], 1, 1);
439 break;
440 case MODE_OVERFLOW:
441 plane[0] = 1.0e300;
442 plane[3] = 1.0e-300;
443 break;
444 default:
445 ; // nothing
448 glClipPlane(GL_CLIP_PLANE0, plane);
449 glEnable(GL_CLIP_PLANE0);
451 // vertex positions
452 glBegin(GL_POLYGON);
453 glVertex2f(-1, -1);
454 glVertex2f( 1, -1);
455 glVertex2f( 0, 1);
456 glEnd();
458 glDisable(GL_CLIP_PLANE0);
460 return true;
464 // pass large doubles to OpenGL and see what happens when converted to float.
465 bool
466 FPExceptionsTest::testOverflow(void)
468 GLdouble v[3][4];
469 for (int i = 0; i < 3; i++) {
470 v[i][0] = 0.0;
471 v[i][1] = 0.0;
472 v[i][2] = 0.0;
473 v[i][3] = 1.0;
475 v[0][0] = 1.0e300;
476 v[0][1] = -1.0e300;
477 v[1][0] = 1.0e-300;
478 v[1][1] = 1.0e-300;
480 GLdouble mat[16];
481 for (int i = 0; i < 15; i++)
482 mat[i] = 0.0;
483 mat[0] = mat[5] = mat[10] = mat[15] = 1.0e100;
485 glMatrixMode(GL_MODELVIEW);
486 glPushMatrix();
487 glLoadMatrixd(mat);
489 glBegin(GL_POLYGON);
490 glVertex4dv(v[0]);
491 glVertex4dv(v[1]);
492 glVertex4dv(v[2]);
493 glEnd();
495 glPopMatrix();
497 return true;
502 void
503 FPExceptionsTest::setup(void)
505 // Simple texture map
506 static const GLfloat texImage[2][2][3] = {
507 { {1, 1, 1}, {0, 0, 0} },
508 { {0, 0, 0}, {1, 1, 1} }
511 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
512 GL_RGB, GL_FLOAT, texImage);
513 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
514 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
516 // simple lighting
517 glEnable(GL_LIGHT0);
518 glEnable(GL_LIGHT1);
519 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
523 void
524 FPExceptionsTest::reportPassFail(MultiTestResult &r,
525 bool pass, const char *msg) const
527 if (pass) {
528 if (env->options.verbosity)
529 env->log << name << " PASS: " << msg << " test\n";
530 r.numPassed++;
532 else {
533 if (env->options.verbosity)
534 env->log << name << " FAILURE: " << msg << " test\n";
535 r.numFailed++;
539 void
540 FPExceptionsTest::runOne(MultiTestResult &r, Window &w)
542 bool p;
544 (void) w;
546 p = testVertices(MODE_INFINITY);
547 reportPassFail(r, p, "Infinite value vertex");
549 p = testVertices(MODE_NAN);
550 reportPassFail(r, p, "NaN value vertex");
552 p = testVertices(MODE_DIVZERO);
553 reportPassFail(r, p, "Divide by zero vertex");
555 p = testVertices(MODE_DENORM);
556 reportPassFail(r, p, "Denorm vertex");
559 p = testTransformation(MODE_INFINITY);
560 reportPassFail(r, p, "Infinite matrix transform");
562 p = testTransformation(MODE_NAN);
563 reportPassFail(r, p, "NaN matrix transform");
565 p = testTransformation(MODE_DIVZERO);
566 reportPassFail(r, p, "Zero matrix transform");
568 p = testTransformation(MODE_DENORM);
569 reportPassFail(r, p, "Denorm matrix transform");
572 p = testClipping(MODE_INFINITY);
573 reportPassFail(r, p, "Infinite clip plane");
575 p = testClipping(MODE_NAN);
576 reportPassFail(r, p, "NaN clip plane");
578 p = testClipping(MODE_DIVZERO);
579 reportPassFail(r, p, "Zero clip plane");
581 p = testClipping(MODE_DENORM);
582 reportPassFail(r, p, "Denorm clip plane");
584 p = testClipping(MODE_OVERFLOW);
585 reportPassFail(r, p, "Overflow clip plane");
588 p = testOverflow();
589 reportPassFail(r, p, "Overflow");
591 r.pass = (r.numFailed == 0);
595 // The test object itself:
596 FPExceptionsTest FPExceptionsTest("fpexceptions", // test name
597 "window, rgb", // surface/pixel format
598 "", // no extensions required
599 "Test for floating point exceptions caused by +/-infinity, Nan, divide by zero, etc in a number of circumstances.\n");
602 } // namespace GLEAN