]> git.cworth.org Git - apitrace/blob - retrace/glretrace_main.cpp
Added support for recording GL_SAMPLES_PASSED.
[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
34
35 namespace glretrace {
36
37 bool insideList = false;
38 bool insideGlBeginEnd = false;
39
40 struct CallQuery
41 {
42     GLuint ids[3];
43     unsigned call;
44     const trace::FunctionSig *sig;
45 };
46
47 static bool firstFrame = true;
48 static std::list<CallQuery> callQueries;
49 static const int maxActiveCallQueries = 128;
50
51
52 void
53 checkGlError(trace::Call &call) {
54     GLenum error = glGetError();
55     if (error == GL_NO_ERROR) {
56         return;
57     }
58
59     std::ostream & os = retrace::warning(call);
60
61     os << "glGetError(";
62     os << call.name();
63     os << ") = ";
64
65     switch (error) {
66     case GL_INVALID_ENUM:
67         os << "GL_INVALID_ENUM";
68         break;
69     case GL_INVALID_VALUE:
70         os << "GL_INVALID_VALUE";
71         break;
72     case GL_INVALID_OPERATION:
73         os << "GL_INVALID_OPERATION";
74         break;
75     case GL_STACK_OVERFLOW:
76         os << "GL_STACK_OVERFLOW";
77         break;
78     case GL_STACK_UNDERFLOW:
79         os << "GL_STACK_UNDERFLOW";
80         break;
81     case GL_OUT_OF_MEMORY:
82         os << "GL_OUT_OF_MEMORY";
83         break;
84     case GL_INVALID_FRAMEBUFFER_OPERATION:
85         os << "GL_INVALID_FRAMEBUFFER_OPERATION";
86         break;
87     case GL_TABLE_TOO_LARGE:
88         os << "GL_TABLE_TOO_LARGE";
89         break;
90     default:
91         os << error;
92         break;
93     }
94     os << "\n";
95 }
96
97 static GLuint64
98 getTimestamp() {
99     GLuint query = 0;
100     GLuint64 timestamp = 0;
101
102     glGenQueries(1, &query);
103     glQueryCounter(query, GL_TIMESTAMP);
104     glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT, &timestamp);
105     glDeleteQueries(1, &query);
106
107     return timestamp;
108 }
109
110 static void
111 completeCallQuery(CallQuery& query) {
112     /* Get call start and duration */
113     GLuint64 timestamp = 0, duration = 0, samples = 0;
114     glGetQueryObjectui64vEXT(query.ids[0], GL_QUERY_RESULT, &timestamp);
115     glGetQueryObjectui64vEXT(query.ids[1], GL_QUERY_RESULT, &duration);
116     glGetQueryObjectui64vEXT(query.ids[2], GL_QUERY_RESULT, &samples);
117     glDeleteQueries(3, query.ids);
118
119     /* Add call to profile */
120     retrace::profiler.addCall(query.call, query.sig->name, timestamp, duration, samples);
121 }
122
123 void
124 flushQueries() {
125     for (std::list<CallQuery>::iterator itr = callQueries.begin(); itr != callQueries.end(); ++itr) {
126         completeCallQuery(*itr);
127     }
128
129     callQueries.clear();
130 }
131
132 void
133 beginProfileGPU(trace::Call &call) {
134     if (firstFrame) {
135         frame_start();
136     }
137
138     /* Ensure we don't have TOO many queries waiting for results */
139     if (callQueries.size() >= maxActiveCallQueries) {
140         completeCallQuery(callQueries.front());
141         callQueries.pop_front();
142     }
143
144     /* Create call query */
145     CallQuery query;
146     query.call = call.no;
147     query.sig = call.sig;
148
149     glGenQueries(3, query.ids);
150     glQueryCounter(query.ids[0], GL_TIMESTAMP);
151     glBeginQuery(GL_TIME_ELAPSED, query.ids[1]);
152     glBeginQuery(GL_SAMPLES_PASSED, query.ids[2]);
153
154     callQueries.push_back(query);
155 }
156
157 void
158 endProfileGPU(trace::Call &call) {
159     glEndQuery(GL_TIME_ELAPSED);
160     glEndQuery(GL_SAMPLES_PASSED);
161 }
162
163 void
164 frame_start() {
165     firstFrame = false;
166
167     if (retrace::profileGPU) {
168         retrace::profiler.addFrameStart(retrace::frameNo, getTimestamp());
169     }
170 }
171
172 void
173 frame_complete(trace::Call &call) {
174     if (retrace::profileGPU) {
175         /* Complete any remaining queries */
176         flushQueries();
177
178         /* Indicate end of current frame */
179         retrace::profiler.addFrameEnd(getTimestamp());
180     }
181
182     retrace::frameComplete(call);
183
184     /* Indicate start of next frame */
185     frame_start();
186
187     if (!currentDrawable) {
188         return;
189     }
190
191     if (retrace::debug && !currentDrawable->visible) {
192         retrace::warning(call) << "could not infer drawable size (glViewport never called)\n";
193     }
194 }
195
196 } /* namespace glretrace */
197
198
199 void
200 retrace::setUp(void) {
201     glws::init();
202 }
203
204
205 void
206 retrace::addCallbacks(retrace::Retracer &retracer)
207 {
208     retracer.addCallbacks(glretrace::gl_callbacks);
209     retracer.addCallbacks(glretrace::glx_callbacks);
210     retracer.addCallbacks(glretrace::wgl_callbacks);
211     retracer.addCallbacks(glretrace::cgl_callbacks);
212     retracer.addCallbacks(glretrace::egl_callbacks);
213 }
214
215
216 image::Image *
217 retrace::getSnapshot(void) {
218     if (!glretrace::currentDrawable) {
219         return NULL;
220     }
221
222     return glstate::getDrawBufferImage();
223 }
224
225
226 bool
227 retrace::dumpState(std::ostream &os)
228 {
229     if (glretrace::insideGlBeginEnd ||
230         !glretrace::currentDrawable ||
231         !glretrace::currentContext) {
232         return false;
233     }
234
235     glstate::dumpCurrentContext(os);
236
237     return true;
238 }
239
240 void
241 retrace::flushRendering(void) {
242     glretrace::flushQueries();
243     glFlush();
244 }
245
246 void
247 retrace::waitForInput(void) {
248     while (glws::processEvents()) {
249     }
250 }
251
252 void
253 retrace::cleanUp(void) {
254     glws::cleanup();
255 }