add options to conrol presentation and clear behaviour
[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, stateDraw, statePresent, statePostRender, stateOutsideRender, numProfilerStates };
38 static const char *profilerStateNames[numProfilerStates] = { "Pre-Render", "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 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(bool overdraw, bool copy) : GLWindow(XOpenDisplay(0), createGLBackend()), overdraw(overdraw), copy(copy), 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(ProfilerState 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                 //////////////////////////////////////////////
118                 profilerTick(statePreRender);
119                 double time = getTime();
120                 // anim
121                 double passedTime = time-lastFrame;
122                 boxPos += boxSpeed*passedTime*boxDirection;
123                 while (boxPos < 0 || boxPos+boxWidth > 1) { // wrapover
124                         if (boxPos < 0) {
125                                 boxPos = -boxPos;
126                                 boxDirection = -boxDirection;
127                         }
128                         else {
129                                 boxPos = 1.0-boxWidth-(boxPos+boxWidth-1.0);
130                                 boxDirection = -boxDirection;
131                         }
132                 }
133                 lastFrame = time;
134                 //////////////////////////////////////////////
135                 profilerTick(stateDraw);
136                 if (overdraw) {
137                         glBegin(GL_QUADS);
138                         // clear manually
139                         glColor3f(0.0f, 0.0f, 0.0f);
140                         drawRect(0, 0, 1, 1);
141                 }
142                 else {
143                         glClear(GL_COLOR_BUFFER_BIT);
144                         glBegin(GL_QUADS);
145                 }
146                 glColor3f(0.8f, 1.0f, 0.75f);
147                 drawRect(boxPos, 0, boxPos+boxWidth, 1);
148                 glEnd();
149                 //////////////////////////////////////////////
150                 profilerTick(statePresent);
151                 if (copy) {
152                         glDrawBuffer(GL_FRONT);
153                         glCopyPixels(0, 0, getWidth(), getHeight(), GL_COLOR);
154                         glDrawBuffer(GL_BACK);
155                 }
156                 else {
157                         getBackend()->swapBuffers();
158                 }
159                 //////////////////////////////////////////////
160                 profilerTick(statePostRender);
161                 glFlush();
162                 ++framect;
163                 //////////////////////////////////////////////
164                 profilerTick(stateOutsideRender);
165         }
166         
167         virtual void handleKeyPress(KeySym key)
168         {
169                 switch (key) {
170                         case XK_Escape: close(); break;
171                         case XK_F1: setFullscreen(!getFullscreen()); break;
172                         default: break;
173                 }
174         }
175
176 private:
177         bool overdraw, copy;
178         double lastFrame;
179         GLfloat boxPos, boxDirection;
180         // FPS
181         double lastDisplay, lastProfile;                 
182         int framect, curState;
183         double stateTime[numProfilerStates];
184 };
185
186
187
188 int main(int argc, char ** argv)
189 {
190         // program options handling
191         po::options_description desc("Allowed options");
192         desc.add_options()
193                 ("help,h", "produce help message")
194                 ("swap-interval,i", po::value<int>(), "set swap interval")
195                 ("copy,c", "copy to front buffer (instead of performing a buffer swap)")
196                 ("overdraw,o", "overdraw previous image (instead of calling glClear)")
197         ;
198         po::variables_map vm;
199         po::store(po::parse_command_line(argc, argv, desc), vm);
200         po::notify(vm);
201
202         if (vm.count("help")) {
203                 std::cout << desc << "\n";
204                 return 1;
205         }
206
207         // actual program
208         TearTestWindow w(vm.count("overdraw"), vm.count("copy"));
209         w.open(800, 600);
210         if (vm.count("swap-interval"))
211                 w.setSwapInterval(vm["swap-interval"].as<int>());
212         w.exec();
213 }