add command-line option for swap interval
[gltest.git] / gltest.cpp
1 // stdlib includes
2 #include <time.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <limits.h>
7 #include <unistd.h>
8 #include <assert.h>
9 #include <GL/gl.h>
10 #include <boost/program_options.hpp>
11
12 namespace po = boost::program_options;
13
14 // include proper GL connector
15 #include "glwindow.h"
16 #if defined(USE_GLX)
17 #include "glxbackend.h"
18 GLBackend *createGLBackend()
19 {
20         return new GLXBackend();
21 }
22 #elif defined(USE_EGL)
23 #include "eglbackend.h"
24 GLBackend *createGLBackend()
25 {
26         return new EGLBackend();
27 }
28 #else
29 #error "No GL window type selected"
30 #endif
31
32 // configuration
33 const GLfloat boxWidth = 0.045f;
34 const GLfloat boxSpeed = 1.25f; // per second
35
36 // profiler
37 const int numProfilerStates = 5;
38 const char *profilerStateNames[numProfilerStates] = { "Pre-Render", "Drawing", "Swapping", "Post-Render", "Outside renderer"};
39
40 // utility functions
41 static double getTime()
42 {
43         struct timespec tp;
44         clock_gettime(CLOCK_MONOTONIC, &tp);
45         return tp.tv_sec + 1e-9 * tp.tv_nsec;
46 }
47
48 static void drawRect(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
49 {
50         glVertex2f(x1, y1); glVertex2f(x2, y1); glVertex2f(x2, y2); glVertex2f(x1, y2);
51 }
52
53 // the window
54 class TearTestWindow : public GLWindow {
55 public:
56         TearTestWindow() : GLWindow(XOpenDisplay(0), createGLBackend()), boxPos(0), boxDirection(1)
57         {}
58
59         void setSwapInterval(int i) {
60                 getBackend()->setSwapInterval(i);
61         }
62
63 protected:
64         virtual void initGL()
65         {
66                 // initialize GL proper
67                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
68                 glDisable(GL_DEPTH_TEST);
69                 // initialize clocks
70                 lastFrame = getTime();
71                 // initailize profiler
72                 framect = 0;
73                 memset(stateTime, 0, sizeof(stateTime));
74                 curState = -1;
75                 lastDisplay = lastProfile = getTime();
76         }
77         
78         virtual void resizeGL(unsigned int width, unsigned int height)
79         {
80                 /* prevent divide-by-zero */                      
81                 if (height == 0)                                  
82                         height = 1;                                   
83                 glViewport(0, 0, width, height);
84                 glMatrixMode(GL_PROJECTION);                      
85                 glLoadIdentity();                                 
86                 glOrtho (0, 1, 1, 0, 0, 1);
87                 glMatrixMode(GL_MODELVIEW);      
88                 glClear(GL_COLOR_BUFFER_BIT);                                                 
89                 glFlush();
90         }
91         
92         void profilerTick(int nextState)
93         {
94                 assert (nextState >= 0 && nextState < numProfilerStates);
95                 double time = getTime();
96                 if (curState >= 0)
97                         stateTime[curState] += time-lastProfile;
98                 curState = nextState;
99                 lastProfile = time;
100                 // display?
101                 const double elapsed = time-lastDisplay;
102                 if (elapsed >= 3) {
103                         printf("%.1f fps, time spent: ", framect/elapsed);
104                         for (int i = 0; i < numProfilerStates; ++i) {
105                                 if (i != 0) printf(", ");
106                                 printf("%s %.1f%%", profilerStateNames[i], stateTime[i]/elapsed*100);
107                         }
108                         printf("\n");
109                         lastDisplay = time;
110                         framect = 0;
111                         memset(stateTime, 0, sizeof(stateTime));
112                 }
113         }
114         
115         void renderGL()
116         {                            
117                 profilerTick(0);
118                 double time = getTime();
119                 // anim
120                 double passedTime = time-lastFrame;
121                 boxPos += boxSpeed*passedTime*boxDirection;
122                 while (boxPos < 0 || boxPos+boxWidth > 1) { // wrapover
123                         if (boxPos < 0) {
124                                 boxPos = -boxPos;
125                                 boxDirection = -boxDirection;
126                         }
127                         else {
128                                 boxPos = 1.0-boxWidth-(boxPos+boxWidth-1.0);
129                                 boxDirection = -boxDirection;
130                         }
131                 }
132                 lastFrame = time;
133                 // draw
134                 //glFlush();
135                 profilerTick(1);
136                 //glClear(GL_COLOR_BUFFER_BIT);
137                 glBegin(GL_QUADS);
138                 // clear manually
139                 glColor3f(0.0f, 0.0f, 0.0f);
140                 drawRect(0, 0, 1, 1);
141                 glColor3f(0.8f, 1.0f, 0.75f);
142                 drawRect(boxPos, 0, boxPos+boxWidth, 1);
143                 glEnd();
144                 usleep(20*1000);
145                 profilerTick(2);
146                 getBackend()->swapBuffers();
147 //              glDrawBuffer(GL_FRONT);
148 //              int xpos = 0;
149 //              int ypos = 0;
150                 //foreach (const QRect &r, region.rects()) {
151                         // convert to OpenGL coordinates
152                         //int y = displayHeight() - 0 - r.height();
153 //                      glBitmap(0, 0, 0, 0, 0 - xpos, 0 - ypos, NULL); // not glRasterPos2f, see glxbackend.cpp
154 //                      xpos = 0;
155 //                      ypos = 0;
156 //                      glCopyPixels(0, 0, getWidth(), getHeight(), GL_COLOR);
157                 //}
158 //              glBitmap(0, 0, 0, 0, -xpos, -ypos, NULL); // move position back to 0,0
159 //              glDrawBuffer(GL_BACK);
160                 profilerTick(3);
161                 glFlush();
162                 ++framect;
163                 profilerTick(4);
164         }
165         
166         virtual void handleKeyPress(KeySym key)
167         {
168                 switch (key) {
169                         case XK_Escape: close(); break;
170                         case XK_F1: setFullscreen(!getFullscreen()); break;
171                         default: break;
172                 }
173         }
174
175 private:
176         double lastFrame;
177         GLfloat boxPos, boxDirection;
178         // FPS
179         double lastDisplay, lastProfile;                 
180         int framect, curState;
181         double stateTime[numProfilerStates];
182 };
183
184
185
186 int main(int argc, char ** argv)
187 {
188         // program options handling
189         po::options_description desc("Allowed options");
190         desc.add_options()
191                 ("help,h", "produce help message")
192                 ("swap-interval,i", po::value<int>(), "set swap interval")
193         ;
194         po::variables_map vm;
195         po::store(po::parse_command_line(argc, argv, desc), vm);
196         po::notify(vm);
197
198         if (vm.count("help")) {
199                 std::cout << desc << "\n";
200                 return 1;
201         }
202
203         // actual program
204         TearTestWindow w;
205         w.open(800, 600);
206         if (vm.count("swap-interval"))
207                 w.setSwapInterval(vm["swap-interval"].as<int>());
208         w.exec();
209 }