X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=retrace%2Fglretrace_main.cpp;h=f369b33b7316c0f2c7ce7181268ba2c8736bbcaa;hb=48c661ea6c0f2bd9b76a3385cd946b7d07bc9b5f;hp=8bd52762410adbea9f7e7748365fe9af07e39895;hpb=00fa77c21097e9ef28c5091ec9b05691523aa36c;p=apitrace diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp index 8bd5276..f369b33 100755 --- a/retrace/glretrace_main.cpp +++ b/retrace/glretrace_main.cpp @@ -42,15 +42,24 @@ namespace glretrace { bool insideList = false; bool insideGlBeginEnd = false; +bool supportsARBShaderObjects = false; + +enum { + GPU_START = 0, + GPU_DURATION, + OCCLUSION, + NUM_QUERIES, +}; struct CallQuery { - GLuint ids[3]; + GLuint ids[NUM_QUERIES]; unsigned call; + bool isDraw; GLuint program; const trace::FunctionSig *sig; - uint64_t cpuStart; - uint64_t cpuEnd; + int64_t cpuStart; + int64_t cpuEnd; }; static bool supportsElapsed = true; @@ -58,7 +67,6 @@ static bool supportsTimestamp = true; static bool supportsOcclusion = true; static bool supportsDebugOutput = true; -static bool firstFrame = true; static std::list callQueries; static void APIENTRY @@ -67,97 +75,99 @@ debugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsi 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; + while (error != GL_NO_ERROR) { + 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"; + + error = glGetError(); } - os << "\n"; } -static inline GLuint64 -getGpuTimestamp() { - GLuint query = 0; - GLuint64 timestamp = 0; - +static inline int64_t +getCurrentTime(void) { if (retrace::profilingGpuTimes && supportsTimestamp) { - glGenQueries(1, &query); - glQueryCounter(query, GL_TIMESTAMP); - glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT, ×tamp); - glDeleteQueries(1, &query); + /* Get the current GL time without stalling */ + GLint64 timestamp = 0; + glGetInteger64v(GL_TIMESTAMP, ×tamp); + return timestamp; + } else { + return os::getTime(); } - - return timestamp; } -static inline GLuint64 -getCpuTimestamp() { - if (retrace::profilingCpuTimes) { - return os::getTime(); +static inline int64_t +getTimeFrequency(void) { + if (retrace::profilingGpuTimes && supportsTimestamp) { + return 1000000000; } else { - return 0; + return os::timeFrequency; } } static void completeCallQuery(CallQuery& query) { /* Get call start and duration */ - GLuint64 gpuStart = 0, gpuDuration = 0, cpuDuration = 0, samples = 0; + int64_t gpuStart = 0, gpuDuration = 0, cpuDuration = 0, pixels = 0; - if (retrace::profilingGpuTimes) { - if (supportsTimestamp) { - glGetQueryObjectui64vEXT(query.ids[0], GL_QUERY_RESULT, &gpuStart); + if (query.isDraw) { + if (retrace::profilingGpuTimes) { + if (supportsTimestamp) { + glGetQueryObjecti64vEXT(query.ids[GPU_START], GL_QUERY_RESULT, &gpuStart); + } + + glGetQueryObjecti64vEXT(query.ids[GPU_DURATION], GL_QUERY_RESULT, &gpuDuration); } - glGetQueryObjectui64vEXT(query.ids[1], GL_QUERY_RESULT, &gpuDuration); + if (retrace::profilingPixelsDrawn) { + glGetQueryObjecti64vEXT(query.ids[OCCLUSION], GL_QUERY_RESULT, &pixels); + } + + } else { + pixels = -1; } if (retrace::profilingCpuTimes) { cpuDuration = query.cpuEnd - query.cpuStart; } - if (retrace::profilingPixelsDrawn) { - glGetQueryObjectui64vEXT(query.ids[2], GL_QUERY_RESULT, &samples); - } - - glDeleteQueries(3, query.ids); + glDeleteQueries(NUM_QUERIES, query.ids); /* Add call to profile */ - retrace::profiler.addCall(query.call, query.sig->name, query.program, samples, gpuStart, gpuDuration, query.cpuStart, cpuDuration); + retrace::profiler.addCall(query.call, query.sig->name, query.program, pixels, gpuStart, gpuDuration, query.cpuStart, cpuDuration); } void @@ -170,67 +180,76 @@ flushQueries() { } void -beginProfile(trace::Call &call) { - if (firstFrame) { - frame_start(); - } +beginProfile(trace::Call &call, bool isDraw) { + glretrace::Context *currentContext = glretrace::getCurrentContext(); /* Create call query */ CallQuery query; + query.isDraw = isDraw; query.call = call.no; query.sig = call.sig; - query.program = glretrace::currentContext ? glretrace::currentContext->activeProgram : 0; + query.program = currentContext ? currentContext->activeProgram : 0; - glGenQueries(3, query.ids); + glGenQueries(NUM_QUERIES, query.ids); - if (retrace::profilingGpuTimes) { - if (supportsTimestamp) { - glQueryCounter(query.ids[0], GL_TIMESTAMP); + /* GPU profiling only for draw calls */ + if (isDraw) { + if (retrace::profilingGpuTimes) { + if (supportsTimestamp) { + glQueryCounter(query.ids[GPU_START], GL_TIMESTAMP); + } + + glBeginQuery(GL_TIME_ELAPSED, query.ids[GPU_DURATION]); } - glBeginQuery(GL_TIME_ELAPSED, query.ids[1]); + if (retrace::profilingPixelsDrawn) { + glBeginQuery(GL_SAMPLES_PASSED, query.ids[OCCLUSION]); + } } - if (retrace::profilingPixelsDrawn) { - glBeginQuery(GL_SAMPLES_PASSED, query.ids[2]); - } + callQueries.push_back(query); + /* CPU profiling for all calls */ if (retrace::profilingCpuTimes) { - query.cpuStart = getCpuTimestamp(); + CallQuery& query = callQueries.back(); + query.cpuStart = getCurrentTime(); } - - callQueries.push_back(query); } void -endProfile(trace::Call &call) { +endProfile(trace::Call &call, bool isDraw) { + + /* CPU profiling for all calls */ if (retrace::profilingCpuTimes) { CallQuery& query = callQueries.back(); - query.cpuEnd = getCpuTimestamp(); + query.cpuEnd = getCurrentTime(); } - if (retrace::profilingGpuTimes) { - glEndQuery(GL_TIME_ELAPSED); - } + /* GPU profiling only for draw calls */ + if (isDraw) { + if (retrace::profilingGpuTimes) { + glEndQuery(GL_TIME_ELAPSED); + } - if (retrace::profilingPixelsDrawn) { - glEndQuery(GL_SAMPLES_PASSED); + if (retrace::profilingPixelsDrawn) { + glEndQuery(GL_SAMPLES_PASSED); + } } } void initContext() { - GLuint64 gpuTime, cpuTime; - const char* extensions; - - extensions = (const char*)glGetString(GL_EXTENSIONS); + glretrace::Context *currentContext = glretrace::getCurrentContext(); /* Ensure we have adequate extension support */ - supportsTimestamp = glws::checkExtension("GL_ARB_timer_query", extensions); - supportsElapsed = glws::checkExtension("GL_EXT_timer_query", extensions) || supportsTimestamp; - supportsOcclusion = glws::checkExtension("GL_ARB_occlusion_query", extensions); - supportsDebugOutput = glws::checkExtension("GL_ARB_debug_output", extensions); - + assert(currentContext); + supportsTimestamp = currentContext->hasExtension("GL_ARB_timer_query"); + supportsElapsed = currentContext->hasExtension("GL_EXT_timer_query") || supportsTimestamp; + supportsOcclusion = currentContext->hasExtension("GL_ARB_occlusion_query"); + supportsDebugOutput = currentContext->hasExtension("GL_ARB_debug_output"); + supportsARBShaderObjects = currentContext->hasExtension("GL_ARB_shader_objects"); + + /* Check for timer query support */ if (retrace::profilingGpuTimes) { if (!supportsTimestamp && !supportsElapsed) { std::cout << "Error: Cannot run profile, GL_EXT_timer_query extension is not supported." << std::endl; @@ -246,12 +265,15 @@ initContext() { } } + /* Check for occlusion query support */ if (retrace::profilingPixelsDrawn && !supportsOcclusion) { std::cout << "Error: Cannot run profile, GL_ARB_occlusion_query extension is not supported." << std::endl; exit(-1); } + /* Setup debug message call back */ if (retrace::debug && supportsDebugOutput) { + glretrace::Context *currentContext = glretrace::getCurrentContext(); glDebugMessageCallbackARB(&debugOutputCallback, currentContext); if (DEBUG_OUTPUT_SYNCHRONOUS) { @@ -260,17 +282,12 @@ initContext() { } /* Sync the gpu and cpu start times */ - gpuTime = getGpuTimestamp(); - cpuTime = getCpuTimestamp(); - retrace::profiler.setBaseTimes(gpuTime, cpuTime); -} - -void -frame_start() { - firstFrame = false; - - if (retrace::profiling) { - retrace::profiler.addFrameStart(retrace::frameNo, getGpuTimestamp(), getCpuTimestamp()); + if (retrace::profilingCpuTimes || retrace::profilingGpuTimes) { + if (!retrace::profiler.hasBaseTimes()) { + GLint64 currentTime = getCurrentTime(); + retrace::profiler.setBaseCpuTime(currentTime); + retrace::profiler.setBaseGpuTime(currentTime); + } } } @@ -281,19 +298,18 @@ frame_complete(trace::Call &call) { flushQueries(); /* Indicate end of current frame */ - retrace::profiler.addFrameEnd(getGpuTimestamp(), getCpuTimestamp()); + retrace::profiler.addFrameEnd(); } retrace::frameComplete(call); - /* Indicate start of next frame */ - frame_start(); - - if (!currentDrawable) { + glretrace::Context *currentContext = glretrace::getCurrentContext(); + if (!currentContext) { return; } - if (retrace::debug && !currentDrawable->visible) { + assert(currentContext->drawable); + if (retrace::debug && !currentContext->drawable->visible) { retrace::warning(call) << "could not infer drawable size (glViewport never called)\n"; } } @@ -364,9 +380,35 @@ debugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsi } /* namespace glretrace */ +class GLDumper : public retrace::Dumper { +public: + image::Image * + getSnapshot(void) { + if (!glretrace::getCurrentContext()) { + return NULL; + } + return glstate::getDrawBufferImage(); + } + + bool + dumpState(std::ostream &os) { + glretrace::Context *currentContext = glretrace::getCurrentContext(); + if (glretrace::insideGlBeginEnd || + !currentContext) { + return false; + } + glstate::dumpCurrentContext(os); + return true; + } +}; + +static GLDumper glDumper; + + void retrace::setUp(void) { glws::init(); + dumper = &glDumper; } @@ -381,39 +423,19 @@ retrace::addCallbacks(retrace::Retracer &retracer) } -image::Image * -retrace::getSnapshot(void) { - if (!glretrace::currentDrawable) { - return NULL; - } - - return glstate::getDrawBufferImage(); -} - - -bool -retrace::dumpState(std::ostream &os) -{ - if (glretrace::insideGlBeginEnd || - !glretrace::currentDrawable || - !glretrace::currentContext) { - return false; - } - - glstate::dumpCurrentContext(os); - - return true; -} - void retrace::flushRendering(void) { - glretrace::flushQueries(); - glFlush(); + glretrace::Context *currentContext = glretrace::getCurrentContext(); + if (currentContext) { + glretrace::flushQueries(); + glFlush(); + } } void retrace::waitForInput(void) { while (glws::processEvents()) { + os::sleep(100*1000); } }