]> git.cworth.org Git - apitrace/blob - retrace/glretrace_main.cpp
Removed arbitary limit on active queries.
[apitrace] / retrace / glretrace_main.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <string.h>
28
29 #include "retrace.hpp"
30 #include "glproc.hpp"
31 #include "glstate.hpp"
32 #include "glretrace.hpp"
33 #include "os_time.hpp"
34
35
36 namespace glretrace {
37
38 bool insideList = false;
39 bool insideGlBeginEnd = false;
40
41 struct CallQuery
42 {
43     GLuint ids[3];
44     unsigned call;
45     GLuint program;
46     const trace::FunctionSig *sig;
47     uint64_t start;
48     uint64_t duration;
49 };
50
51 static bool firstFrame = true;
52 static std::list<CallQuery> callQueries;
53 static std::map<glws::Context*, GLuint> activePrograms;
54
55
56 void
57 checkGlError(trace::Call &call) {
58     GLenum error = glGetError();
59     if (error == GL_NO_ERROR) {
60         return;
61     }
62
63     std::ostream & os = retrace::warning(call);
64
65     os << "glGetError(";
66     os << call.name();
67     os << ") = ";
68
69     switch (error) {
70     case GL_INVALID_ENUM:
71         os << "GL_INVALID_ENUM";
72         break;
73     case GL_INVALID_VALUE:
74         os << "GL_INVALID_VALUE";
75         break;
76     case GL_INVALID_OPERATION:
77         os << "GL_INVALID_OPERATION";
78         break;
79     case GL_STACK_OVERFLOW:
80         os << "GL_STACK_OVERFLOW";
81         break;
82     case GL_STACK_UNDERFLOW:
83         os << "GL_STACK_UNDERFLOW";
84         break;
85     case GL_OUT_OF_MEMORY:
86         os << "GL_OUT_OF_MEMORY";
87         break;
88     case GL_INVALID_FRAMEBUFFER_OPERATION:
89         os << "GL_INVALID_FRAMEBUFFER_OPERATION";
90         break;
91     case GL_TABLE_TOO_LARGE:
92         os << "GL_TABLE_TOO_LARGE";
93         break;
94     default:
95         os << error;
96         break;
97     }
98     os << "\n";
99 }
100
101 static GLuint64
102 getGpuTimestamp() {
103     GLuint query = 0;
104     GLuint64 timestamp = 0;
105
106     if (retrace::profilingGpuTimes) {
107         glGenQueries(1, &query);
108         glQueryCounter(query, GL_TIMESTAMP);
109         glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT, &timestamp);
110         glDeleteQueries(1, &query);
111     }
112
113     return timestamp;
114 }
115
116 static GLuint64
117 getCpuTimestamp() {
118     if (retrace::profilingCpuTimes) {
119         return os::getTime() * (1.0E9 / os::timeFrequency);
120     } else {
121         return 0;
122     }
123 }
124
125 static void
126 completeCallQuery(CallQuery& query) {
127     /* Get call start and duration */
128     GLuint64 timestamp = 0, duration = 0, samples = 0;
129
130     if (retrace::profilingGpuTimes) {
131         glGetQueryObjectui64vEXT(query.ids[0], GL_QUERY_RESULT, &timestamp);
132         glGetQueryObjectui64vEXT(query.ids[1], GL_QUERY_RESULT, &duration);
133     }
134
135     if (retrace::profilingPixelsDrawn) {
136         glGetQueryObjectui64vEXT(query.ids[2], GL_QUERY_RESULT, &samples);
137     }
138
139     glDeleteQueries(3, query.ids);
140
141     /* Add call to profile */
142     retrace::profiler.addCall(query.call, query.sig->name, query.program, samples, timestamp, duration, query.start, query.duration);
143 }
144
145 void
146 flushQueries() {
147     for (std::list<CallQuery>::iterator itr = callQueries.begin(); itr != callQueries.end(); ++itr) {
148         completeCallQuery(*itr);
149     }
150
151     callQueries.clear();
152 }
153
154 void setActiveProgram(GLuint program)
155 {
156     activePrograms[glretrace::currentContext] = program;
157 }
158
159 static GLuint
160 getActiveProgram()
161 {
162     std::map<glws::Context*, GLuint>::iterator it;
163     it = activePrograms.find(glretrace::currentContext);
164     if (it == activePrograms.end())
165         return 0;
166
167     return it->second;
168 }
169
170 void
171 beginProfile(trace::Call &call) {
172     if (firstFrame) {
173         const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
174         if (!glws::checkExtension("GL_ARB_timer_query", extensions)) {
175             std::cout << "Error: Cannot run profile, GL_ARB_timer_query extension is not supported." << std::endl;
176             exit(-1);
177         }
178
179         frame_start();
180     }
181
182     /* Create call query */
183     CallQuery query;
184     query.call = call.no;
185     query.sig = call.sig;
186     query.program = getActiveProgram();
187
188     glGenQueries(3, query.ids);
189
190     if (retrace::profilingGpuTimes) {
191         glQueryCounter(query.ids[0], GL_TIMESTAMP);
192         glBeginQuery(GL_TIME_ELAPSED, query.ids[1]);
193     }
194
195     if (retrace::profilingPixelsDrawn) {
196         glBeginQuery(GL_SAMPLES_PASSED, query.ids[2]);
197     }
198
199     if (retrace::profilingCpuTimes) {
200         query.start = os::getTime();
201     }
202
203     callQueries.push_back(query);
204 }
205
206 void
207 endProfile(trace::Call &call) {
208     if (retrace::profilingCpuTimes) {
209         CallQuery& query = callQueries.back();
210         query.duration = (os::getTime() - query.start) * (1.0E9 / os::timeFrequency);
211     }
212
213     if (retrace::profilingGpuTimes) {
214         glEndQuery(GL_TIME_ELAPSED);
215     }
216
217     if (retrace::profilingPixelsDrawn) {
218         glEndQuery(GL_SAMPLES_PASSED);
219     }
220 }
221
222 void
223 frame_start() {
224     firstFrame = false;
225
226     if (retrace::profiling) {
227         retrace::profiler.addFrameStart(retrace::frameNo, getGpuTimestamp(), getCpuTimestamp());
228     }
229 }
230
231 void
232 frame_complete(trace::Call &call) {
233     if (retrace::profiling) {
234         /* Complete any remaining queries */
235         flushQueries();
236
237         /* Indicate end of current frame */
238         retrace::profiler.addFrameEnd(getGpuTimestamp(), getCpuTimestamp());
239     }
240
241     retrace::frameComplete(call);
242
243     /* Indicate start of next frame */
244     frame_start();
245
246     if (!currentDrawable) {
247         return;
248     }
249
250     if (retrace::debug && !currentDrawable->visible) {
251         retrace::warning(call) << "could not infer drawable size (glViewport never called)\n";
252     }
253 }
254
255 } /* namespace glretrace */
256
257
258 void
259 retrace::setUp(void) {
260     glws::init();
261 }
262
263
264 void
265 retrace::addCallbacks(retrace::Retracer &retracer)
266 {
267     retracer.addCallbacks(glretrace::gl_callbacks);
268     retracer.addCallbacks(glretrace::glx_callbacks);
269     retracer.addCallbacks(glretrace::wgl_callbacks);
270     retracer.addCallbacks(glretrace::cgl_callbacks);
271     retracer.addCallbacks(glretrace::egl_callbacks);
272 }
273
274
275 image::Image *
276 retrace::getSnapshot(void) {
277     if (!glretrace::currentDrawable) {
278         return NULL;
279     }
280
281     return glstate::getDrawBufferImage();
282 }
283
284
285 bool
286 retrace::dumpState(std::ostream &os)
287 {
288     if (glretrace::insideGlBeginEnd ||
289         !glretrace::currentDrawable ||
290         !glretrace::currentContext) {
291         return false;
292     }
293
294     glstate::dumpCurrentContext(os);
295
296     return true;
297 }
298
299 void
300 retrace::flushRendering(void) {
301     glretrace::flushQueries();
302     glFlush();
303 }
304
305 void
306 retrace::waitForInput(void) {
307     while (glws::processEvents()) {
308     }
309 }
310
311 void
312 retrace::cleanUp(void) {
313     glws::cleanup();
314 }