1/*
2 * This program is under the GNU GPL.
3 * Use at your own risk.
4 *
5 * written by David Bucciarelli (tech.hmw@plus.it)
6 *            Humanware s.r.l.
7 */
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12#include <math.h>
13#include "glut_wrap.h"
14
15typedef struct
16{
17   char *name;
18   char *unit;
19   void (*init) (void);
20   int (*run) (int, int);
21   int type;
22   int numsize;
23   int size[10];
24}
25benchmark;
26
27static int frontbuffer = 1;
28
29/***************************************************************************/
30
31static void
32init_test01(void)
33{
34   glMatrixMode(GL_PROJECTION);
35   glLoadIdentity();
36   gluOrtho2D(-0.5, 639.5, -0.5, 479.5);
37   glMatrixMode(GL_MODELVIEW);
38
39   glShadeModel(GL_FLAT);
40   glDisable(GL_DEPTH_TEST);
41
42   glClearColor(0.0, 0.1, 1.0, 0.0);
43   glClear(GL_COLOR_BUFFER_BIT);
44   glColor3f(1.0, 0.0, 0.0);
45}
46
47static int
48test01(int size, int num)
49{
50   int x, y;
51
52   glBegin(GL_POINTS);
53   for (y = 0; y < num; y++)
54      for (x = 0; x < 480; x++)
55	 glVertex2i(x, x);
56   glEnd();
57
58   return 480 * num;
59}
60
61/***************************************************************************/
62
63static void
64init_test02(void)
65{
66   glMatrixMode(GL_PROJECTION);
67   glLoadIdentity();
68   gluOrtho2D(-0.5, 639.5, -0.5, 479.5);
69   glMatrixMode(GL_MODELVIEW);
70
71   glShadeModel(GL_SMOOTH);
72   glDisable(GL_DEPTH_TEST);
73
74   glClearColor(0.0, 0.1, 1.0, 0.0);
75   glClear(GL_COLOR_BUFFER_BIT);
76}
77
78static int
79test02(int size, int num)
80{
81   int x, y;
82
83   glBegin(GL_LINES);
84   for (y = 0; y < num; y++)
85      for (x = 0; x < size; x++) {
86	 glColor3f(0.0, 1.0, y / (float) num);
87	 glVertex2i(0, size - 1);
88	 glColor3f(1.0, 0.0, x / (float) size);
89	 glVertex2i(x, x);
90      }
91   glEnd();
92
93   return num * size;
94}
95
96/***************************************************************************/
97
98static void
99init_test03(void)
100{
101   glMatrixMode(GL_PROJECTION);
102   glLoadIdentity();
103   glOrtho(-0.5, 639.5, -0.5, 479.5, 1.0, -1000.0 * 480.0);
104   glMatrixMode(GL_MODELVIEW);
105
106   glShadeModel(GL_SMOOTH);
107   glEnable(GL_DEPTH_TEST);
108
109   glClearColor(0.0, 0.1, 1.0, 0.0);
110   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
111}
112
113static int
114test03(int size, int num)
115{
116   int x, y, z;
117
118   glBegin(GL_TRIANGLES);
119   for (y = 0; y < num; y++)
120      for (x = 0; x < size; x += 5) {
121	 z = num * size - (y * size + x);
122	 glColor3f(0.0, 1.0, 0.0);
123	 glVertex3i(0, x, z);
124
125	 glColor3f(1.0, 0.0, x / (float) size);
126	 glVertex3i(size - 1 - x, 0, z);
127
128	 glColor3f(1.0, x / (float) size, 0.0);
129	 glVertex3i(x, size - 1 - x, z);
130      }
131   glEnd();
132
133   return size * num / 5;
134}
135
136/***************************************************************************/
137
138static void
139init_test04(void)
140{
141   int x, y;
142   GLubyte tex[128 * 128 * 3];
143   GLenum gluerr;
144
145   glMatrixMode(GL_PROJECTION);
146   glLoadIdentity();
147   glOrtho(-0.5, 639.5, -0.5, 479.5, 1.0, -1000.0 * 480.0);
148
149   glMatrixMode(GL_MODELVIEW);
150
151   glShadeModel(GL_SMOOTH);
152   glEnable(GL_DEPTH_TEST);
153
154   glEnable(GL_BLEND);
155   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
156
157   for (y = 0; y < 128; y++)
158      for (x = 0; x < 128; x++) {
159	 tex[(x + y * 128) * 3 + 0] = ((x % (128 / 4)) < (128 / 8)) ? 255 : 0;
160	 tex[(x + y * 128) * 3 + 1] = ((y % (128 / 4)) < (128 / 8)) ? 255 : 0;
161	 tex[(x + y * 128) * 3 + 2] = x;
162      }
163
164   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
165   if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 128, 128, GL_RGB,
166				   GL_UNSIGNED_BYTE, (GLvoid *) (&tex[0])))) {
167      fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr));
168      exit(-1);
169   }
170
171   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
172   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
173
174   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
175		   GL_LINEAR_MIPMAP_NEAREST);
176   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
177
178   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
179   glEnable(GL_TEXTURE_2D);
180
181   glClearColor(0.0, 0.1, 1.0, 0.0);
182   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
183}
184
185static int
186test04(int size, int num)
187{
188   int x, y, z;
189
190   glBegin(GL_TRIANGLES);
191   for (y = 0; y < num; y++)
192      for (x = 0; x < size; x += 5) {
193	 z = num * size - (y * size + x);
194	 glTexCoord2f(1.0, 1.0);
195	 glColor3f(1.0, 0.0, 0.0);
196	 glVertex3i(0, x, z);
197
198	 glTexCoord2f(0.0, 1.0);
199	 glColor3f(0.0, 1.0, 0.0);
200	 glVertex3i(size - 1 - x, 0, z);
201
202	 glTexCoord2f(1.0, 0.0);
203	 glColor3f(0.0, 0.0, 1.0);
204	 glVertex3i(x, size - 1 - x, z);
205      }
206   glEnd();
207
208   return num * size / 5;
209}
210
211/***************************************************************************/
212
213static void
214init_test05(void)
215{
216   int x, y;
217   GLubyte tex[128 * 128 * 3];
218   GLenum gluerr;
219
220   glMatrixMode(GL_PROJECTION);
221   glLoadIdentity();
222   glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
223
224   glMatrixMode(GL_MODELVIEW);
225
226   glShadeModel(GL_SMOOTH);
227   glEnable(GL_DEPTH_TEST);
228
229   glEnable(GL_BLEND);
230   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
231
232   for (y = 0; y < 128; y++)
233      for (x = 0; x < 128; x++) {
234	 tex[(x + y * 128) * 3 + 0] = ((x % (128 / 4)) < (128 / 8)) ? 255 : 0;
235	 tex[(x + y * 128) * 3 + 1] = ((y % (128 / 4)) < (128 / 8)) ? 255 : 0;
236	 tex[(x + y * 128) * 3 + 2] = x;
237      }
238
239   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
240   if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 128, 128, GL_RGB,
241				   GL_UNSIGNED_BYTE, (GLvoid *) (&tex[0])))) {
242      fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr));
243      exit(-1);
244   }
245
246   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
247   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
248
249   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
250		   GL_LINEAR_MIPMAP_NEAREST);
251   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
252
253   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
254   glEnable(GL_TEXTURE_2D);
255
256   glDepthFunc(GL_ALWAYS);
257
258   glClearColor(0.0, 0.1, 1.0, 0.0);
259   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
260}
261
262static int
263test05(int size, int num)
264{
265   int y;
266   float v0[3], v1[3], v2[3], v3[3];
267   float cv0[3], cv1[3], cv2[3], cv3[3];
268   float tv0[3], tv1[3], tv2[3], tv3[3];
269
270   v0[0] = 320 - size / 2;
271   v0[1] = 240 - size / 2;
272   v0[2] = 0.0;
273   v1[0] = 320 + size / 2;
274   v1[1] = 240 - size / 2;
275   v1[2] = 0.0;
276   v2[0] = 320 - size / 2;
277   v2[1] = 240 + size / 2;
278   v2[2] = 0.0;
279   v3[0] = 320 + size / 2;
280   v3[1] = 240 + size / 2;
281   v3[2] = 0.0;
282   cv0[0] = 1.0;
283   cv0[1] = 0.0;
284   cv0[2] = 0.0;
285   cv1[0] = 1.0;
286   cv1[1] = 1.0;
287   cv1[2] = 0.0;
288   cv2[0] = 1.0;
289   cv2[1] = 0.0;
290   cv2[2] = 1.0;
291   cv3[0] = 1.0;
292   cv3[1] = 1.0;
293   cv3[2] = 1.0;
294   tv0[0] = 0.0;
295   tv0[1] = 0.0;
296   tv0[2] = 0.0;
297   tv1[0] = 1.0;
298   tv1[1] = 0.0;
299   tv1[2] = 0.0;
300   tv2[0] = 0.0;
301   tv2[1] = 1.0;
302   tv2[2] = 0.0;
303   tv3[0] = 1.0;
304   tv3[1] = 1.0;
305   tv3[2] = 0.0;
306
307   glBegin(GL_TRIANGLE_STRIP);
308   for (y = 0; y < num; y++) {
309      glColor3fv(cv0);
310      glTexCoord2fv(tv0);
311      glVertex3fv(v0);
312
313      glColor3fv(cv1);
314      glTexCoord2fv(tv1);
315      glVertex3fv(v1);
316
317      glColor3fv(cv2);
318      glTexCoord2fv(tv2);
319      glVertex3fv(v2);
320
321      glColor3fv(cv3);
322      glTexCoord2fv(tv3);
323      glVertex3fv(v3);
324   }
325   glEnd();
326
327   return 4 * num - 2;
328}
329
330/***************************************************************************/
331
332static void
333init_test06(void)
334{
335   glMatrixMode(GL_PROJECTION);
336   glLoadIdentity();
337   gluOrtho2D(-0.5, 639.5, -0.5, 479.5);
338   glMatrixMode(GL_MODELVIEW);
339
340   glShadeModel(GL_SMOOTH);
341   glEnable(GL_DEPTH_TEST);
342
343   glClearColor(0.0, 0.1, 1.0, 0.0);
344   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
345}
346
347static int
348test06(int size, int num)
349{
350   int y;
351
352   for (y = 0; y < num; y++) {
353      glClearColor(y / (float) num, 0.1, 1.0, 0.0);
354      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
355   }
356
357   return num;
358}
359
360/***************************************************************************/
361
362#define BMARKS_TIME 5.0
363
364#define NUM_BMARKS 6
365
366/* 554 ~= sqrt(640*480) */
367
368static benchmark bmarks[NUM_BMARKS] = {
369   {"Simple Points", "Pnts", init_test01, test01, 0, 0,
370    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
371   {"Smooth Lines", "Lins", init_test02, test02, 1, 5,
372    {480, 250, 100, 50, 25, 0, 0, 0, 0, 0}},
373   {"ZSmooth Triangles", "Tris", init_test03, test03, 1, 5,
374    {480, 250, 100, 50, 25, 0, 0, 0, 0, 0}},
375   {"ZSmooth Tex Blend Triangles", "Tris", init_test04, test04, 1, 5,
376    {480, 250, 100, 50, 25, 0, 0, 0, 0, 0}},
377   {"ZSmooth Tex Blend TMesh Triangles", "Tris", init_test05, test05, 2, 8,
378    {400, 250, 100, 50, 25, 10, 5, 2, 0, 0}},
379   {"Color/Depth Buffer Clears", "Clrs", init_test06, test06, 3, 0,
380    {554, 0, 0, 0, 0, 0, 0, 0, 0, 0}}
381};
382
383/***************************************************************************/
384
385static void
386dotest0param(benchmark * bmark)
387{
388   float stime, etime, dtime, tottime, maxtime, mintime;
389   int num, numelem, calibnum, j;
390
391   glPushAttrib(GL_ALL_ATTRIB_BITS);
392   bmark->init();
393
394   stime = glutGet(GLUT_ELAPSED_TIME);
395
396   dtime = 0.0;
397   calibnum = 0;
398   while (dtime < 2.0) {
399      bmark->run(0, 1);
400      glFinish();
401      etime = glutGet(GLUT_ELAPSED_TIME);
402      dtime = (etime - stime) / 1000.0;
403      calibnum++;
404   }
405   glPopAttrib();
406
407   fprintf(stderr, "Elapsed time for the calibration test (%d): %f\n",
408	   calibnum, dtime);
409
410   num = (int) ((BMARKS_TIME / dtime) * calibnum);
411
412   if (num < 1)
413      num = 1;
414
415   fprintf(stderr, "Selected number of benchmark iterations: %d\n", num);
416
417   mintime = HUGE_VAL;
418   maxtime = -HUGE_VAL;
419
420   for (tottime = 0.0, j = 0; j < 5; j++) {
421      glPushAttrib(GL_ALL_ATTRIB_BITS);
422      bmark->init();
423
424      stime = glutGet(GLUT_ELAPSED_TIME);
425      numelem = bmark->run(0, num);
426      glFinish();
427      etime = glutGet(GLUT_ELAPSED_TIME);
428
429      glPopAttrib();
430
431      dtime = (etime - stime) / 1000.0;
432      tottime += dtime;
433
434      fprintf(stderr, "Elapsed time for run %d: %f\n", j, dtime);
435
436      if (dtime < mintime)
437	 mintime = dtime;
438      if (dtime > maxtime)
439	 maxtime = dtime;
440   }
441
442   tottime -= mintime + maxtime;
443
444   fprintf(stdout, "%s\n%f %s/sec", bmark->name, numelem / (tottime / 3.0),
445	   bmark->unit);
446
447   if (bmark->type == 3)
448      fprintf(stdout, ", MPixel Fill/sec: %f\n\n",
449	      (numelem * bmark->size[0] * (float) bmark->size[0]) /
450	      (1000000.0 * tottime / 3.0));
451   else
452      fprintf(stdout, "\n\n");
453}
454
455/***************************************************************************/
456
457static void
458dotest1param(benchmark * bmark)
459{
460   float stime, etime, dtime, tottime, maxtime, mintime;
461   int num, numelem, calibnum, j, k;
462
463   fprintf(stdout, "%s\n", bmark->name);
464
465   for (j = 0; j < bmark->numsize; j++) {
466      fprintf(stderr, "Current size: %d\n", bmark->size[j]);
467
468      glPushAttrib(GL_ALL_ATTRIB_BITS);
469      bmark->init();
470
471      stime = glutGet(GLUT_ELAPSED_TIME);
472
473      dtime = 0.0;
474      calibnum = 0;
475      while (dtime < 2.0) {
476	 bmark->run(bmark->size[j], 1);
477	 glFinish();
478	 etime = glutGet(GLUT_ELAPSED_TIME);
479	 dtime = (etime - stime) / 1000.0;
480	 calibnum++;
481      }
482      glPopAttrib();
483
484      fprintf(stderr, "Elapsed time for the calibration test (%d): %f\n",
485	      calibnum, dtime);
486
487      num = (int) ((BMARKS_TIME / dtime) * calibnum);
488
489      if (num < 1)
490	 num = 1;
491
492      fprintf(stderr, "Selected number of benchmark iterations: %d\n", num);
493
494      mintime = HUGE_VAL;
495      maxtime = -HUGE_VAL;
496
497      for (numelem = 1, tottime = 0.0, k = 0; k < 5; k++) {
498	 glPushAttrib(GL_ALL_ATTRIB_BITS);
499	 bmark->init();
500
501	 stime = glutGet(GLUT_ELAPSED_TIME);
502	 numelem = bmark->run(bmark->size[j], num);
503	 glFinish();
504	 etime = glutGet(GLUT_ELAPSED_TIME);
505
506	 glPopAttrib();
507
508	 dtime = (etime - stime) / 1000.0;
509	 tottime += dtime;
510
511	 fprintf(stderr, "Elapsed time for run %d: %f\n", k, dtime);
512
513	 if (dtime < mintime)
514	    mintime = dtime;
515	 if (dtime > maxtime)
516	    maxtime = dtime;
517      }
518
519      tottime -= mintime + maxtime;
520
521      fprintf(stdout, "SIZE=%03d => %f %s/sec", bmark->size[j],
522	      numelem / (tottime / 3.0), bmark->unit);
523      if (bmark->type == 2)
524	 fprintf(stdout, ", MPixel Fill/sec: %f\n",
525		 (numelem * bmark->size[j] * bmark->size[j] / 2) /
526		 (1000000.0 * tottime / 3.0));
527      else
528	 fprintf(stdout, "\n");
529   }
530
531   fprintf(stdout, "\n\n");
532}
533
534/***************************************************************************/
535
536static void
537display(void)
538{
539   int i;
540
541   if (frontbuffer)
542      glDrawBuffer(GL_FRONT);
543   else
544      glDrawBuffer(GL_BACK);
545
546   for (i = 0; i < NUM_BMARKS; i++) {
547      fprintf(stderr, "Benchmark: %d\n", i);
548
549      switch (bmarks[i].type) {
550      case 0:
551      case 3:
552	 dotest0param(&bmarks[i]);
553	 break;
554      case 1:
555      case 2:
556	 dotest1param(&bmarks[i]);
557	 break;
558      }
559   }
560
561   exit(0);
562}
563
564int
565main(int ac, char **av)
566{
567   fprintf(stderr, "GLTest v1.0\nWritten by David Bucciarelli\n");
568
569   if (ac == 2)
570      frontbuffer = 0;
571
572   glutInitWindowSize(640, 480);
573   glutInit(&ac, av);
574   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
575   glutCreateWindow("OpenGL/Mesa Performances");
576   glutDisplayFunc(display);
577   glutMainLoop();
578
579   return 0;
580}
581