m_debug_clip.c revision b8f29f29eb611c92d43aaf8ffcd2d9743b3af967
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.1
4 *
5 * Copyright (C) 1999-2005  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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Gareth Hughes
26 */
27
28#include "glheader.h"
29#include "context.h"
30#include "macros.h"
31#include "imports.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 */
41static char dummy;
42#endif
43
44#ifdef DEBUG  /* This code only used for debugging */
45
46static clip_func *clip_tab[2] = {
47   _mesa_clip_tab,
48   _mesa_clip_np_tab
49};
50static char *cnames[2] = {
51   "_mesa_clip_tab",
52   "_mesa_clip_np_tab"
53};
54#ifdef RUN_DEBUG_BENCHMARK
55static char *cstrings[2] = {
56   "clip, perspective divide",
57   "clip, no divide"
58};
59#endif
60
61
62/* =============================================================
63 * Reference cliptests
64 */
65
66static GLvector4f *ref_cliptest_points4( GLvector4f *clip_vec,
67					 GLvector4f *proj_vec,
68					 GLubyte clipMask[],
69					 GLubyte *orMask,
70					 GLubyte *andMask )
71{
72   const GLuint stride = clip_vec->stride;
73   const GLuint count = clip_vec->count;
74   const GLfloat *from = (GLfloat *)clip_vec->start;
75   GLuint c = 0;
76   GLfloat (*vProj)[4] = (GLfloat (*)[4])proj_vec->start;
77   GLubyte tmpAndMask = *andMask;
78   GLubyte tmpOrMask = *orMask;
79   GLuint i;
80   for ( i = 0 ; i < count ; i++, STRIDE_F(from, stride) ) {
81      const GLfloat cx = from[0];
82      const GLfloat cy = from[1];
83      const GLfloat cz = from[2];
84      const GLfloat cw = from[3];
85      GLubyte mask = 0;
86      if ( -cx + cw < 0 ) mask |= CLIP_RIGHT_BIT;
87      if (  cx + cw < 0 ) mask |= CLIP_LEFT_BIT;
88      if ( -cy + cw < 0 ) mask |= CLIP_TOP_BIT;
89      if (  cy + cw < 0 ) mask |= CLIP_BOTTOM_BIT;
90      if ( -cz + cw < 0 ) mask |= CLIP_FAR_BIT;
91      if (  cz + cw < 0 ) mask |= CLIP_NEAR_BIT;
92      clipMask[i] = mask;
93      if ( mask ) {
94	 c++;
95	 tmpAndMask &= mask;
96	 tmpOrMask |= mask;
97	 vProj[i][0] = 0;
98	 vProj[i][1] = 0;
99	 vProj[i][2] = 0;
100	 vProj[i][3] = 1;
101      } else {
102	 GLfloat oow = 1.0F / cw;
103	 vProj[i][0] = cx * oow;
104	 vProj[i][1] = cy * oow;
105	 vProj[i][2] = cz * oow;
106	 vProj[i][3] = oow;
107      }
108   }
109
110   *orMask = tmpOrMask;
111   *andMask = (GLubyte) (c < count ? 0 : tmpAndMask);
112
113   proj_vec->flags |= VEC_SIZE_4;
114   proj_vec->size = 4;
115   proj_vec->count = clip_vec->count;
116   return proj_vec;
117}
118
119/* Keep these here for now, even though we don't use them...
120 */
121static GLvector4f *ref_cliptest_points3( GLvector4f *clip_vec,
122					 GLvector4f *proj_vec,
123					 GLubyte clipMask[],
124					 GLubyte *orMask,
125					 GLubyte *andMask )
126{
127   const GLuint stride = clip_vec->stride;
128   const GLuint count = clip_vec->count;
129   const GLfloat *from = (GLfloat *)clip_vec->start;
130
131   GLubyte tmpOrMask = *orMask;
132   GLubyte tmpAndMask = *andMask;
133   GLuint i;
134   for ( i = 0 ; i < count ; i++, STRIDE_F(from, stride) ) {
135      const GLfloat cx = from[0], cy = from[1], cz = from[2];
136      GLubyte mask = 0;
137      if ( cx >  1.0 )		mask |= CLIP_RIGHT_BIT;
138      else if ( cx < -1.0 )	mask |= CLIP_LEFT_BIT;
139      if ( cy >  1.0 )		mask |= CLIP_TOP_BIT;
140      else if ( cy < -1.0 )	mask |= CLIP_BOTTOM_BIT;
141      if ( cz >  1.0 )		mask |= CLIP_FAR_BIT;
142      else if ( cz < -1.0 )	mask |= CLIP_NEAR_BIT;
143      clipMask[i] = mask;
144      tmpOrMask |= mask;
145      tmpAndMask &= mask;
146   }
147
148   *orMask = tmpOrMask;
149   *andMask = tmpAndMask;
150   return clip_vec;
151}
152
153static GLvector4f * ref_cliptest_points2( GLvector4f *clip_vec,
154					  GLvector4f *proj_vec,
155					  GLubyte clipMask[],
156					  GLubyte *orMask,
157					  GLubyte *andMask )
158{
159   const GLuint stride = clip_vec->stride;
160   const GLuint count = clip_vec->count;
161   const GLfloat *from = (GLfloat *)clip_vec->start;
162
163   GLubyte tmpOrMask = *orMask;
164   GLubyte tmpAndMask = *andMask;
165   GLuint i;
166   for ( i = 0 ; i < count ; i++, STRIDE_F(from, stride) ) {
167      const GLfloat cx = from[0], cy = from[1];
168      GLubyte mask = 0;
169      if ( cx >  1.0 )		mask |= CLIP_RIGHT_BIT;
170      else if ( cx < -1.0 )	mask |= CLIP_LEFT_BIT;
171      if ( cy >  1.0 )		mask |= CLIP_TOP_BIT;
172      else if ( cy < -1.0 )	mask |= CLIP_BOTTOM_BIT;
173      clipMask[i] = mask;
174      tmpOrMask |= mask;
175      tmpAndMask &= mask;
176   }
177
178   *orMask = tmpOrMask;
179   *andMask = tmpAndMask;
180   return clip_vec;
181}
182
183static clip_func ref_cliptest[5] = {
184   0,
185   0,
186   ref_cliptest_points2,
187   ref_cliptest_points3,
188   ref_cliptest_points4
189};
190
191
192/* =============================================================
193 * Cliptest tests
194 */
195
196ALIGN16(static GLfloat, s[TEST_COUNT][4]);
197ALIGN16(static GLfloat, d[TEST_COUNT][4]);
198ALIGN16(static GLfloat, r[TEST_COUNT][4]);
199
200
201static int test_cliptest_function( clip_func func, int np,
202				   int psize, long *cycles )
203{
204   GLvector4f source[1], dest[1], ref[1];
205   GLubyte dm[TEST_COUNT], dco, dca;
206   GLubyte rm[TEST_COUNT], rco, rca;
207   int i, j;
208#ifdef  RUN_DEBUG_BENCHMARK
209   int cycle_i;                /* the counter for the benchmarks we run */
210#endif
211
212   (void) cycles;
213
214   if ( psize > 4 ) {
215      _mesa_problem( NULL, "test_cliptest_function called with psize > 4\n" );
216      return 0;
217   }
218
219   for ( i = 0 ; i < TEST_COUNT ; i++) {
220      ASSIGN_4V( d[i], 0.0, 0.0, 0.0, 1.0 );
221      ASSIGN_4V( s[i], 0.0, 0.0, 0.0, 1.0 );
222      for ( j = 0 ; j < psize ; j++ )
223         s[i][j] = rnd();
224   }
225
226   source->data = (GLfloat(*)[4])s;
227   source->start = (GLfloat *)s;
228   source->count = TEST_COUNT;
229   source->stride = sizeof(s[0]);
230   source->size = 4;
231   source->flags = 0;
232
233   dest->data = (GLfloat(*)[4])d;
234   dest->start = (GLfloat *)d;
235   dest->count = TEST_COUNT;
236   dest->stride = sizeof(float[4]);
237   dest->size = 0;
238   dest->flags = 0;
239
240   ref->data = (GLfloat(*)[4])r;
241   ref->start = (GLfloat *)r;
242   ref->count = TEST_COUNT;
243   ref->stride = sizeof(float[4]);
244   ref->size = 0;
245   ref->flags = 0;
246
247   dco = rco = 0;
248   dca = rca = CLIP_ALL_BITS;
249
250   ref_cliptest[psize]( source, ref, rm, &rco, &rca );
251
252   if ( mesa_profile ) {
253      BEGIN_RACE( *cycles );
254      func( source, dest, dm, &dco, &dca );
255      END_RACE( *cycles );
256   }
257   else {
258      func( source, dest, dm, &dco, &dca );
259   }
260
261   if ( dco != rco ) {
262      _mesa_printf( "\n-----------------------------\n" );
263      _mesa_printf( "dco = 0x%02x   rco = 0x%02x\n", dco, rco );
264      return 0;
265   }
266   if ( dca != rca ) {
267      _mesa_printf( "\n-----------------------------\n" );
268      _mesa_printf( "dca = 0x%02x   rca = 0x%02x\n", dca, rca );
269      return 0;
270   }
271   for ( i = 0 ; i < TEST_COUNT ; i++ ) {
272      if ( dm[i] != rm[i] ) {
273	 _mesa_printf( "\n-----------------------------\n" );
274	 _mesa_printf( "(i = %i)\n", i );
275	 _mesa_printf( "dm = 0x%02x   rm = 0x%02x\n", dm[i], rm[i] );
276	 return 0;
277      }
278   }
279
280   /* Only verify output on projected points4 case.  FIXME: Do we need
281    * to test other cases?
282    */
283   if ( np || psize < 4 )
284      return 1;
285
286   for ( i = 0 ; i < TEST_COUNT ; i++ ) {
287      for ( j = 0 ; j < 4 ; j++ ) {
288         if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) {
289            _mesa_printf( "\n-----------------------------\n" );
290            _mesa_printf( "(i = %i, j = %i)  dm = 0x%02x   rm = 0x%02x\n",
291		    i, j, dm[i], rm[i] );
292            _mesa_printf( "%f \t %f \t [diff = %e - %i bit missed]\n",
293		    d[i][0], r[i][0], r[i][0]-d[i][0],
294		    MAX_PRECISION - significand_match( d[i][0], r[i][0] ) );
295            _mesa_printf( "%f \t %f \t [diff = %e - %i bit missed]\n",
296		    d[i][1], r[i][1], r[i][1]-d[i][1],
297		    MAX_PRECISION - significand_match( d[i][1], r[i][1] ) );
298            _mesa_printf( "%f \t %f \t [diff = %e - %i bit missed]\n",
299		    d[i][2], r[i][2], r[i][2]-d[i][2],
300		    MAX_PRECISION - significand_match( d[i][2], r[i][2] ) );
301            _mesa_printf( "%f \t %f \t [diff = %e - %i bit missed]\n",
302		    d[i][3], r[i][3], r[i][3]-d[i][3],
303		    MAX_PRECISION - significand_match( d[i][3], r[i][3] ) );
304            return 0;
305         }
306      }
307   }
308
309   return 1;
310}
311
312void _math_test_all_cliptest_functions( char *description )
313{
314   int np, psize;
315   long benchmark_tab[2][4];
316   static int first_time = 1;
317
318   if ( first_time ) {
319      first_time = 0;
320      mesa_profile = _mesa_getenv( "MESA_PROFILE" );
321   }
322
323#ifdef RUN_DEBUG_BENCHMARK
324   if ( mesa_profile ) {
325      if ( !counter_overhead ) {
326	 INIT_COUNTER();
327	 _mesa_printf( "counter overhead: %ld cycles\n\n", counter_overhead );
328      }
329      _mesa_printf( "cliptest results after hooking in %s functions:\n", description );
330   }
331#endif
332
333#ifdef RUN_DEBUG_BENCHMARK
334   if ( mesa_profile ) {
335      _mesa_printf( "\n\t" );
336      for ( psize = 2 ; psize <= 4 ; psize++ ) {
337	 _mesa_printf( " p%d\t", psize );
338      }
339      _mesa_printf( "\n--------------------------------------------------------\n\t" );
340   }
341#endif
342
343   for ( np = 0 ; np < 2 ; np++ ) {
344      for ( psize = 2 ; psize <= 4 ; psize++ ) {
345	 clip_func func = clip_tab[np][psize];
346	 long *cycles = &(benchmark_tab[np][psize-1]);
347
348	 if ( test_cliptest_function( func, np, psize, cycles ) == 0 ) {
349	    char buf[100];
350	    _mesa_sprintf( buf, "%s[%d] failed test (%s)",
351		     cnames[np], psize, description );
352	    _mesa_problem( NULL, buf );
353	 }
354#ifdef RUN_DEBUG_BENCHMARK
355	 if ( mesa_profile )
356	    _mesa_printf( " %li\t", benchmark_tab[np][psize-1] );
357#endif
358      }
359#ifdef RUN_DEBUG_BENCHMARK
360      if ( mesa_profile )
361	 _mesa_printf( " | [%s]\n\t", cstrings[np] );
362#endif
363   }
364#ifdef RUN_DEBUG_BENCHMARK
365   if ( mesa_profile )
366      _mesa_printf( "\n" );
367#endif
368}
369
370
371#endif /* DEBUG */
372