void Retracer::retrace(trace::Call &call) { call_dumped = false; if (verbosity >= 1) { dumpCall(call); } Callback callback = 0; trace::Id id = call.sig->id; if (id >= callbacks.size()) { callbacks.resize(id + 1); callback = 0; } else { callback = callbacks[id]; } if (!callback) { Map::const_iterator it = map.find(call.name()); if (it == map.end()) { callback = &unsupported; } else { callback = it->second; } callbacks[id] = callback; } assert(callback); assert(callbacks[id] == callback); callback(call); }
void checkGlError(trace::Call &call) { GLenum error = glGetError(); while (error != GL_NO_ERROR) { uint64_t errorHash = call.sig->id ^ uint64_t(error) << 32; size_t errorCount = errorCounts[errorHash]++; if (errorCount <= maxWarningCount) { std::ostream & os = retrace::warning(call); os << "glGetError("; os << call.name(); os << ") = "; switch (error) { case GL_INVALID_ENUM: os << "GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: os << "GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: os << "GL_INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: os << "GL_STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: os << "GL_STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: os << "GL_OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: os << "GL_INVALID_FRAMEBUFFER_OPERATION"; break; case GL_TABLE_TOO_LARGE: os << "GL_TABLE_TOO_LARGE"; break; default: os << error; break; } if (errorCount == maxWarningCount) { os << ": too many identical messages; ignoring"; } os << std::endl; } error = glGetError(); } }
static void display(void) { startTime = OS::GetTime(); Trace::Call *call; while ((call = parser.parse_call())) { const char *name = call->name(); if (retrace::verbosity >= 1) { std::cout << *call; std::cout.flush(); } if (name[0] == 'C' && name[1] == 'G' && name[2] == 'L') { glretrace::retrace_call_cgl(*call); } else if (name[0] == 'w' && name[1] == 'g' && name[2] == 'l') { glretrace::retrace_call_wgl(*call); } else if (name[0] == 'g' && name[1] == 'l' && name[2] == 'X') { glretrace::retrace_call_glx(*call); } else { retrace::retrace_call(*call); } if (!insideGlBeginEnd && drawable && context && call->no >= dump_state) { glstate::dumpCurrentContext(std::cout); exit(0); } delete call; } // Reached the end of trace glFlush(); long long endTime = OS::GetTime(); float timeInterval = (endTime - startTime) * 1.0E-6; if (retrace::verbosity >= -1) { std::cout << "Rendered " << frame << " frames" " in " << timeInterval << " secs," " average of " << (frame/timeInterval) << " fps\n"; } if (wait) { while (ws->processEvents()) {} } else { exit(0); } }
void Retracer::retrace(trace::Call &call) { call_dumped = false; if (verbosity >= 1) { if (verbosity >= 2 || !(call.flags & trace::CALL_FLAG_VERBOSE)) { dumpCall(call); } } Callback callback = 0; trace::Id id = call.sig->id; if (id >= callbacks.size()) { callbacks.resize(id + 1); callback = 0; } else { callback = callbacks[id]; } if (!callback) { Map::const_iterator it = map.find(call.name()); if (it == map.end()) { callback = &unsupported; } else { callback = it->second; } callbacks[id] = callback; } assert(callback); assert(callbacks[id] == callback); if (retrace::profiling) { long long startTime = os::getTime(); callback(call); long long stopTime = os::getTime(); float timeInterval = (stopTime - startTime) * (1.0E6 / os::timeFrequency); std::cout << call.no << " " << "[" << timeInterval << " usec] " ; trace::dump(call, std::cout, trace::DUMP_FLAG_NO_CALL_NO | trace::DUMP_FLAG_NO_COLOR); } else { callback(call); } }
void checkGlError(Trace::Call &call) { GLenum error = glGetError(); if (error == GL_NO_ERROR) { return; } if (retrace::verbosity == 0) { std::cout << call; std::cout.flush(); } std::cerr << call.no << ": "; std::cerr << "warning: glGetError("; std::cerr << call.name(); std::cerr << ") = "; switch (error) { case GL_INVALID_ENUM: std::cerr << "GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: std::cerr << "GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: std::cerr << "GL_INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: std::cerr << "GL_STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: std::cerr << "GL_STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: std::cerr << "GL_OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: std::cerr << "GL_INVALID_FRAMEBUFFER_OPERATION"; break; case GL_TABLE_TOO_LARGE: std::cerr << "GL_TABLE_TOO_LARGE"; break; default: std::cerr << error; break; } std::cerr << "\n"; }
void checkGlError(trace::Call &call) { GLenum error = glGetError(); if (error == GL_NO_ERROR) { return; } std::ostream & os = retrace::warning(call); os << "glGetError("; os << call.name(); os << ") = "; switch (error) { case GL_INVALID_ENUM: os << "GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: os << "GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: os << "GL_INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: os << "GL_STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: os << "GL_STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: os << "GL_OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: os << "GL_INVALID_FRAMEBUFFER_OPERATION"; break; case GL_TABLE_TOO_LARGE: os << "GL_TABLE_TOO_LARGE"; break; default: os << error; break; } os << "\n"; }
void calcStatistics(trace::Call &call) { /* Count the total number of calls */ nCalls += 1; /* Count the rendering calls */ if(call.flags & trace::CALL_FLAG_RENDER) nRenderCalls += 1; /* Calculate the uploaded texel size */ const char* funcName = call.name(); if(!strcmp(funcName,"glTexImage2D")) { unsigned width = call.arg(3).toUInt(); unsigned height = call.arg(4).toUInt(); texUploads += width*height; } else if (!strcmp(funcName,"glTexSubImage2D")) { unsigned width = call.arg(4).toUInt(); unsigned height = call.arg(5).toUInt(); texUploads += width*height; } /* Count the number of vertices and triangles */ if(call.flags & trace::CALL_FLAG_RENDER) { // std::cout << funcName << std::endl; const trace::FunctionSig* sig = call.sig; unsigned nargs = sig->num_args; /* See if it has 'count' and/or 'mode' in its arguments */ int midx = -1; int cidx = -1; for(int i=0; i<nargs; i++) { if(!strcmp(sig->arg_names[i], "mode")) { midx = i; } else if(!strcmp(sig->arg_names[i], "count")) { cidx = i; } } if(cidx >= 0) { int count = call.arg(cidx).toSInt(); nVertices += count; if(midx >= 0) { int mode = call.arg(midx).toSInt(); switch(mode) { case GL_POINTS: count = count * 2; break; case GL_LINES: count = count; break; case GL_LINE_LOOP: count = count * 2 + 2; break; case GL_LINE_STRIP: count = count * 2; break; case GL_TRIANGLES: count = count / 3; break; case GL_TRIANGLE_STRIP: count = count - 2; break; case GL_TRIANGLE_FAN: count = count - 2; break; default: break; } nTriangles += count; } } } }
void unsupported(trace::Call &call) { warning(call) << "unsupported " << call.name() << " call\n"; }
static void display(void) { Trace::Call *call; while ((call = parser.parse_call())) { const std::string &name = call->name(); if ((name[0] == 'w' && name[1] == 'g' && name[2] == 'l') || (name[0] == 'g' && name[1] == 'l' && name[2] == 'X')) { // XXX: We ignore the majority of the OS-specific calls for now if (name == "glXSwapBuffers" || name == "wglSwapBuffers") { if (retrace::verbosity >= 1) { std::cout << *call; std::cout.flush(); }; frame_complete(); if (double_buffer) drawable->swapBuffers(); else glFlush(); } else if (name == "glXMakeCurrent" || name == "wglMakeCurrent") { glFlush(); if (!double_buffer) { frame_complete(); } } else { continue; } } if (name == "glFlush") { glFlush(); if (!double_buffer) { frame_complete(); } } retrace::retrace_call(*call); if (!insideGlBeginEnd && call->no >= dump_state) { state_dump(std::cout); exit(0); } delete call; } // Reached the end of trace glFlush(); long long endTime = OS::GetTime(); float timeInterval = (endTime - startTime) * 1.0E-6; if (retrace::verbosity >= -1) { std::cout << "Rendered " << frame << " frames" " in " << timeInterval << " secs," " average of " << (frame/timeInterval) << " fps\n"; } if (wait) { while (ws->processEvents()) {} } else { exit(0); } }