1 /* gltest - small OpenGL tearing test program
2 * Copyright (C) 2012-2013 Ralf Jung <post@ralfj.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <boost/program_options.hpp>
29 namespace po = boost::program_options;
31 // my GL utility functions and the GL window class
34 // include proper GL backend (windowing system)
36 #include "glxbackend.h"
37 static GLBackend *createGLBackend()
39 return new GLXBackend();
41 #elif defined(WIN_EGL)
42 #include "eglbackend.h"
43 static GLBackend *createGLBackend()
45 return new EGLBackend();
48 #error "No GL window type selected"
52 static const GLfloat boxWidth = 0.045f;
53 static const GLfloat boxSpeed = 1.25f; // per second
56 enum ProfilerState { StatePreRender, StateClear, StateDraw, StatePresent, StatePostRender, StateOutsideRender, NumProfilerStates };
57 static const char *profilerStateNames[NumProfilerStates] = { "Pre-Render", "Clearing", "Drawing", "Presenting", "Post-Render", "Outside renderer"};
60 static double getTime()
63 clock_gettime(CLOCK_MONOTONIC, &tp);
64 return tp.tv_sec + 1e-9 * tp.tv_nsec;
68 class TearTestWindow : public GLWindow {
70 TearTestWindow() : GLWindow(XOpenDisplay(0), createGLBackend()),
71 overdraw(false), sleep_time(0), boxPos(0), boxDirection(1)
74 void setOverdraw(bool overdraw) { this->overdraw = overdraw; }
75 void setSleepTime(int sleep_time) { this->sleep_time = sleep_time; }
77 void setSwapInterval(int i) { getBackend()->setSwapInterval(i); }
84 GLfloat boxPos, boxDirection;
86 double lastDisplay, lastProfile;
88 ProfilerState curState;
89 double stateTime[NumProfilerStates];
94 // initialize GL proper
95 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
96 glDisable(GL_DEPTH_TEST);
98 lastFrame = getTime();
99 // initailize profiler
101 memset(stateTime, 0, sizeof(stateTime));
102 curState = NumProfilerStates;
103 lastDisplay = lastProfile = getTime();
106 virtual void resizeGL(unsigned int width, unsigned int height)
108 glViewport(0, 0, width, height);
109 initialise2dProjection();
110 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
113 void profilerTick(ProfilerState nextState)
115 assert (nextState >= 0 && nextState < NumProfilerStates);
116 double time = getTime();
117 if (curState >= 0 && curState < NumProfilerStates)
118 stateTime[curState] += time-lastProfile;
119 curState = nextState;
122 const double elapsed = time-lastDisplay;
124 printf("%.1f fps, time spent: ", framect/elapsed);
125 for (int i = 0; i < NumProfilerStates; ++i) {
126 if (i != 0) printf(", ");
127 printf("%s %.1f%%", profilerStateNames[i], stateTime[i]/elapsed*100);
132 memset(stateTime, 0, sizeof(stateTime));
138 //////////////////////////////////////////////
139 profilerTick(StatePreRender);
140 double time = getTime();
142 double passedTime = time-lastFrame;
143 boxPos += boxSpeed*passedTime*boxDirection;
144 while (boxPos < 0 || boxPos+boxWidth > 1) { // wrapover
147 boxDirection = -boxDirection;
150 boxPos = 1.0-boxWidth-(boxPos+boxWidth-1.0);
151 boxDirection = -boxDirection;
155 //////////////////////////////////////////////
156 profilerTick(StateClear);
159 drawQuad(/*color*/0.0f, 0.0f, 0.0f, /*coordinates*/0, 0, 1, 1);
162 glClear(GL_COLOR_BUFFER_BIT);
164 //////////////////////////////////////////////
165 profilerTick(StateDraw);
166 drawQuad(/*color*/0.8f, 1.0f, 0.75f, /*coordinates*/boxPos, 0, boxPos+boxWidth, 1);
167 usleep(sleep_time*1000);
168 //////////////////////////////////////////////
169 profilerTick(StatePresent);
170 getBackend()->swapBuffers();
171 //////////////////////////////////////////////
172 profilerTick(StatePostRender);
175 //////////////////////////////////////////////
176 profilerTick(StateOutsideRender);
179 virtual void handleKeyPress(KeySym key)
182 case XK_Escape: close(); break;
183 case XK_F1: setFullscreen(!getFullscreen()); break;
189 int main(int argc, char ** argv)
191 // program options handling
192 po::options_description desc("Allowed options");
194 ("help,h", "produce help message")
195 ("swap-interval,i", po::value<int>(), "set swap interval")
196 ("overdraw,o", "overdraw previous image (instead of calling glClear)")
197 ("sleep,s", po::value<int>()->default_value(0), "Number of milliseconds to sleep in each frame (in the drawing phase)")
199 po::variables_map vm;
200 po::store(po::parse_command_line(argc, argv, desc), vm);
203 if (vm.count("help")) {
204 std::cout << desc << "\n";
210 w.setOverdraw(vm.count("overdraw"));
211 w.setSleepTime(vm["sleep"].as<int>());
213 if (vm.count("swap-interval"))
214 w.setSwapInterval(vm["swap-interval"].as<int>());