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 
34 #include "m_matrix.h"
35 #include "m_xform.h"
36 
37 #include "m_debug.h"
38 #include "m_debug_util.h"
39 
40 
41 #ifdef __UNIXOS2__
42 /* The linker doesn't like empty files */
43 static char dummy;
44 #endif
45 
46 #ifdef DEBUG_MATH  /* This code only used for debugging */
47 
48 
49 static int m_norm_identity[16] = {
50    ONE, NIL, NIL, NIL,
51    NIL, ONE, NIL, NIL,
52    NIL, NIL, ONE, NIL,
53    NIL, NIL, NIL, NIL
54 };
55 static int m_norm_general[16] = {
56    VAR, VAR, VAR, NIL,
57    VAR, VAR, VAR, NIL,
58    VAR, VAR, VAR, NIL,
59    NIL, NIL, NIL, NIL
60 };
61 static int m_norm_no_rot[16] = {
62    VAR, NIL, NIL, NIL,
63    NIL, VAR, NIL, NIL,
64    NIL, NIL, VAR, NIL,
65    NIL, NIL, NIL, NIL
66 };
67 static int *norm_templates[8] = {
68    m_norm_no_rot,
69    m_norm_no_rot,
70    m_norm_no_rot,
71    m_norm_general,
72    m_norm_general,
73    m_norm_general,
74    m_norm_identity,
75    m_norm_identity
76 };
77 static int norm_types[8] = {
78    NORM_TRANSFORM_NO_ROT,
79    NORM_TRANSFORM_NO_ROT | NORM_RESCALE,
80    NORM_TRANSFORM_NO_ROT | NORM_NORMALIZE,
81    NORM_TRANSFORM,
82    NORM_TRANSFORM | NORM_RESCALE,
83    NORM_TRANSFORM | NORM_NORMALIZE,
84    NORM_RESCALE,
85    NORM_NORMALIZE
86 };
87 static int norm_scale_types[8] = {               /*  rescale factor          */
88    NIL,                                          /*  NIL disables rescaling  */
89    VAR,
90    NIL,
91    NIL,
92    VAR,
93    NIL,
94    VAR,
95    NIL
96 };
97 static int norm_normalize_types[8] = {           /*  normalizing ?? (no = 0) */
98    0,
99    0,
100    1,
101    0,
102    0,
103    1,
104    0,
105    1
106 };
107 static char *norm_strings[8] = {
108    "NORM_TRANSFORM_NO_ROT",
109    "NORM_TRANSFORM_NO_ROT | NORM_RESCALE",
110    "NORM_TRANSFORM_NO_ROT | NORM_NORMALIZE",
111    "NORM_TRANSFORM",
112    "NORM_TRANSFORM | NORM_RESCALE",
113    "NORM_TRANSFORM | NORM_NORMALIZE",
114    "NORM_RESCALE",
115    "NORM_NORMALIZE"
116 };
117 
118 
119 /* =============================================================
120  * Reference transformations
121  */
122 
ref_norm_transform_rescale(const GLmatrix * mat,GLfloat scale,const GLvector4f * in,const GLfloat * lengths,GLvector4f * dest)123 static void ref_norm_transform_rescale( const GLmatrix *mat,
124 					GLfloat scale,
125 					const GLvector4f *in,
126 					const GLfloat *lengths,
127 					GLvector4f *dest )
128 {
129    GLuint i;
130    const GLfloat *s = in->start;
131    const GLfloat *m = mat->inv;
132    GLfloat (*out)[4] = (GLfloat (*)[4]) dest->start;
133 
134    (void) lengths;
135 
136    for ( i = 0 ; i < in->count ; i++ ) {
137       GLfloat t[3];
138 
139       TRANSFORM_NORMAL( t, s, m );
140       SCALE_SCALAR_3V( out[i], scale, t );
141 
142       s = (GLfloat *)((char *)s + in->stride);
143    }
144 }
145 
ref_norm_transform_normalize(const GLmatrix * mat,GLfloat scale,const GLvector4f * in,const GLfloat * lengths,GLvector4f * dest)146 static void ref_norm_transform_normalize( const GLmatrix *mat,
147 					  GLfloat scale,
148 					  const GLvector4f *in,
149 					  const GLfloat *lengths,
150 					  GLvector4f *dest )
151 {
152    GLuint i;
153    const GLfloat *s = in->start;
154    const GLfloat *m = mat->inv;
155    GLfloat (*out)[4] = (GLfloat (*)[4]) dest->start;
156 
157    for ( i = 0 ; i < in->count ; i++ ) {
158       GLfloat t[3];
159 
160       TRANSFORM_NORMAL( t, s, m );
161 
162       if ( !lengths ) {
163          GLfloat len = LEN_SQUARED_3FV( t );
164          if ( len > 1e-20 ) {
165 	    /* Hmmm, don't know how we could test the precalculated
166 	     * length case...
167 	     */
168             scale = 1.0f / sqrtf(len);
169 	    SCALE_SCALAR_3V( out[i], scale, t );
170          } else {
171             out[i][0] = out[i][1] = out[i][2] = 0;
172          }
173       } else {
174          scale = lengths[i];
175 	 SCALE_SCALAR_3V( out[i], scale, t );
176       }
177 
178       s = (GLfloat *)((char *)s + in->stride);
179    }
180 }
181 
182 
183 /* =============================================================
184  * Normal transformation tests
185  */
186 
init_matrix(GLfloat * m)187 static void init_matrix( GLfloat *m )
188 {
189    m[0] = 63.0; m[4] = 43.0; m[ 8] = 29.0; m[12] = 43.0;
190    m[1] = 55.0; m[5] = 17.0; m[ 9] = 31.0; m[13] =  7.0;
191    m[2] = 44.0; m[6] =  9.0; m[10] =  7.0; m[14] =  3.0;
192    m[3] = 11.0; m[7] = 23.0; m[11] = 91.0; m[15] =  9.0;
193 }
194 
195 
test_norm_function(normal_func func,int mtype,long * cycles)196 static int test_norm_function( normal_func func, int mtype, long *cycles )
197 {
198    GLvector4f source[1], dest[1], dest2[1], ref[1], ref2[1];
199    GLmatrix mat[1];
200    GLfloat s[TEST_COUNT][5], d[TEST_COUNT][4], r[TEST_COUNT][4];
201    GLfloat d2[TEST_COUNT][4], r2[TEST_COUNT][4], length[TEST_COUNT];
202    GLfloat scale;
203    GLfloat *m;
204    int i, j;
205 #ifdef  RUN_DEBUG_BENCHMARK
206    int cycle_i;		/* the counter for the benchmarks we run */
207 #endif
208 
209    (void) cycles;
210 
211    mat->m = align_malloc( 16 * sizeof(GLfloat), 16 );
212    mat->inv = m = mat->m;
213 
214    init_matrix( m );
215 
216    scale = 1.0F + rnd () * norm_scale_types[mtype];
217 
218    for ( i = 0 ; i < 4 ; i++ ) {
219       for ( j = 0 ; j < 4 ; j++ ) {
220          switch ( norm_templates[mtype][i * 4 + j] ) {
221          case NIL:
222             m[j * 4 + i] = 0.0;
223             break;
224          case ONE:
225             m[j * 4 + i] = 1.0;
226             break;
227          case NEG:
228             m[j * 4 + i] = -1.0;
229             break;
230          case VAR:
231             break;
232          default:
233             exit(1);
234          }
235       }
236    }
237 
238    for ( i = 0 ; i < TEST_COUNT ; i++ ) {
239       ASSIGN_3V( d[i],  0.0, 0.0, 0.0 );
240       ASSIGN_3V( s[i],  0.0, 0.0, 0.0 );
241       ASSIGN_3V( d2[i], 0.0, 0.0, 0.0 );
242       for ( j = 0 ; j < 3 ; j++ )
243          s[i][j] = rnd();
244       length[i] = 1.0f / sqrtf( LEN_SQUARED_3FV( s[i] ) );
245    }
246 
247    source->data = (GLfloat(*)[4]) s;
248    source->start = (GLfloat *) s;
249    source->count = TEST_COUNT;
250    source->stride = sizeof(s[0]);
251    source->flags = 0;
252 
253    dest->data = d;
254    dest->start = (GLfloat *) d;
255    dest->count = TEST_COUNT;
256    dest->stride = sizeof(float[4]);
257    dest->flags = 0;
258 
259    dest2->data = d2;
260    dest2->start = (GLfloat *) d2;
261    dest2->count = TEST_COUNT;
262    dest2->stride = sizeof(float[4]);
263    dest2->flags = 0;
264 
265    ref->data = r;
266    ref->start = (GLfloat *) r;
267    ref->count = TEST_COUNT;
268    ref->stride = sizeof(float[4]);
269    ref->flags = 0;
270 
271    ref2->data = r2;
272    ref2->start = (GLfloat *) r2;
273    ref2->count = TEST_COUNT;
274    ref2->stride = sizeof(float[4]);
275    ref2->flags = 0;
276 
277    if ( norm_normalize_types[mtype] == 0 ) {
278       ref_norm_transform_rescale( mat, scale, source, NULL, ref );
279    } else {
280       ref_norm_transform_normalize( mat, scale, source, NULL, ref );
281       ref_norm_transform_normalize( mat, scale, source, length, ref2 );
282    }
283 
284    if ( mesa_profile ) {
285       BEGIN_RACE( *cycles );
286       func( mat, scale, source, NULL, dest );
287       END_RACE( *cycles );
288       func( mat, scale, source, length, dest2 );
289    } else {
290       func( mat, scale, source, NULL, dest );
291       func( mat, scale, source, length, dest2 );
292    }
293 
294    for ( i = 0 ; i < TEST_COUNT ; i++ ) {
295       for ( j = 0 ; j < 3 ; j++ ) {
296          if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) {
297             printf( "-----------------------------\n" );
298             printf( "(i = %i, j = %i)\n", i, j );
299             printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
300 		    d[i][0], r[i][0], r[i][0]/d[i][0],
301 		    MAX_PRECISION - significand_match( d[i][0], r[i][0] ) );
302             printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
303 		    d[i][1], r[i][1], r[i][1]/d[i][1],
304 		    MAX_PRECISION - significand_match( d[i][1], r[i][1] ) );
305             printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
306 		    d[i][2], r[i][2], r[i][2]/d[i][2],
307 		    MAX_PRECISION - significand_match( d[i][2], r[i][2] ) );
308             return 0;
309          }
310 
311          if ( norm_normalize_types[mtype] != 0 ) {
312             if ( significand_match( d2[i][j], r2[i][j] ) < REQUIRED_PRECISION ) {
313                printf( "------------------- precalculated length case ------\n" );
314                printf( "(i = %i, j = %i)\n", i, j );
315                printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
316 		       d2[i][0], r2[i][0], r2[i][0]/d2[i][0],
317 		       MAX_PRECISION - significand_match( d2[i][0], r2[i][0] ) );
318                printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
319 		       d2[i][1], r2[i][1], r2[i][1]/d2[i][1],
320 		       MAX_PRECISION - significand_match( d2[i][1], r2[i][1] ) );
321                printf( "%f \t %f \t [ratio = %e - %i bit missed]\n",
322 		       d2[i][2], r2[i][2], r2[i][2]/d2[i][2],
323 		       MAX_PRECISION - significand_match( d2[i][2], r2[i][2] ) );
324                return 0;
325             }
326          }
327       }
328    }
329 
330    align_free( mat->m );
331    return 1;
332 }
333 
_math_test_all_normal_transform_functions(char * description)334 void _math_test_all_normal_transform_functions( char *description )
335 {
336    int mtype;
337    long benchmark_tab[0xf];
338    static int first_time = 1;
339 
340    if ( first_time ) {
341       first_time = 0;
342       mesa_profile = getenv( "MESA_PROFILE" );
343    }
344 
345 #ifdef RUN_DEBUG_BENCHMARK
346    if ( mesa_profile ) {
347       if ( !counter_overhead ) {
348 	 INIT_COUNTER();
349 	 printf( "counter overhead: %ld cycles\n\n", counter_overhead );
350       }
351       printf( "normal transform results after hooking in %s functions:\n",
352 	      description );
353       printf( "\n-------------------------------------------------------\n" );
354    }
355 #endif
356 
357    for ( mtype = 0 ; mtype < 8 ; mtype++ ) {
358       normal_func func = _mesa_normal_tab[norm_types[mtype]];
359       long *cycles = &benchmark_tab[mtype];
360 
361       if ( test_norm_function( func, mtype, cycles ) == 0 ) {
362 	 char buf[100];
363 	 sprintf( buf, "_mesa_normal_tab[0][%s] failed test (%s)",
364 		  norm_strings[mtype], description );
365 	 _mesa_problem( NULL, "%s", buf );
366       }
367 
368 #ifdef RUN_DEBUG_BENCHMARK
369       if ( mesa_profile ) {
370 	 printf( " %li\t", benchmark_tab[mtype] );
371 	 printf( " | [%s]\n", norm_strings[mtype] );
372       }
373 #endif
374    }
375 #ifdef RUN_DEBUG_BENCHMARK
376    if ( mesa_profile ) {
377       printf( "\n" );
378    }
379 #endif
380 }
381 
382 
383 #endif /* DEBUG_MATH */
384