int main(int argc, char **argv) { using namespace retrace; int i; assert(snapshotFrequency.empty()); int opt; while ((opt = getopt_long_only(argc, argv, shortOptions, longOptions, NULL)) != -1) { switch (opt) { case 'h': usage(argv[0]); return 0; case 'b': retrace::debug = false; retrace::verbosity = -1; break; case CALL_NOS_OPT: useCallNos = trace::boolOption(optarg); break; case 'D': dumpStateCallNo = atoi(optarg); dumpingState = true; retrace::verbosity = -2; break; case CORE_OPT: retrace::setFeatureLevel("3_2_core"); break; case DB_OPT: retrace::doubleBuffer = true; break; case DRIVER_OPT: if (strcasecmp(optarg, "hw") == 0) { driver = DRIVER_HARDWARE; } else if (strcasecmp(optarg, "sw") == 0) { driver = DRIVER_SOFTWARE; } else if (strcasecmp(optarg, "ref") == 0) { driver = DRIVER_REFERENCE; } else if (strcasecmp(optarg, "null") == 0) { driver = DRIVER_NULL; } else { driver = DRIVER_MODULE; driverModule = optarg; } break; case SB_OPT: retrace::doubleBuffer = false; break; case SINGLETHREAD_OPT: retrace::singleThread = true; break; case 's': snapshotPrefix = optarg; if (snapshotFrequency.empty()) { snapshotFrequency = trace::CallSet(trace::FREQUENCY_FRAME); } if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) { os::setBinaryMode(stdout); retrace::verbosity = -2; } else { /* * Create the snapshot directory if it does not exist. * * We can't just use trimFilename() because when applied to * "/foo/boo/" it would merely return "/foo". * * XXX: create nested directories. */ os::String prefix(snapshotPrefix); os::String::iterator sep = prefix.rfindSep(false); if (sep != prefix.end()) { prefix.erase(sep, prefix.end()); if (!prefix.exists() && !os::createDirectory(prefix)) { std::cerr << "error: failed to create `" << prefix.str() << "` directory\n"; } } } break; case SNAPSHOT_FORMAT_OPT: if (strcmp(optarg, "RGB") == 0) snapshotFormat = RAW_RGB; else snapshotFormat = PNM_FMT; break; case 'S': snapshotFrequency.merge(optarg); if (snapshotPrefix == NULL) { snapshotPrefix = ""; } break; case 'v': ++retrace::verbosity; break; case 'w': waitOnFinish = true; break; case LOOP_OPT: loopOnFinish = true; break; case PGPU_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingGpuTimes = true; break; case PCPU_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingCpuTimes = true; break; case PPD_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingPixelsDrawn = true; break; case PMEM_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingMemoryUsage = true; break; default: std::cerr << "error: unknown option " << opt << "\n"; usage(argv[0]); return 1; } } #ifndef _WIN32 if (!isatty(STDOUT_FILENO)) { dumpFlags |= trace::DUMP_FLAG_NO_COLOR; } #endif retrace::setUp(); if (retrace::profiling) { retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn, retrace::profilingMemoryUsage); } os::setExceptionCallback(exceptionCallback); for (i = optind; i < argc; ++i) { if (!retrace::parser.open(argv[i])) { return 1; } retrace::mainLoop(); retrace::parser.close(); } os::resetExceptionCallback(); // XXX: X often hangs on XCloseDisplay //retrace::cleanUp(); return 0; }
int main(int argc, char **argv) { using namespace retrace; int loopCount = 0; int i; bool snapshotThreaded = false; os::setDebugOutput(os::OUTPUT_STDERR); assert(snapshotFrequency.empty()); int opt; while ((opt = getopt_long_only(argc, argv, shortOptions, longOptions, NULL)) != -1) { switch (opt) { case 'h': usage(argv[0]); return 0; case 'b': retrace::debug = 0; retrace::verbosity = -1; break; case MARKERS_OPT: retrace::markers = true; break; case 'd': ++retrace::debug; break; case CALL_NOS_OPT: useCallNos = trace::boolOption(optarg); break; case 'D': dumpStateCallNo = atoi(optarg); dumpingState = true; retrace::verbosity = -2; break; case DUMP_FORMAT_OPT: if (strcasecmp(optarg, "json") == 0) { stateWriterFactory = &createJSONStateWriter; } else if (strcasecmp(optarg, "ubjson") == 0) { os::setBinaryMode(stdout); stateWriterFactory = &createUBJSONStateWriter; } else { std::cerr << "error: unsupported dump format `" << optarg << "`\n"; return EXIT_FAILURE; } break; case CORE_OPT: retrace::setFeatureLevel("3_2_core"); break; case DB_OPT: retrace::doubleBuffer = true; break; case SAMPLES_OPT: retrace::samples = atoi(optarg); break; case DRIVER_OPT: if (strcasecmp(optarg, "hw") == 0) { driver = DRIVER_HARDWARE; } else if (strcasecmp(optarg, "sw") == 0) { driver = DRIVER_SOFTWARE; } else if (strcasecmp(optarg, "ref") == 0) { driver = DRIVER_REFERENCE; } else if (strcasecmp(optarg, "null") == 0) { driver = DRIVER_NULL; } else { driver = DRIVER_MODULE; driverModule = optarg; } break; case FULLSCREEN_OPT: retrace::forceWindowed = false; break; case HEADLESS_OPT: ws::headless = true; break; case SB_OPT: retrace::doubleBuffer = false; break; case SINGLETHREAD_OPT: retrace::singleThread = true; break; case 's': dumpingSnapshots = true; snapshotPrefix = optarg; if (snapshotFrequency.empty()) { snapshotFrequency = trace::CallSet(trace::FREQUENCY_FRAME); } if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) { os::setBinaryMode(stdout); retrace::verbosity = -2; } else { /* * Create the snapshot directory if it does not exist. * * We can't just use trimFilename() because when applied to * "/foo/boo/" it would merely return "/foo". * * XXX: create nested directories. */ os::String prefix(snapshotPrefix); os::String::iterator sep = prefix.rfindSep(false); if (sep != prefix.end()) { prefix.erase(sep, prefix.end()); if (!prefix.exists() && !os::createDirectory(prefix)) { std::cerr << "error: failed to create `" << prefix.str() << "` directory\n"; } } } break; case SNAPSHOT_FORMAT_OPT: if (strcmp(optarg, "RGB") == 0) snapshotFormat = RAW_RGB; else if (strcmp(optarg, "MD5") == 0) snapshotFormat = RAW_MD5; else snapshotFormat = PNM_FMT; break; case 'S': dumpingSnapshots = true; snapshotFrequency.merge(optarg); break; case SNAPSHOT_INTERVAL_OPT: snapshotInterval = atoi(optarg); break; case 't': snapshotThreaded = true; break; case 'v': ++retrace::verbosity; break; case 'w': waitOnFinish = true; break; case LOOP_OPT: loopCount = trace::intOption(optarg, -1); break; case PGPU_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingGpuTimes = true; break; case PCPU_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingCpuTimes = true; break; case PPD_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingPixelsDrawn = true; break; case PMEM_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingMemoryUsage = true; break; case PCALLS_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingWithBackends = true; retrace::profilingCallsMetricsString = optarg; break; case PFRAMES_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingWithBackends = true; retrace::profilingFramesMetricsString = optarg; break; case PDRAWCALLS_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingWithBackends = true; retrace::profilingDrawCallsMetricsString = optarg; break; case PLMETRICS_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingWithBackends = true; retrace::profilingListMetrics = true; break; case GENPASS_OPT: retrace::debug = 0; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingWithBackends = true; retrace::profilingNumPasses = true; break; default: std::cerr << "error: unknown option " << opt << "\n"; usage(argv[0]); return 1; } } #ifndef _WIN32 if (!isatty(STDOUT_FILENO)) { dumpFlags |= trace::DUMP_FLAG_NO_COLOR; } #endif #ifdef _WIN32 // Set Windows timer resolution to the minimum period supported by the // system TIMECAPS tc; MMRESULT mmRes = timeGetDevCaps(&tc, sizeof tc); if (mmRes == MMSYSERR_NOERROR) { mmRes = timeBeginPeriod(tc.wPeriodMin); } #endif if (snapshotThreaded) { snapshotter = new ThreadedSnapshotter(os::thread::hardware_concurrency()); } else { snapshotter = new Snapshotter(); } retrace::setUp(); if (retrace::profiling && !retrace::profilingWithBackends) { retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn, retrace::profilingMemoryUsage); } os::setExceptionCallback(exceptionCallback); for (retrace::curPass = 0; retrace::curPass < retrace::numPasses; retrace::curPass++) { for (i = optind; i < argc; ++i) { parser = new trace::Parser; if (loopCount) { parser = lastFrameLoopParser(parser, loopCount); } if (!parser->open(argv[i])) { return 1; } retrace::mainLoop(); parser->close(); delete parser; parser = NULL; } } os::resetExceptionCallback(); delete snapshotter; // XXX: X often hangs on XCloseDisplay //retrace::cleanUp(); #ifdef _WIN32 if (mmRes == MMSYSERR_NOERROR) { timeEndPeriod(tc.wPeriodMin); } #endif return 0; }
namespace glretrace { bool double_buffer = true; bool insideGlBeginEnd = false; trace::Parser parser; glws::Profile defaultProfile = glws::PROFILE_COMPAT; glws::Visual *visual[glws::PROFILE_MAX]; glws::Drawable *drawable = NULL; glws::Context *context = NULL; unsigned frame = 0; long long startTime = 0; bool wait = false; bool benchmark = false; static const char *compare_prefix = NULL; static const char *snapshot_prefix = NULL; static trace::CallSet snapshot_frequency; static trace::CallSet compare_frequency; unsigned dump_state = ~0; 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"; } /** * Grow the current drawble. * * We need to infer the drawable size from GL calls because the drawable sizes * are specified by OS specific calls which we do not trace. */ void updateDrawable(int width, int height) { if (!drawable) { return; } if (drawable->visible && width <= drawable->width && height <= drawable->height) { return; } // Ignore zero area viewports if (width == 0 || height == 0) { return; } // Check for bound framebuffer last, as this may have a performance impact. GLint draw_framebuffer = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer); if (draw_framebuffer != 0) { return; } drawable->resize(width, height); drawable->show(); glScissor(0, 0, width, height); } static void snapshot(unsigned call_no) { assert(snapshot_prefix || compare_prefix); if (!drawable) { return; } image::Image *ref = NULL; if (compare_prefix) { os::String filename = os::String::format("%s%010u.png", compare_prefix, call_no); ref = image::readPNG(filename); if (!ref) { return; } if (retrace::verbosity >= 0) { std::cout << "Read " << filename << "\n"; } } image::Image *src = glstate::getDrawBufferImage(); if (!src) { return; } if (snapshot_prefix) { if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) { char comment[21]; snprintf(comment, sizeof comment, "%u", call_no); src->writePNM(std::cout, comment); } else { os::String filename = os::String::format("%s%010u.png", snapshot_prefix, call_no); if (src->writePNG(filename) && retrace::verbosity >= 0) { std::cout << "Wrote " << filename << "\n"; } } } if (ref) { std::cout << "Snapshot " << call_no << " average precision of " << src->compare(*ref) << " bits\n"; delete ref; } delete src; } void frame_complete(trace::Call &call) { ++frame; if (!drawable) { return; } if (!drawable->visible) { retrace::warning(call) << "could not infer drawable size (glViewport never called)\n"; } } static void display(void) { retrace::Retracer retracer; retracer.addCallbacks(gl_callbacks); retracer.addCallbacks(glx_callbacks); retracer.addCallbacks(wgl_callbacks); retracer.addCallbacks(cgl_callbacks); retracer.addCallbacks(egl_callbacks); startTime = os::getTime(); trace::Call *call; while ((call = parser.parse_call())) { bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET; bool doSnapshot = snapshot_frequency.contains(*call) || compare_frequency.contains(*call) ; // For calls which cause rendertargets to be swaped, we take the // snapshot _before_ swapping the rendertargets. if (doSnapshot && swapRenderTarget) { if (call->flags & trace::CALL_FLAG_END_FRAME) { // For swapbuffers/presents we still use this call number, // spite not have been executed yet. snapshot(call->no); } else { // Whereas for ordinate fbo/rendertarget changes we use the // previous call's number. snapshot(call->no - 1); } } retracer.retrace(*call); if (doSnapshot && !swapRenderTarget) { snapshot(call->no); } 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.0 / os::timeFrequency); if ((retrace::verbosity >= -1) || (retrace::profiling)) { std::cout << "Rendered " << frame << " frames" " in " << timeInterval << " secs," " average of " << (frame/timeInterval) << " fps\n"; } if (wait) { while (glws::processEvents()) {} } else { exit(0); } } static void usage(void) { std::cout << "Usage: glretrace [OPTION] TRACE\n" "Replay TRACE.\n" "\n" " -b benchmark mode (no error checking or warning messages)\n" " -p profiling mode (run whole trace, dump profiling info)\n" " -c PREFIX compare against snapshots\n" " -C CALLSET calls to compare (default is every frame)\n" " -core use core profile\n" " -db use a double buffer visual (default)\n" " -sb use a single buffer visual\n" " -s PREFIX take snapshots; `-` for PNM stdout output\n" " -S CALLSET calls to snapshot (default is every frame)\n" " -v increase output verbosity\n" " -D CALLNO dump state at specific call no\n" " -w wait on final frame\n"; } extern "C" int main(int argc, char **argv) { assert(compare_frequency.empty()); assert(snapshot_frequency.empty()); int i; for (i = 1; i < argc; ++i) { const char *arg = argv[i]; if (arg[0] != '-') { break; } if (!strcmp(arg, "--")) { break; } else if (!strcmp(arg, "-b")) { benchmark = true; retrace::verbosity = -1; glws::debug = false; } else if (!strcmp(arg, "-p")) { retrace::profiling = true; retrace::verbosity = -1; glws::debug = false; } else if (!strcmp(arg, "-c")) { compare_prefix = argv[++i]; if (compare_frequency.empty()) { compare_frequency = trace::CallSet(trace::FREQUENCY_FRAME); } } else if (!strcmp(arg, "-C")) { compare_frequency = trace::CallSet(argv[++i]); if (compare_prefix == NULL) { compare_prefix = ""; } } else if (!strcmp(arg, "-D")) { dump_state = atoi(argv[++i]); retrace::verbosity = -2; } else if (!strcmp(arg, "-core")) { defaultProfile = glws::PROFILE_CORE; } else if (!strcmp(arg, "-db")) { double_buffer = true; } else if (!strcmp(arg, "-sb")) { double_buffer = false; } else if (!strcmp(arg, "--help")) { usage(); return 0; } else if (!strcmp(arg, "-s")) { snapshot_prefix = argv[++i]; if (snapshot_frequency.empty()) { snapshot_frequency = trace::CallSet(trace::FREQUENCY_FRAME); } if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) { os::setBinaryMode(stdout); retrace::verbosity = -2; } } else if (!strcmp(arg, "-S")) { snapshot_frequency = trace::CallSet(argv[++i]); if (snapshot_prefix == NULL) { snapshot_prefix = ""; } } else if (!strcmp(arg, "-v")) { ++retrace::verbosity; } else if (!strcmp(arg, "-w")) { wait = true; } else { std::cerr << "error: unknown option " << arg << "\n"; usage(); return 1; } } glws::init(); visual[glws::PROFILE_COMPAT] = glws::createVisual(double_buffer, glws::PROFILE_COMPAT); visual[glws::PROFILE_CORE] = glws::createVisual(double_buffer, glws::PROFILE_CORE); visual[glws::PROFILE_ES1] = glws::createVisual(double_buffer, glws::PROFILE_ES1); visual[glws::PROFILE_ES2] = glws::createVisual(double_buffer, glws::PROFILE_ES2); for ( ; i < argc; ++i) { if (!parser.open(argv[i])) { std::cerr << "error: failed to open " << argv[i] << "\n"; return 1; } display(); parser.close(); } for (int n = 0; n < glws::PROFILE_MAX; n++) { delete visual[n]; } glws::cleanup(); return 0; } } /* namespace glretrace */
int main(int argc, char **argv) { assert(compare_frequency.empty()); assert(snapshot_frequency.empty()); int i; for (i = 1; i < argc; ++i) { const char *arg = argv[i]; if (arg[0] != '-') { break; } if (!strcmp(arg, "--")) { break; } else if (!strcmp(arg, "-b")) { benchmark = true; retrace::verbosity = -1; glws::debug = false; } else if (!strcmp(arg, "-p")) { retrace::profiling = true; retrace::verbosity = -1; glws::debug = false; } else if (!strcmp(arg, "-c")) { compare_prefix = argv[++i]; if (compare_frequency.empty()) { compare_frequency = trace::CallSet(trace::FREQUENCY_FRAME); } } else if (!strcmp(arg, "-C")) { compare_frequency = trace::CallSet(argv[++i]); if (compare_prefix == NULL) { compare_prefix = ""; } } else if (!strcmp(arg, "-D")) { dump_state = atoi(argv[++i]); retrace::verbosity = -2; } else if (!strcmp(arg, "-core")) { defaultProfile = glws::PROFILE_CORE; } else if (!strcmp(arg, "-db")) { double_buffer = true; } else if (!strcmp(arg, "-sb")) { double_buffer = false; } else if (!strcmp(arg, "--help")) { usage(); return 0; } else if (!strcmp(arg, "-s")) { snapshot_prefix = argv[++i]; if (snapshot_frequency.empty()) { snapshot_frequency = trace::CallSet(trace::FREQUENCY_FRAME); } if (snapshot_prefix[0] == '-' && snapshot_prefix[1] == 0) { os::setBinaryMode(stdout); retrace::verbosity = -2; } } else if (!strcmp(arg, "-S")) { snapshot_frequency = trace::CallSet(argv[++i]); if (snapshot_prefix == NULL) { snapshot_prefix = ""; } } else if (!strcmp(arg, "-v")) { ++retrace::verbosity; } else if (!strcmp(arg, "-w")) { wait = true; } else { std::cerr << "error: unknown option " << arg << "\n"; usage(); return 1; } } glws::init(); visual[glws::PROFILE_COMPAT] = glws::createVisual(double_buffer, glws::PROFILE_COMPAT); visual[glws::PROFILE_CORE] = glws::createVisual(double_buffer, glws::PROFILE_CORE); visual[glws::PROFILE_ES1] = glws::createVisual(double_buffer, glws::PROFILE_ES1); visual[glws::PROFILE_ES2] = glws::createVisual(double_buffer, glws::PROFILE_ES2); for ( ; i < argc; ++i) { if (!parser.open(argv[i])) { std::cerr << "error: failed to open " << argv[i] << "\n"; return 1; } display(); parser.close(); } for (int n = 0; n < glws::PROFILE_MAX; n++) { delete visual[n]; } glws::cleanup(); return 0; }
static void display(void) { retrace::Retracer retracer; retracer.addCallbacks(gl_callbacks); retracer.addCallbacks(glx_callbacks); retracer.addCallbacks(wgl_callbacks); retracer.addCallbacks(cgl_callbacks); retracer.addCallbacks(egl_callbacks); startTime = os::getTime(); trace::Call *call; while ((call = parser.parse_call())) { bool swapRenderTarget = call->flags & trace::CALL_FLAG_SWAP_RENDERTARGET; bool doSnapshot = snapshot_frequency.contains(*call) || compare_frequency.contains(*call) ; // For calls which cause rendertargets to be swaped, we take the // snapshot _before_ swapping the rendertargets. if (doSnapshot && swapRenderTarget) { if (call->flags & trace::CALL_FLAG_END_FRAME) { // For swapbuffers/presents we still use this call number, // spite not have been executed yet. snapshot(call->no); } else { // Whereas for ordinate fbo/rendertarget changes we use the // previous call's number. snapshot(call->no - 1); } } retracer.retrace(*call); if (doSnapshot && !swapRenderTarget) { snapshot(call->no); } 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.0 / os::timeFrequency); if ((retrace::verbosity >= -1) || (retrace::profiling)) { std::cout << "Rendered " << frame << " frames" " in " << timeInterval << " secs," " average of " << (frame/timeInterval) << " fps\n"; } if (wait) { while (glws::processEvents()) {} } else { exit(0); } }
int main(int argc, char **argv) { using namespace retrace; int i; assert(compareFrequency.empty()); assert(snapshotFrequency.empty()); int opt; while ((opt = getopt_long_only(argc, argv, shortOptions, longOptions, NULL)) != -1) { switch (opt) { case 'h': usage(argv[0]); return 0; case 'b': retrace::debug = false; retrace::verbosity = -1; break; case CALL_NOS_OPT: useCallNos = trace::boolOption(optarg); break; case 'c': comparePrefix = optarg; if (compareFrequency.empty()) { compareFrequency = trace::CallSet(trace::FREQUENCY_FRAME); } break; case 'C': compareFrequency = trace::CallSet(optarg); if (comparePrefix == NULL) { comparePrefix = ""; } break; case 'D': dumpStateCallNo = atoi(optarg); dumpingState = true; retrace::verbosity = -2; break; case CORE_OPT: retrace::coreProfile = true; break; case DB_OPT: retrace::doubleBuffer = true; break; case DRIVER_OPT: if (strcasecmp(optarg, "hw") == 0) { driver = DRIVER_HARDWARE; } else if (strcasecmp(optarg, "sw") == 0) { driver = DRIVER_SOFTWARE; } else if (strcasecmp(optarg, "ref") == 0) { driver = DRIVER_REFERENCE; } else if (strcasecmp(optarg, "null") == 0) { driver = DRIVER_NULL; } else { driver = DRIVER_MODULE; driverModule = optarg; } break; case SB_OPT: retrace::doubleBuffer = false; break; case SINGLETHREAD_OPT: retrace::singleThread = true; break; case 's': snapshotPrefix = optarg; if (snapshotFrequency.empty()) { snapshotFrequency = trace::CallSet(trace::FREQUENCY_FRAME); } if (snapshotPrefix[0] == '-' && snapshotPrefix[1] == 0) { os::setBinaryMode(stdout); retrace::verbosity = -2; } break; case SNAPSHOT_FORMAT_OPT: if (strcmp(optarg, "RGB") == 0) snapshotFormat = RAW_RGB; else snapshotFormat = PNM_FMT; break; case 'S': snapshotFrequency = trace::CallSet(optarg); if (snapshotPrefix == NULL) { snapshotPrefix = ""; } break; case 'v': ++retrace::verbosity; break; case 'w': waitOnFinish = true; break; case LOOP_OPT: loopOnFinish = true; break; case PGPU_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingGpuTimes = true; break; case PCPU_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingCpuTimes = true; break; case PPD_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingPixelsDrawn = true; break; case PMEM_OPT: retrace::debug = false; retrace::profiling = true; retrace::verbosity = -1; retrace::profilingMemoryUsage = true; break; default: std::cerr << "error: unknown option " << opt << "\n"; usage(argv[0]); return 1; } } retrace::setUp(); if (retrace::profiling) { retrace::profiler.setup(retrace::profilingCpuTimes, retrace::profilingGpuTimes, retrace::profilingPixelsDrawn, retrace::profilingMemoryUsage); } os::setExceptionCallback(exceptionCallback); for (i = optind; i < argc; ++i) { if (!retrace::parser.open(argv[i])) { return 1; } retrace::mainLoop(); retrace::parser.close(); } os::resetExceptionCallback(); // XXX: X often hangs on XCloseDisplay //retrace::cleanUp(); return 0; }