1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 /*
26  * Updated for P6 architecture by Gareth Hughes.
27  */
28 
29 #include "main/glheader.h"
30 #include "main/context.h"
31 #include "main/macros.h"
32 
33 #include "m_matrix.h"
34 #include "m_xform.h"
35 
36 #include "m_debug.h"
37 #include "m_debug_util.h"
38 
39 #ifdef __UNIXOS2__
40 /* The linker doesn't like empty files */
41 static char dummy;
42 #endif
43 
44 #ifdef DEBUG_MATH  /* This code only used for debugging */
45 
46 
47 /* Overhead of profiling counter in cycles.  Automatically adjusted to
48  * your machine at run time - counter initialization should give very
49  * consistent results.
50  */
51 long counter_overhead = 0;
52 
53 /* This is the value of the environment variable MESA_PROFILE, and is
54  * used to determine if we should benchmark the functions as well as
55  * verify their correctness.
56  */
57 char *mesa_profile = NULL;
58 
59 
60 static int m_general[16] = {
61    VAR, VAR, VAR, VAR,
62    VAR, VAR, VAR, VAR,
63    VAR, VAR, VAR, VAR,
64    VAR, VAR, VAR, VAR
65 };
66 static int m_identity[16] = {
67    ONE, NIL, NIL, NIL,
68    NIL, ONE, NIL, NIL,
69    NIL, NIL, ONE, NIL,
70    NIL, NIL, NIL, ONE
71 };
72 static int  m_2d[16]  = {
73    VAR, VAR, NIL, VAR,
74    VAR, VAR, NIL, VAR,
75    NIL, NIL, ONE, NIL,
76    NIL, NIL, NIL, ONE
77 };
78 static int m_2d_no_rot[16] = {
79    VAR, NIL, NIL, VAR,
80    NIL, VAR, NIL, VAR,
81    NIL, NIL, ONE, NIL,
82    NIL, NIL, NIL, ONE
83 };
84 static int m_3d[16] = {
85    VAR, VAR, VAR, VAR,
86    VAR, VAR, VAR, VAR,
87    VAR, VAR, VAR, VAR,
88    NIL, NIL, NIL, ONE
89 };
90 static int m_3d_no_rot[16] = {
91    VAR, NIL, NIL, VAR,
92    NIL, VAR, NIL, VAR,
93    NIL, NIL, VAR, VAR,
94    NIL, NIL, NIL, ONE
95 };
96 static int m_perspective[16] = {
97    VAR, NIL, VAR, NIL,
98    NIL, VAR, VAR, NIL,
99    NIL, NIL, VAR, VAR,
100    NIL, NIL, NEG, NIL
101 };
102 static int *templates[7] = {
103    m_general,
104    m_identity,
105    m_3d_no_rot,
106    m_perspective,
107    m_2d,
108    m_2d_no_rot,
109    m_3d
110 };
111 static enum GLmatrixtype mtypes[7] = {
112    MATRIX_GENERAL,
113    MATRIX_IDENTITY,
114    MATRIX_3D_NO_ROT,
115    MATRIX_PERSPECTIVE,
116    MATRIX_2D,
117    MATRIX_2D_NO_ROT,
118    MATRIX_3D
119 };
120 static char *mstrings[7] = {
121    "MATRIX_GENERAL",
122    "MATRIX_IDENTITY",
123    "MATRIX_3D_NO_ROT",
124    "MATRIX_PERSPECTIVE",
125    "MATRIX_2D",
126    "MATRIX_2D_NO_ROT",
127    "MATRIX_3D"
128 };
129 
130 
131 /* =============================================================
132  * Reference transformations
133  */
134 
ref_transform(GLvector4f * dst,const GLmatrix * mat,const GLvector4f * src)135 static void ref_transform( GLvector4f *dst,
136                            const GLmatrix *mat,
137                            const GLvector4f *src )
138 {
139    GLuint i;
140    GLfloat *s = (GLfloat *)src->start;
141    GLfloat (*d)[4] = (GLfloat (*)[4])dst->start;
142    const GLfloat *m = mat->m;
143 
144    for ( i = 0 ; i < src->count ; i++ ) {
145       TRANSFORM_POINT( d[i], m, s );
146       s = (GLfloat *)((char *)s + src->stride);
147    }
148 }
149 
150 
151 /* =============================================================
152  * Vertex transformation tests
153  */
154 
init_matrix(GLfloat * m)155 static void init_matrix( GLfloat *m )
156 {
157    m[0] = 63.0; m[4] = 43.0; m[ 8] = 29.0; m[12] = 43.0;
158    m[1] = 55.0; m[5] = 17.0; m[ 9] = 31.0; m[13] =  7.0;
159    m[2] = 44.0; m[6] =  9.0; m[10] =  7.0; m[14] =  3.0;
160    m[3] = 11.0; m[7] = 23.0; m[11] = 91.0; m[15] =  9.0;
161 }
162 
163 ALIGN16(static GLfloat, s[TEST_COUNT][4]);
164 ALIGN16(static GLfloat, d[TEST_COUNT][4]);
165 ALIGN16(static GLfloat, r[TEST_COUNT][4]);
166 
test_transform_function(transform_func func,int psize,int mtype,unsigned long * cycles)167 static int test_transform_function( transform_func func, int psize,
168 				    int mtype, unsigned long *cycles )
169 {
170    GLvector4f source[1], dest[1], ref[1];
171    GLmatrix mat[1];
172    GLfloat *m;
173    int i, j;
174 #ifdef  RUN_DEBUG_BENCHMARK
175    int cycle_i;                /* the counter for the benchmarks we run */
176 #endif
177 
178    (void) cycles;
179 
180    if ( psize > 4 ) {
181       _mesa_problem( NULL, "test_transform_function called with psize > 4\n" );
182       return 0;
183    }
184 
185    mat->m = align_malloc( 16 * sizeof(GLfloat), 16 );
186    mat->type = mtypes[mtype];
187 
188    m = mat->m;
189    assert( ((long)m & 15) == 0 );
190 
191    init_matrix( m );
192 
193    for ( i = 0 ; i < 4 ; i++ ) {
194       for ( j = 0 ; j < 4 ; j++ ) {
195          switch ( templates[mtype][i * 4 + j] ) {
196          case NIL:
197             m[j * 4 + i] = 0.0;
198             break;
199          case ONE:
200             m[j * 4 + i] = 1.0;
201             break;
202          case NEG:
203             m[j * 4 + i] = -1.0;
204             break;
205          case VAR:
206             break;
207          default:
208             assert(0);
209             return 0;
210          }
211       }
212    }
213 
214    for ( i = 0 ; i < TEST_COUNT ; i++) {
215       ASSIGN_4V( d[i], 0.0, 0.0, 0.0, 1.0 );
216       ASSIGN_4V( s[i], 0.0, 0.0, 0.0, 1.0 );
217       for ( j = 0 ; j < psize ; j++ )
218          s[i][j] = rnd();
219    }
220 
221    source->data = (GLfloat(*)[4])s;
222    source->start = (GLfloat *)s;
223    source->count = TEST_COUNT;
224    source->stride = sizeof(s[0]);
225    source->size = 4;
226    source->flags = 0;
227 
228    dest->data = (GLfloat(*)[4])d;
229    dest->start = (GLfloat *)d;
230    dest->count = TEST_COUNT;
231    dest->stride = sizeof(float[4]);
232    dest->size = 0;
233    dest->flags = 0;
234 
235    ref->data = (GLfloat(*)[4])r;
236    ref->start = (GLfloat *)r;
237    ref->count = TEST_COUNT;
238    ref->stride = sizeof(float[4]);
239    ref->size = 0;
240    ref->flags = 0;
241 
242    ref_transform( ref, mat, source );
243 
244    if ( mesa_profile ) {
245       BEGIN_RACE( *cycles );
246       func( dest, mat->m, source );
247       END_RACE( *cycles );
248    }
249    else {
250       func( dest, mat->m, source );
251    }
252 
253    for ( i = 0 ; i < TEST_COUNT ; i++ ) {
254       for ( j = 0 ; j < 4 ; j++ ) {
255          if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) {
256             printf("-----------------------------\n" );
257             printf("(i = %i, j = %i)\n", i, j );
258             printf("%f \t %f \t [diff = %e - %i bit missed]\n",
259 		    d[i][0], r[i][0], r[i][0]-d[i][0],
260 		    MAX_PRECISION - significand_match( d[i][0], r[i][0] ) );
261             printf("%f \t %f \t [diff = %e - %i bit missed]\n",
262 		    d[i][1], r[i][1], r[i][1]-d[i][1],
263 		    MAX_PRECISION - significand_match( d[i][1], r[i][1] ) );
264             printf("%f \t %f \t [diff = %e - %i bit missed]\n",
265 		    d[i][2], r[i][2], r[i][2]-d[i][2],
266 		    MAX_PRECISION - significand_match( d[i][2], r[i][2] ) );
267             printf("%f \t %f \t [diff = %e - %i bit missed]\n",
268 		    d[i][3], r[i][3], r[i][3]-d[i][3],
269 		    MAX_PRECISION - significand_match( d[i][3], r[i][3] ) );
270             return 0;
271          }
272       }
273    }
274 
275    align_free( mat->m );
276    return 1;
277 }
278 
_math_test_all_transform_functions(char * description)279 void _math_test_all_transform_functions( char *description )
280 {
281    int psize, mtype;
282    unsigned long benchmark_tab[4][7];
283    static int first_time = 1;
284 
285    if ( first_time ) {
286       first_time = 0;
287       mesa_profile = getenv( "MESA_PROFILE" );
288    }
289 
290 #ifdef RUN_DEBUG_BENCHMARK
291    if ( mesa_profile ) {
292       if ( !counter_overhead ) {
293 	 INIT_COUNTER();
294 	 printf("counter overhead: %lu cycles\n\n", counter_overhead );
295       }
296       printf("transform results after hooking in %s functions:\n", description );
297    }
298 #endif
299 
300 #ifdef RUN_DEBUG_BENCHMARK
301    if ( mesa_profile ) {
302       printf("\n" );
303       for ( psize = 1 ; psize <= 4 ; psize++ ) {
304 	 printf(" p%d\t", psize );
305       }
306       printf("\n--------------------------------------------------------\n" );
307    }
308 #endif
309 
310    for ( mtype = 0 ; mtype < 7 ; mtype++ ) {
311       for ( psize = 1 ; psize <= 4 ; psize++ ) {
312 	 transform_func func = _mesa_transform_tab[psize][mtypes[mtype]];
313 	 unsigned long *cycles = &(benchmark_tab[psize-1][mtype]);
314 
315 	 if ( test_transform_function( func, psize, mtype, cycles ) == 0 ) {
316 	    char buf[100];
317 	    sprintf(buf, "_mesa_transform_tab[0][%d][%s] failed test (%s)",
318 		    psize, mstrings[mtype], description );
319 	    _mesa_problem( NULL, "%s", buf );
320 	 }
321 #ifdef RUN_DEBUG_BENCHMARK
322 	 if ( mesa_profile )
323 	    printf(" %li\t", benchmark_tab[psize-1][mtype] );
324 #endif
325       }
326 #ifdef RUN_DEBUG_BENCHMARK
327       if ( mesa_profile )
328 	 printf(" | [%s]\n", mstrings[mtype] );
329 #endif
330    }
331 #ifdef RUN_DEBUG_BENCHMARK
332    if ( mesa_profile )
333       printf( "\n" );
334 #endif
335 }
336 
337 
338 #endif /* DEBUG_MATH */
339