Home | History | Annotate | Download | only in math
      1 
      2 /*
      3  * Mesa 3-D graphics library
      4  *
      5  * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Gareth Hughes
     27  */
     28 
     29 #include "c99_math.h"
     30 #include "main/glheader.h"
     31 #include "main/context.h"
     32 #include "main/macros.h"
     33 #include "main/imports.h"
     34 
     35 #include "m_matrix.h"
     36 #include "m_xform.h"
     37 
     38 #include "m_debug.h"
     39 #include "m_debug_util.h"
     40 
     41 
     42 #ifdef __UNIXOS2__
     43 /* The linker doesn't like empty files */
     44 static char dummy;
     45 #endif
     46 
     47 #ifdef DEBUG_MATH  /* This code only used for debugging */
     48 
     49 
     50 static int m_norm_identity[16] = {
     51    ONE, NIL, NIL, NIL,
     52    NIL, ONE, NIL, NIL,
     53    NIL, NIL, ONE, NIL,
     54    NIL, NIL, NIL, NIL
     55 };
     56 static int m_norm_general[16] = {
     57    VAR, VAR, VAR, NIL,
     58    VAR, VAR, VAR, NIL,
     59    VAR, VAR, VAR, NIL,
     60    NIL, NIL, NIL, NIL
     61 };
     62 static int m_norm_no_rot[16] = {
     63    VAR, NIL, NIL, NIL,
     64    NIL, VAR, NIL, NIL,
     65    NIL, NIL, VAR, NIL,
     66    NIL, NIL, NIL, NIL
     67 };
     68 static int *norm_templates[8] = {
     69    m_norm_no_rot,
     70    m_norm_no_rot,
     71    m_norm_no_rot,
     72    m_norm_general,
     73    m_norm_general,
     74    m_norm_general,
     75    m_norm_identity,
     76    m_norm_identity
     77 };
     78 static int norm_types[8] = {
     79    NORM_TRANSFORM_NO_ROT,
     80    NORM_TRANSFORM_NO_ROT | NORM_RESCALE,
     81    NORM_TRANSFORM_NO_ROT | NORM_NORMALIZE,
     82    NORM_TRANSFORM,
     83    NORM_TRANSFORM | NORM_RESCALE,
     84    NORM_TRANSFORM | NORM_NORMALIZE,
     85    NORM_RESCALE,
     86    NORM_NORMALIZE
     87 };
     88 static int norm_scale_types[8] = {               /*  rescale factor          */
     89    NIL,                                          /*  NIL disables rescaling  */
     90    VAR,
     91    NIL,
     92    NIL,
     93    VAR,
     94    NIL,
     95    VAR,
     96    NIL
     97 };
     98 static int norm_normalize_types[8] = {           /*  normalizing ?? (no = 0) */
     99    0,
    100    0,
    101    1,
    102    0,
    103    0,
    104    1,
    105    0,
    106    1
    107 };
    108 static char *norm_strings[8] = {
    109    "NORM_TRANSFORM_NO_ROT",
    110    "NORM_TRANSFORM_NO_ROT | NORM_RESCALE",
    111    "NORM_TRANSFORM_NO_ROT | NORM_NORMALIZE",
    112    "NORM_TRANSFORM",
    113    "NORM_TRANSFORM | NORM_RESCALE",
    114    "NORM_TRANSFORM | NORM_NORMALIZE",
    115    "NORM_RESCALE",
    116    "NORM_NORMALIZE"
    117 };
    118 
    119 
    120 /* =============================================================
    121  * Reference transformations
    122  */
    123 
    124 static void ref_norm_transform_rescale( const GLmatrix *mat,
    125 					GLfloat scale,
    126 					const GLvector4f *in,
    127 					const GLfloat *lengths,
    128 					GLvector4f *dest )
    129 {
    130    GLuint i;
    131    const GLfloat *s = in->start;
    132    const GLfloat *m = mat->inv;
    133    GLfloat (*out)[4] = (GLfloat (*)[4]) dest->start;
    134 
    135    (void) lengths;
    136 
    137    for ( i = 0 ; i < in->count ; i++ ) {
    138       GLfloat t[3];
    139 
    140       TRANSFORM_NORMAL( t, s, m );
    141       SCALE_SCALAR_3V( out[i], scale, t );
    142 
    143       s = (GLfloat *)((char *)s + in->stride);
    144    }
    145 }
    146 
    147 static void ref_norm_transform_normalize( const GLmatrix *mat,
    148 					  GLfloat scale,
    149 					  const GLvector4f *in,
    150 					  const GLfloat *lengths,
    151 					  GLvector4f *dest )
    152 {
    153    GLuint i;
    154    const GLfloat *s = in->start;
    155    const GLfloat *m = mat->inv;
    156    GLfloat (*out)[4] = (GLfloat (*)[4]) dest->start;
    157 
    158    for ( i = 0 ; i < in->count ; i++ ) {
    159       GLfloat t[3];
    160 
    161       TRANSFORM_NORMAL( t, s, m );
    162 
    163       if ( !lengths ) {
    164          GLfloat len = LEN_SQUARED_3FV( t );
    165          if ( len > 1e-20 ) {
    166 	    /* Hmmm, don't know how we could test the precalculated
    167 	     * length case...
    168 	     */
    169             scale = 1.0f / sqrtf(len);
    170 	    SCALE_SCALAR_3V( out[i], scale, t );
    171          } else {
    172             out[i][0] = out[i][1] = out[i][2] = 0;
    173          }
    174       } else {
    175          scale = lengths[i];
    176 	 SCALE_SCALAR_3V( out[i], scale, t );
    177       }
    178 
    179       s = (GLfloat *)((char *)s + in->stride);
    180    }
    181 }
    182 
    183 
    184 /* =============================================================
    185  * Normal transformation tests
    186  */
    187 
    188 static void init_matrix( GLfloat *m )
    189 {
    190    m[0] = 63.0; m[4] = 43.0; m[ 8] = 29.0; m[12] = 43.0;
    191    m[1] = 55.0; m[5] = 17.0; m[ 9] = 31.0; m[13] =  7.0;
    192    m[2] = 44.0; m[6] =  9.0; m[10] =  7.0; m[14] =  3.0;
    193    m[3] = 11.0; m[7] = 23.0; m[11] = 91.0; m[15] =  9.0;
    194 }
    195 
    196 
    197 static int test_norm_function( normal_func func, int mtype, long *cycles )
    198 {
    199    GLvector4f source[1], dest[1], dest2[1], ref[1], ref2[1];
    200    GLmatrix mat[1];
    201    GLfloat s[TEST_COUNT][5], d[TEST_COUNT][4], r[TEST_COUNT][4];
    202    GLfloat d2[TEST_COUNT][4], r2[TEST_COUNT][4], length[TEST_COUNT];
    203    GLfloat scale;
    204    GLfloat *m;
    205    int i, j;
    206 #ifdef  RUN_DEBUG_BENCHMARK
    207    int cycle_i;		/* the counter for the benchmarks we run */
    208 #endif
    209 
    210    (void) cycles;
    211 
    212    mat->m = _mesa_align_malloc( 16 * sizeof(GLfloat), 16 );
    213    mat->inv = m = mat->m;
    214 
    215    init_matrix( m );
    216 
    217    scale = 1.0F + rnd () * norm_scale_types[mtype];
    218 
    219    for ( i = 0 ; i < 4 ; i++ ) {
    220       for ( j = 0 ; j < 4 ; j++ ) {
    221          switch ( norm_templates[mtype][i * 4 + j] ) {
    222          case NIL:
    223             m[j * 4 + i] = 0.0;
    224             break;
    225          case ONE:
    226             m[j * 4 + i] = 1.0;
    227             break;
    228          case NEG:
    229             m[j * 4 + i] = -1.0;
    230             break;
    231          case VAR:
    232             break;
    233          default:
    234             exit(1);
    235          }
    236       }
    237    }
    238 
    239    for ( i = 0 ; i < TEST_COUNT ; i++ ) {
    240       ASSIGN_3V( d[i],  0.0, 0.0, 0.0 );
    241       ASSIGN_3V( s[i],  0.0, 0.0, 0.0 );
    242       ASSIGN_3V( d2[i], 0.0, 0.0, 0.0 );
    243       for ( j = 0 ; j < 3 ; j++ )
    244          s[i][j] = rnd();
    245       length[i] = 1.0f / sqrtf( LEN_SQUARED_3FV( s[i] ) );
    246    }
    247 
    248    source->data = (GLfloat(*)[4]) s;
    249    source->start = (GLfloat *) s;
    250    source->count = TEST_COUNT;
    251    source->stride = sizeof(s[0]);
    252    source->flags = 0;
    253 
    254    dest->data = d;
    255    dest->start = (GLfloat *) d;
    256    dest->count = TEST_COUNT;
    257    dest->stride = sizeof(float[4]);
    258    dest->flags = 0;
    259 
    260    dest2->data = d2;
    261    dest2->start = (GLfloat *) d2;
    262    dest2->count = TEST_COUNT;
    263    dest2->stride = sizeof(float[4]);
    264    dest2->flags = 0;
    265 
    266    ref->data = r;
    267    ref->start = (GLfloat *) r;
    268    ref->count = TEST_COUNT;
    269    ref->stride = sizeof(float[4]);
    270    ref->flags = 0;
    271 
    272    ref2->data = r2;
    273    ref2->start = (GLfloat *) r2;
    274    ref2->count = TEST_COUNT;
    275    ref2->stride = sizeof(float[4]);
    276    ref2->flags = 0;
    277 
    278    if ( norm_normalize_types[mtype] == 0 ) {
    279       ref_norm_transform_rescale( mat, scale, source, NULL, ref );
    280    } else {
    281       ref_norm_transform_normalize( mat, scale, source, NULL, ref );
    282       ref_norm_transform_normalize( mat, scale, source, length, ref2 );
    283    }
    284 
    285    if ( mesa_profile ) {
    286       BEGIN_RACE( *cycles );
    287       func( mat, scale, source, NULL, dest );
    288       END_RACE( *cycles );
    289       func( mat, scale, source, length, dest2 );
    290    } else {
    291       func( mat, scale, source, NULL, dest );
    292       func( mat, scale, source, length, dest2 );
    293    }
    294 
    295    for ( i = 0 ; i < TEST_COUNT ; i++ ) {
    296       for ( j = 0 ; j < 3 ; j++ ) {
    297          if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) {
    298             printf( "-----------------------------\n" );
    299             printf( "(i = %i, j = %i)\n", i, j );
    300             printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
    301 		    d[i][0], r[i][0], r[i][0]/d[i][0],
    302 		    MAX_PRECISION - significand_match( d[i][0], r[i][0] ) );
    303             printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
    304 		    d[i][1], r[i][1], r[i][1]/d[i][1],
    305 		    MAX_PRECISION - significand_match( d[i][1], r[i][1] ) );
    306             printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
    307 		    d[i][2], r[i][2], r[i][2]/d[i][2],
    308 		    MAX_PRECISION - significand_match( d[i][2], r[i][2] ) );
    309             return 0;
    310          }
    311 
    312          if ( norm_normalize_types[mtype] != 0 ) {
    313             if ( significand_match( d2[i][j], r2[i][j] ) < REQUIRED_PRECISION ) {
    314                printf( "------------------- precalculated length case ------\n" );
    315                printf( "(i = %i, j = %i)\n", i, j );
    316                printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
    317 		       d2[i][0], r2[i][0], r2[i][0]/d2[i][0],
    318 		       MAX_PRECISION - significand_match( d2[i][0], r2[i][0] ) );
    319                printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
    320 		       d2[i][1], r2[i][1], r2[i][1]/d2[i][1],
    321 		       MAX_PRECISION - significand_match( d2[i][1], r2[i][1] ) );
    322                printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
    323 		       d2[i][2], r2[i][2], r2[i][2]/d2[i][2],
    324 		       MAX_PRECISION - significand_match( d2[i][2], r2[i][2] ) );
    325                return 0;
    326             }
    327          }
    328       }
    329    }
    330 
    331    _mesa_align_free( mat->m );
    332    return 1;
    333 }
    334 
    335 void _math_test_all_normal_transform_functions( char *description )
    336 {
    337    int mtype;
    338    long benchmark_tab[0xf];
    339    static int first_time = 1;
    340 
    341    if ( first_time ) {
    342       first_time = 0;
    343       mesa_profile = getenv( "MESA_PROFILE" );
    344    }
    345 
    346 #ifdef RUN_DEBUG_BENCHMARK
    347    if ( mesa_profile ) {
    348       if ( !counter_overhead ) {
    349 	 INIT_COUNTER();
    350 	 printf( "counter overhead: %ld cycles\n\n", counter_overhead );
    351       }
    352       printf( "normal transform results after hooking in %s functions:\n",
    353 	      description );
    354       printf( "\n-------------------------------------------------------\n" );
    355    }
    356 #endif
    357 
    358    for ( mtype = 0 ; mtype < 8 ; mtype++ ) {
    359       normal_func func = _mesa_normal_tab[norm_types[mtype]];
    360       long *cycles = &benchmark_tab[mtype];
    361 
    362       if ( test_norm_function( func, mtype, cycles ) == 0 ) {
    363 	 char buf[100];
    364 	 sprintf( buf, "_mesa_normal_tab[0][%s] failed test (%s)",
    365 		  norm_strings[mtype], description );
    366 	 _mesa_problem( NULL, "%s", buf );
    367       }
    368 
    369 #ifdef RUN_DEBUG_BENCHMARK
    370       if ( mesa_profile ) {
    371 	 printf( " %li\t", benchmark_tab[mtype] );
    372 	 printf( " | [%s]\n", norm_strings[mtype] );
    373       }
    374 #endif
    375    }
    376 #ifdef RUN_DEBUG_BENCHMARK
    377    if ( mesa_profile ) {
    378       printf( "\n" );
    379    }
    380 #endif
    381 }
    382 
    383 
    384 #endif /* DEBUG_MATH */
    385