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