1 /**
2  *
3  * Compiz benchmark plugin
4  *
5  * bench.c
6  *
7  * Copyright : (C) 2006 by Dennis Kasprzyk
8  * E-mail    : onestone@beryl-project.org
9  *
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  **/
22 
23 #include <compiz-core.h>
24 
25 #include "bench_tex.h"
26 #include "bench_options.h"
27 
28 #define GET_BENCH_DISPLAY(d)                                  \
29     ((BenchDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
30 
31 #define BENCH_DISPLAY(d)                      \
32     BenchDisplay *bd = GET_BENCH_DISPLAY (d)
33 
34 #define GET_BENCH_SCREEN(s, bd)                                   \
35     ((BenchScreen *) (s)->base.privates[(bd)->screenPrivateIndex].ptr)
36 
37 #define BENCH_SCREEN(s)                                                      \
38     BenchScreen *bs = GET_BENCH_SCREEN (s, GET_BENCH_DISPLAY (s->display))
39 
40 #define TIMEVALDIFF(tv1, tv2)                                              \
41     (((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
42      ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) +                         \
43       ((tv1)->tv_usec - (tv2)->tv_usec)) / 1000 :                           \
44      ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) +                     \
45       (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)) / 1000)
46 
47 #define TIMEVALDIFFU(tv1, tv2)                                              \
48     (((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
49      ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) +                      \
50       ((tv1)->tv_usec - (tv2)->tv_usec)):                                   \
51      ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) +                  \
52       (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)))
53 
54 #ifdef GL_DEBUG
55 
56 static GLenum gl_error;
57 
58 #define GLERR  gl_error=glGetError(); if (gl_error !=  GL_NO_ERROR) { fprintf (stderr,"GL error 0x%X has occured at %s:%d\n",gl_error,__FILE__,__LINE__); }
59 #else
60 #define GLERR
61 #endif
62 
63 static int displayPrivateIndex = 0;
64 
65 typedef struct _BenchDisplay
66 {
67     int  screenPrivateIndex;
68     Bool active;
69 }
70 BenchDisplay;
71 
72 typedef struct _BenchScreen
73 {
74     GLuint dList;
75     float  rrVal;
76     float  fps;
77     float  alpha;
78 
79     struct timeval initTime;
80     struct timeval lastRedraw;
81 
82     float ctime;
83     float frames;
84 
85     GLuint numTex[10];
86     GLuint backTex;
87 
88     PreparePaintScreenProc preparePaintScreen;
89     DonePaintScreenProc    donePaintScreen;
90     PaintOutputProc        paintOutput;
91 }
92 BenchScreen;
93 
94 static void
benchPreparePaintScreen(CompScreen * s,int ms)95 benchPreparePaintScreen (CompScreen *s,
96 			 int        ms)
97 {
98     BENCH_SCREEN (s);
99     BENCH_DISPLAY (s->display);
100 
101     float nRrVal;
102     float ratio = 0.05;
103     int   timediff;
104 
105     struct timeval now;
106 
107     gettimeofday (&now, 0);
108 
109     timediff = TIMEVALDIFF (&now, &bs->lastRedraw);
110 
111     nRrVal = MIN (1.1, (float) s->optimalRedrawTime / (float) timediff);
112 
113     bs->rrVal = (bs->rrVal * (1.0 - ratio) ) + (nRrVal * ratio);
114 
115     bs->fps = (bs->fps * (1.0 - ratio) ) +
116 	      (1000000.0 / TIMEVALDIFFU (&now, &bs->lastRedraw) * ratio);
117 
118     bs->lastRedraw = now;
119 
120     if (benchGetOutputConsole (s->display) && bd->active)
121     {
122 	bs->frames++;
123 	bs->ctime += timediff;
124 
125 	if (bs->ctime >
126 	    benchGetConsoleUpdateTime (s->display) * 1000)
127 	{
128 	    printf ("[BENCH] : %.0f frames in %.1f seconds = %.3f FPS\n",
129 		    bs->frames, bs->ctime / 1000.0,
130 		    bs->frames / (bs->ctime / 1000.0) );
131 	    bs->frames = 0;
132 	    bs->ctime = 0;
133 	}
134     }
135 
136     UNWRAP (bs, s, preparePaintScreen);
137     (*s->preparePaintScreen) (s, (bs->alpha > 0.0) ? timediff : ms);
138     WRAP (bs, s, preparePaintScreen, benchPreparePaintScreen);
139 
140     if (bd->active)
141 	bs->alpha += timediff / 1000.0;
142     else
143 	bs->alpha -= timediff / 1000.0;
144 
145     bs->alpha = MIN (1.0, MAX (0.0, bs->alpha) );
146 }
147 
148 static void
benchDonePaintScreen(CompScreen * s)149 benchDonePaintScreen (CompScreen *s)
150 {
151     BENCH_SCREEN (s);
152     BENCH_DISPLAY (s->display);
153 
154     if (bs->alpha > 0.0)
155     {
156 	damageScreen (s);
157 	glFlush();
158 	XSync (s->display->display, FALSE);
159 
160 	if (benchGetDisableLimiter (s->display) )
161 	{
162 	    s->lastRedraw = bs->initTime;
163 	    s->timeMult = 0;
164 	}
165 
166 	if (!bd->active)
167 	    s->timeMult = 0;
168     }
169 
170     UNWRAP (bs, s, donePaintScreen);
171     (*s->donePaintScreen) (s);
172     WRAP (bs, s, donePaintScreen, benchDonePaintScreen);
173 }
174 
175 static Bool
benchPaintOutput(CompScreen * s,const ScreenPaintAttrib * sa,const CompTransform * transform,Region region,CompOutput * output,unsigned int mask)176 benchPaintOutput (CompScreen              *s,
177 		  const ScreenPaintAttrib *sa,
178 		  const CompTransform     *transform,
179 		  Region                  region,
180 		  CompOutput              *output,
181 		  unsigned int            mask)
182 {
183 
184     Bool status,  isSet;
185     unsigned int  fps;
186     CompTransform sTransform = *transform;
187 
188     BENCH_SCREEN (s);
189 
190     UNWRAP (bs, s, paintOutput);
191     status = (*s->paintOutput) (s, sa, transform, region, output, mask);
192     WRAP (bs, s, paintOutput, benchPaintOutput);
193 
194     if (bs->alpha <= 0.0
195 	|| !benchGetOutputScreen (s->display) )
196 	return status;
197 
198     glGetError();
199     glPushAttrib (GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT);
200     GLERR;
201 
202     transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
203 
204     glPushMatrix ();
205     glLoadMatrixf (sTransform.m);
206 
207     glEnable (GL_BLEND);
208     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
209     glColor4f (1.0, 1.0, 1.0, bs->alpha);
210     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
211 
212     glTranslatef (benchGetPositionX (s->display),
213 		  benchGetPositionY (s->display), 0);
214 
215     glEnable (GL_TEXTURE_2D);
216     glBindTexture (GL_TEXTURE_2D, bs->backTex);
217 
218     glBegin (GL_QUADS);
219     glTexCoord2f (0, 0);
220     glVertex2f (0, 0);
221     glTexCoord2f (0, 1);
222     glVertex2f (0, 256);
223     glTexCoord2f (1, 1);
224     glVertex2f (512, 256);
225     glTexCoord2f (1, 0);
226     glVertex2f (512, 0);
227     glEnd();
228 
229     glBindTexture (GL_TEXTURE_2D, 0);
230     glDisable (GL_TEXTURE_2D);
231 
232     glTranslatef (53, 83, 0);
233 
234     float rrVal = MIN (1.0, MAX (0.0, bs->rrVal) );
235 
236     if (rrVal < 0.5)
237     {
238 	glBegin (GL_QUADS);
239 	glColor4f (1.0, 0.0, 0.0, bs->alpha);
240 	glVertex2f (0.0, 0.0);
241 	glVertex2f (0.0, 25.0);
242 	glColor4f (1.0, rrVal * 2.0, 0.0, bs->alpha);
243 	glVertex2f (330.0 * rrVal, 25.0);
244 	glVertex2f (330.0 * rrVal, 0.0);
245 	glEnd();
246     }
247     else
248     {
249 	glBegin (GL_QUADS);
250 	glColor4f (1.0, 0.0, 0.0, bs->alpha);
251 	glVertex2f (0.0, 0.0);
252 	glVertex2f (0.0, 25.0);
253 	glColor4f (1.0, 1.0, 0.0, bs->alpha);
254 	glVertex2f (165.0, 25.0);
255 	glVertex2f (165.0, 0.0);
256 	glEnd();
257 
258 	glBegin (GL_QUADS);
259 	glColor4f (1.0, 1.0, 0.0, bs->alpha);
260 	glVertex2f (165.0, 0.0);
261 	glVertex2f (165.0, 25.0);
262 	glColor4f (1.0 - ( (rrVal - 0.5) * 2.0), 1.0, 0.0, bs->alpha);
263 	glVertex2f (165.0 + 330.0 * (rrVal - 0.5), 25.0);
264 	glVertex2f (165.0 + 330.0 * (rrVal - 0.5), 0.0);
265 	glEnd();
266     }
267 
268     glColor4f (0.0, 0.0, 0.0, bs->alpha);
269     glCallList (bs->dList);
270     glTranslatef (72, 45, 0);
271 
272     float red;
273 
274     if (bs->fps > 30.0)
275 	red = 0.0;
276     else
277 	red = 1.0;
278 
279     if (bs->fps <= 30.0 && bs->fps > 20.0)
280 	red = 1.0 - ( (bs->fps - 20.0) / 10.0);
281 
282     glColor4f (red, 0.0, 0.0, bs->alpha);
283     glEnable (GL_TEXTURE_2D);
284 
285     isSet = FALSE;
286 
287     fps = (bs->fps * 100.0);
288     fps = MIN (999999, fps);
289 
290     if (fps >= 100000)
291     {
292 	glBindTexture (GL_TEXTURE_2D, bs->numTex[fps / 100000]);
293 	glCallList (bs->dList + 1);
294 	isSet = TRUE;
295     }
296 
297     fps %= 100000;
298 
299     glTranslatef (12, 0, 0);
300 
301     if (fps >= 10000 || isSet)
302     {
303 	glBindTexture (GL_TEXTURE_2D, bs->numTex[fps / 10000]);
304 	glCallList (bs->dList + 1);
305 	isSet = TRUE;
306     }
307 
308     fps %= 10000;
309 
310     glTranslatef (12, 0, 0);
311 
312     if (fps >= 1000 || isSet)
313     {
314 	glBindTexture (GL_TEXTURE_2D, bs->numTex[fps / 1000]);
315 	glCallList (bs->dList + 1);
316     }
317 
318     fps %= 1000;
319 
320     glTranslatef (12, 0, 0);
321 
322     glBindTexture (GL_TEXTURE_2D, bs->numTex[fps / 100]);
323     glCallList (bs->dList + 1);
324     fps %= 100;
325 
326     glTranslatef (19, 0, 0);
327 
328     glBindTexture (GL_TEXTURE_2D, bs->numTex[fps / 10]);
329     glCallList (bs->dList + 1);
330     fps %= 10;
331 
332     glTranslatef (12, 0, 0);
333 
334     glBindTexture (GL_TEXTURE_2D, bs->numTex[fps]);
335     glCallList (bs->dList + 1);
336 
337     glBindTexture (GL_TEXTURE_2D, 0);
338     glDisable (GL_TEXTURE_2D);
339 
340     glPopMatrix();
341 
342     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
343 
344     glColor4f (1.0, 1.0, 1.0, 1.0);
345 
346     glPopAttrib();
347     glGetError();
348 
349     return status;
350 }
351 
352 static Bool
benchInitScreen(CompPlugin * p,CompScreen * s)353 benchInitScreen (CompPlugin *p,
354 		 CompScreen *s)
355 {
356     int i;
357 
358     BENCH_DISPLAY (s->display);
359 
360     BenchScreen *bs = (BenchScreen *) calloc (1, sizeof (BenchScreen) );
361 
362     s->base.privates[bd->screenPrivateIndex].ptr = bs;
363 
364     WRAP (bs, s, paintOutput, benchPaintOutput);
365     WRAP (bs, s, preparePaintScreen, benchPreparePaintScreen);
366     WRAP (bs, s, donePaintScreen, benchDonePaintScreen);
367 
368     glGenTextures (10, bs->numTex);
369     glGenTextures (1, &bs->backTex);
370 
371     glGetError();
372 
373     glEnable (GL_TEXTURE_2D);
374 
375     bs->alpha = 0;
376     bs->ctime = 0;
377     bs->frames = 0;
378 
379     for (i = 0; i < 10; i++)
380     {
381 	//Bind the texture
382 	glBindTexture (GL_TEXTURE_2D, bs->numTex[i]);
383 
384 	//Load the parameters
385 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
386 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
387 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
388 	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
389 
390 	glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, 16, 32, 0,
391 		      GL_RGBA, GL_UNSIGNED_BYTE, number_data[i]);
392 	GLERR;
393     }
394 
395     glBindTexture (GL_TEXTURE_2D, bs->backTex);
396 
397     //Load the parameters
398     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
399     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
400     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
401     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
402 
403     glTexImage2D (GL_TEXTURE_2D, 0, 4, 512, 256, 0, GL_RGBA,
404 		  GL_UNSIGNED_BYTE, image_data);
405     GLERR;
406 
407     glBindTexture (GL_TEXTURE_2D, 0);
408     glDisable (GL_TEXTURE_2D);
409 
410     bs->dList = glGenLists (2);
411     glNewList (bs->dList, GL_COMPILE);
412 
413     glLineWidth (2.0);
414 
415     glBegin (GL_LINE_LOOP);
416     glVertex2f (0, 0);
417     glVertex2f (0, 25);
418     glVertex2f (330, 25);
419     glVertex2f (330, 0);
420     glEnd();
421 
422     glLineWidth (1.0);
423 
424     glBegin (GL_LINES);
425 
426     for (i = 33; i < 330; i += 33)
427     {
428 	glVertex2f (i, 15);
429 	glVertex2f (i, 25);
430     }
431 
432     for (i = 16; i < 330; i += 33)
433     {
434 	glVertex2f (i, 20);
435 	glVertex2f (i, 25);
436     }
437 
438     glEnd();
439 
440     glEndList();
441 
442     glNewList (bs->dList + 1, GL_COMPILE);
443     glBegin (GL_QUADS);
444     glTexCoord2f (0, 0);
445     glVertex2f (0, 0);
446     glTexCoord2f (0, 1);
447     glVertex2f (0, 32);
448     glTexCoord2f (1, 1);
449     glVertex2f (16, 32);
450     glTexCoord2f (1, 0);
451     glVertex2f (16, 0);
452     glEnd();
453     glEndList();
454 
455     gettimeofday (&bs->initTime, 0);
456     gettimeofday (&bs->lastRedraw, 0);
457 
458     return TRUE;
459 }
460 
461 
462 static void
benchFiniScreen(CompPlugin * p,CompScreen * s)463 benchFiniScreen (CompPlugin *p,
464 		 CompScreen *s)
465 {
466 
467     BENCH_SCREEN (s);
468     glDeleteLists (bs->dList, 2);
469 
470     glDeleteTextures (10, bs->numTex);
471     glDeleteTextures (1, &bs->backTex);
472 
473     //Restore the original function
474     UNWRAP (bs, s, paintOutput);
475     UNWRAP (bs, s, preparePaintScreen);
476     UNWRAP (bs, s, donePaintScreen);
477 
478     //Free the pointer
479     free (bs);
480 }
481 
482 static Bool
benchInitiate(CompDisplay * d,CompAction * ac,CompActionState state,CompOption * option,int nOption)483 benchInitiate (CompDisplay     *d,
484 	       CompAction      *ac,
485 	       CompActionState state,
486 	       CompOption      *option,
487 	       int             nOption)
488 {
489     CompScreen *s;
490 
491     BENCH_DISPLAY (d);
492     bd->active = !bd->active;
493     bd->active &= benchGetOutputScreen (d) || benchGetOutputConsole (d);
494     s = findScreenAtDisplay (d, getIntOptionNamed (option, nOption, "root", 0));
495 
496     if (s)
497     {
498 	BENCH_SCREEN (s);
499 	damageScreen (s);
500 	bs->ctime = 0;
501 	bs->frames = 0;
502     }
503 
504     return FALSE;
505 }
506 
507 static Bool
benchInitDisplay(CompPlugin * p,CompDisplay * d)508 benchInitDisplay (CompPlugin  *p,
509 		  CompDisplay *d)
510 {
511     //Generate a bench display
512     BenchDisplay *bd;
513 
514     if (!checkPluginABI ("core", CORE_ABIVERSION))
515 	return FALSE;
516 
517     bd = (BenchDisplay *) malloc (sizeof (BenchDisplay));
518 
519     if (!bd)
520 	return FALSE;
521 
522     //Allocate a private index
523     bd->screenPrivateIndex = allocateScreenPrivateIndex (d);
524     //Check if its valid
525 
526     if (bd->screenPrivateIndex < 0)
527     {
528 	//Its invalid so free memory and return
529 	free (bd);
530 	return FALSE;
531     }
532 
533     benchSetInitiateKeyInitiate (d, benchInitiate);
534 
535     bd->active = FALSE;
536     //Record the display
537     d->base.privates[displayPrivateIndex].ptr = bd;
538     return TRUE;
539 }
540 
541 static void
benchFiniDisplay(CompPlugin * p,CompDisplay * d)542 benchFiniDisplay (CompPlugin  *p,
543 		  CompDisplay *d)
544 {
545     BENCH_DISPLAY (d);
546     //Free the private index
547     freeScreenPrivateIndex (d, bd->screenPrivateIndex);
548     //Free the pointer
549     free (bd);
550 }
551 
552 
553 
554 static Bool
benchInit(CompPlugin * p)555 benchInit (CompPlugin * p)
556 {
557     displayPrivateIndex = allocateDisplayPrivateIndex();
558 
559     if (displayPrivateIndex < 0)
560 	return FALSE;
561 
562     return TRUE;
563 }
564 
565 static void
benchFini(CompPlugin * p)566 benchFini (CompPlugin * p)
567 {
568     if (displayPrivateIndex >= 0)
569 	freeDisplayPrivateIndex (displayPrivateIndex);
570 }
571 
572 static CompBool
benchInitObject(CompPlugin * p,CompObject * o)573 benchInitObject (CompPlugin *p,
574 		 CompObject *o)
575 {
576     static InitPluginObjectProc dispTab[] = {
577 	(InitPluginObjectProc) 0, /* InitCore */
578 	(InitPluginObjectProc) benchInitDisplay,
579 	(InitPluginObjectProc) benchInitScreen
580     };
581 
582     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
583 }
584 
585 static void
benchFiniObject(CompPlugin * p,CompObject * o)586 benchFiniObject (CompPlugin *p,
587 		 CompObject *o)
588 {
589     static FiniPluginObjectProc dispTab[] = {
590 	(FiniPluginObjectProc) 0, /* FiniCore */
591 	(FiniPluginObjectProc) benchFiniDisplay,
592 	(FiniPluginObjectProc) benchFiniScreen
593     };
594 
595     DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
596 }
597 
598 CompPluginVTable benchVTable = {
599     "bench",
600     0,
601     benchInit,
602     benchFini,
603     benchInitObject,
604     benchFiniObject,
605     0,
606     0
607 };
608 
609 CompPluginVTable *
getCompPluginInfo(void)610 getCompPluginInfo (void)
611 {
612     return &benchVTable;
613 }
614