X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=retrace%2Fglretrace_main.cpp;h=44b278fc9f25a13c3aa8d44a544eae2a58d0e5ed;hb=56ad11c7849c7e6ca0ad66558cb1a99c58d4cd3d;hp=df10f435d618bc1ad018f0842606c7d105f33998;hpb=a278de44521ac40e145953687cafdee9b6a56af7;p=apitrace diff --git a/retrace/glretrace_main.cpp b/retrace/glretrace_main.cpp index df10f43..44b278f 100755 --- a/retrace/glretrace_main.cpp +++ b/retrace/glretrace_main.cpp @@ -47,17 +47,18 @@ struct CallQuery { GLuint ids[3]; unsigned call; + bool isDraw; GLuint program; const trace::FunctionSig *sig; - uint64_t start; - uint64_t duration; + int64_t cpuStart; + int64_t cpuEnd; }; static bool supportsElapsed = true; static bool supportsTimestamp = true; static bool supportsOcclusion = true; +static bool supportsDebugOutput = true; -static bool firstFrame = true; static std::list callQueries; static void APIENTRY @@ -108,53 +109,58 @@ checkGlError(trace::Call &call) { os << "\n"; } -static GLuint64 -getGpuTimestamp() { - GLuint query = 0; - GLuint64 timestamp = 0; +static void +getCurrentTimes(int64_t& cpuTime, int64_t& gpuTime) { + GLuint query; if (retrace::profilingGpuTimes && supportsTimestamp) { glGenQueries(1, &query); glQueryCounter(query, GL_TIMESTAMP); - glGetQueryObjectui64vEXT(query, GL_QUERY_RESULT, ×tamp); - glDeleteQueries(1, &query); + glGetQueryObjecti64vEXT(query, GL_QUERY_RESULT, &gpuTime); + } else { + gpuTime = 0; } - return timestamp; -} - -static GLuint64 -getCpuTimestamp() { if (retrace::profilingCpuTimes) { - return os::getTime(); + cpuTime = os::getTime(); } else { - return 0; + cpuTime = 0; + } + + if (retrace::profilingGpuTimes && supportsTimestamp) { + glDeleteQueries(1, &query); } } static void completeCallQuery(CallQuery& query) { /* Get call start and duration */ - GLuint64 timestamp = 0, duration = 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, ×tamp); + if (query.isDraw) { + if (retrace::profilingGpuTimes) { + if (supportsTimestamp) { + glGetQueryObjecti64vEXT(query.ids[0], GL_QUERY_RESULT, &gpuStart); + } + + glGetQueryObjecti64vEXT(query.ids[1], GL_QUERY_RESULT, &gpuDuration); } - if (supportsElapsed) { - glGetQueryObjectui64vEXT(query.ids[1], GL_QUERY_RESULT, &duration); + if (retrace::profilingPixelsDrawn) { + glGetQueryObjecti64vEXT(query.ids[2], GL_QUERY_RESULT, &pixels); } - } - if (retrace::profilingPixelsDrawn && supportsOcclusion) { - glGetQueryObjectui64vEXT(query.ids[2], GL_QUERY_RESULT, &samples); + glDeleteQueries(3, query.ids); + } else { + pixels = -1; } - glDeleteQueries(3, query.ids); + if (retrace::profilingCpuTimes) { + cpuDuration = query.cpuEnd - query.cpuStart; + } /* Add call to profile */ - retrace::profiler.addCall(query.call, query.sig->name, query.program, samples, timestamp, duration, query.start, query.duration); + retrace::profiler.addCall(query.call, query.sig->name, query.program, pixels, gpuStart, gpuDuration, query.cpuStart, cpuDuration); } void @@ -167,65 +173,72 @@ flushQueries() { } void -beginProfile(trace::Call &call) { - if (firstFrame) { - frame_start(); - } - +beginProfile(trace::Call &call, bool isDraw) { /* Create call query */ CallQuery query; + query.isDraw = isDraw; query.call = call.no; query.sig = call.sig; query.program = glretrace::currentContext ? glretrace::currentContext->activeProgram : 0; - glGenQueries(3, query.ids); + /* GPU profiling only for draw calls */ + if (isDraw) { + glGenQueries(3, query.ids); - if (retrace::profilingGpuTimes) { - if (supportsTimestamp) { - glQueryCounter(query.ids[0], GL_TIMESTAMP); - } + if (retrace::profilingGpuTimes) { + if (supportsTimestamp) { + glQueryCounter(query.ids[0], GL_TIMESTAMP); + } - if (supportsElapsed) { glBeginQuery(GL_TIME_ELAPSED, query.ids[1]); } - } - if (retrace::profilingPixelsDrawn && supportsOcclusion) { - glBeginQuery(GL_SAMPLES_PASSED, query.ids[2]); + if (retrace::profilingPixelsDrawn) { + glBeginQuery(GL_SAMPLES_PASSED, query.ids[2]); + } } + callQueries.push_back(query); + + /* CPU profiling for all calls */ if (retrace::profilingCpuTimes) { - query.start = os::getTime(); + callQueries.back().cpuStart = os::getTime(); } - - callQueries.push_back(query); } void -endProfile(trace::Call &call) { +endProfile(trace::Call &call, bool isDraw) { + GLint64 time = os::getTime(); + + /* CPU profiling for all calls */ if (retrace::profilingCpuTimes) { CallQuery& query = callQueries.back(); - query.duration = os::getTime() - query.start; + query.cpuEnd = time; } - if (retrace::profilingGpuTimes && supportsElapsed) { - glEndQuery(GL_TIME_ELAPSED); - } + /* GPU profiling only for draw calls */ + if (isDraw) { + if (retrace::profilingGpuTimes) { + glEndQuery(GL_TIME_ELAPSED); + } - if (retrace::profilingPixelsDrawn && supportsOcclusion) { - glEndQuery(GL_SAMPLES_PASSED); + if (retrace::profilingPixelsDrawn) { + glEndQuery(GL_SAMPLES_PASSED); + } } } void initContext() { - /* Check for extension support */ const char* extensions = (const char*)glGetString(GL_EXTENSIONS); - 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); + /* 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); + /* 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; @@ -241,30 +254,30 @@ 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); } - if (retrace::debug) { - bool supportsDebugOutput = glws::checkExtension("GL_ARB_debug_output", extensions); - - if (supportsDebugOutput) { - glDebugMessageCallbackARB(&debugOutputCallback, currentContext); + /* Setup debug message call back */ + if (retrace::debug && supportsDebugOutput) { + glDebugMessageCallbackARB(&debugOutputCallback, currentContext); - if (DEBUG_OUTPUT_SYNCHRONOUS) { - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - } + if (DEBUG_OUTPUT_SYNCHRONOUS) { + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } } -} -void -frame_start() { - firstFrame = false; + /* Sync the gpu and cpu start times */ + if (retrace::profilingCpuTimes || retrace::profilingGpuTimes) { + if (!retrace::profiler.hasBaseTimes()) { + GLint64 gpuTime, cpuTime; - if (retrace::profiling) { - retrace::profiler.addFrameStart(retrace::frameNo, getGpuTimestamp(), getCpuTimestamp()); + getCurrentTimes(cpuTime, gpuTime); + retrace::profiler.setBaseCpuTime(cpuTime); + retrace::profiler.setBaseGpuTime(gpuTime); + } } } @@ -274,15 +287,29 @@ frame_complete(trace::Call &call) { /* Complete any remaining queries */ flushQueries(); + /* GPU time drifts due to being relative times, not absolute and can be + * affected by the gpu switch between processes. + * + * To attempt to compensate we resynchronise on frame end however there is + * still noticeable drift within a single frame which we do not account for. + */ + if (retrace::profilingCpuTimes || retrace::profilingGpuTimes) { + int64_t cpuTime, gpuTime, error; + + getCurrentTimes(cpuTime, gpuTime); + cpuTime = cpuTime - retrace::profiler.getBaseCpuTime(); + gpuTime = gpuTime - retrace::profiler.getBaseGpuTime(); + error = gpuTime - cpuTime; + + retrace::profiler.setBaseGpuTime(retrace::profiler.getBaseGpuTime() + error); + } + /* 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) { return; }