add option to slep some time during each frame
[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 static GLBackend *createGLBackend()
19 {
20         return new GLXBackend();
21 }
22 #elif defined(USE_EGL)
23 #include "eglbackend.h"
24 static GLBackend *createGLBackend()
25 {
26         return new EGLBackend();
27 }
28 #else
29 #error "No GL window type selected"
30 #endif
31
32 // configuration
33 static const GLfloat boxWidth = 0.045f;
34 static const GLfloat boxSpeed = 1.25f; // per second
35
36 // profiler
37 enum ProfilerState { statePreRender, stateClear, stateDraw, statePresent, statePostRender, stateOutsideRender, numProfilerStates };
38 static const char *profilerStateNames[numProfilerStates] = { "Pre-Render", "Clearing", "Drawing", "Presenting", "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 rectVertices(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
49 {
50         glVertex2f(x1, y1);
51         glVertex2f(x2, y1);
52         glVertex2f(x2, y2);
53         glVertex2f(x1, y2);
54 }
55
56 // the window
57 class TearTestWindow : public GLWindow {
58 public:
59         TearTestWindow(bool overdraw, bool copy, int sleep_time) : GLWindow(XOpenDisplay(0), createGLBackend()),
60                 overdraw(overdraw), copy(copy), sleep_time(sleep_time), boxPos(0), boxDirection(1)
61         {}
62
63         void setSwapInterval(int i) {
64                 getBackend()->setSwapInterval(i);
65         }
66
67 protected:
68         virtual void initGL()
69         {
70                 // initialize GL proper
71                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
72                 glDisable(GL_DEPTH_TEST);
73                 // initialize clocks
74                 lastFrame = getTime();
75                 // initailize profiler
76                 framect = 0;
77                 memset(stateTime, 0, sizeof(stateTime));
78                 curState = -1;
79                 lastDisplay = lastProfile = getTime();
80         }
81         
82         virtual void resizeGL(unsigned int width, unsigned int height)
83         {
84                 /* prevent divide-by-zero */                      
85                 if (height == 0)                                  
86                         height = 1;                                   
87                 glViewport(0, 0, width, height);
88                 glMatrixMode(GL_PROJECTION);                      
89                 glLoadIdentity();                                 
90                 glOrtho (0, 1, 1, 0, 0, 1);
91                 glMatrixMode(GL_MODELVIEW);      
92                 glClear(GL_COLOR_BUFFER_BIT);                                                 
93                 glFlush();
94         }
95         
96         void profilerTick(ProfilerState nextState)
97         {
98                 assert (nextState >= 0 && nextState < numProfilerStates);
99                 double time = getTime();
100                 if (curState >= 0)
101                         stateTime[curState] += time-lastProfile;
102                 curState = nextState;
103                 lastProfile = time;
104                 // display?
105                 const double elapsed = time-lastDisplay;
106                 if (elapsed >= 3) {
107                         printf("%.1f fps, time spent: ", framect/elapsed);
108                         for (int i = 0; i < numProfilerStates; ++i) {
109                                 if (i != 0) printf(", ");
110                                 printf("%s %.1f%%", profilerStateNames[i], stateTime[i]/elapsed*100);
111                         }
112                         printf("\n");
113                         lastDisplay = time;
114                         framect = 0;
115                         memset(stateTime, 0, sizeof(stateTime));
116                 }
117         }
118         
119         void renderGL()
120         {              
121                 //////////////////////////////////////////////
122                 profilerTick(statePreRender);
123                 double time = getTime();
124                 // anim
125                 double passedTime = time-lastFrame;
126                 boxPos += boxSpeed*passedTime*boxDirection;
127                 while (boxPos < 0 || boxPos+boxWidth > 1) { // wrapover
128                         if (boxPos < 0) {
129                                 boxPos = -boxPos;
130                                 boxDirection = -boxDirection;
131                         }
132                         else {
133                                 boxPos = 1.0-boxWidth-(boxPos+boxWidth-1.0);
134                                 boxDirection = -boxDirection;
135                         }
136                 }
137                 lastFrame = time;
138                 //////////////////////////////////////////////
139                 profilerTick(stateClear);
140                 if (overdraw) {
141                         // clear manually
142                         glBegin(GL_QUADS);
143                         glColor3f(0.0f, 0.0f, 0.0f);
144                         rectVertices(0, 0, 1, 1);
145                         glEnd();
146                 }
147                 else {
148                         glClear(GL_COLOR_BUFFER_BIT);
149                 }
150                 //////////////////////////////////////////////
151                 profilerTick(stateDraw);
152                 glBegin(GL_QUADS);
153                 glColor3f(0.8f, 1.0f, 0.75f);
154                 rectVertices(boxPos, 0, boxPos+boxWidth, 1);
155                 glEnd();
156                 usleep(sleep_time*1000);
157                 //////////////////////////////////////////////
158                 profilerTick(statePresent);
159                 if (copy) {
160                         glDrawBuffer(GL_FRONT);
161                         glCopyPixels(0, 0, getWidth(), getHeight(), GL_COLOR);
162                         glDrawBuffer(GL_BACK);
163                 }
164                 else {
165                         getBackend()->swapBuffers();
166                 }
167                 //////////////////////////////////////////////
168                 profilerTick(statePostRender);
169                 glFlush();
170                 ++framect;
171                 //////////////////////////////////////////////
172                 profilerTick(stateOutsideRender);
173         }
174         
175         virtual void handleKeyPress(KeySym key)
176         {
177                 switch (key) {
178                         case XK_Escape: close(); break;
179                         case XK_F1: setFullscreen(!getFullscreen()); break;
180                         default: break;
181                 }
182         }
183
184 private:
185         bool overdraw, copy;
186         int sleep_time;
187         // animation control
188         double lastFrame;
189         GLfloat boxPos, boxDirection;
190         // FPS, profiler
191         double lastDisplay, lastProfile;                 
192         int framect, curState;
193         double stateTime[numProfilerStates];
194 };
195
196 int main(int argc, char ** argv)
197 {
198         // program options handling
199         po::options_description desc("Allowed options");
200         desc.add_options()
201                 ("help,h", "produce help message")
202                 ("swap-interval,i", po::value<int>(), "set swap interval")
203                 ("copy,c", "copy to front buffer (instead of performing a buffer swap)")
204                 ("overdraw,o", "overdraw previous image (instead of calling glClear)")
205                 ("sleep,s", po::value<int>()->default_value(0), "Number of milliseconds to sleap in each frame (in the drawing phase)")
206         ;
207         po::variables_map vm;
208         po::store(po::parse_command_line(argc, argv, desc), vm);
209         po::notify(vm);
210
211         if (vm.count("help")) {
212                 std::cout << desc << "\n";
213                 return 1;
214         }
215
216         // actual program
217         TearTestWindow w(vm.count("overdraw"), vm.count("copy"), vm["sleep"].as<int>());
218         w.open(800, 600);
219         if (vm.count("swap-interval"))
220                 w.setSwapInterval(vm["swap-interval"].as<int>());
221         w.exec();
222 }