diff options
Diffstat (limited to 'gfx/thebes/ContextStateTracker.cpp')
-rw-r--r-- | gfx/thebes/ContextStateTracker.cpp | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/gfx/thebes/ContextStateTracker.cpp b/gfx/thebes/ContextStateTracker.cpp new file mode 100644 index 000000000..e3659e5fc --- /dev/null +++ b/gfx/thebes/ContextStateTracker.cpp @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ContextStateTracker.h" +#include "GLContext.h" +#ifdef MOZ_ENABLE_PROFILER_SPS +#include "ProfilerMarkers.h" +#endif + +namespace mozilla { + +void +ContextStateTrackerOGL::PushOGLSection(GLContext* aGL, const char* aSectionName) +{ + if (!profiler_feature_active("gpu")) { + return; + } + + if (!aGL->IsSupported(gl::GLFeature::query_objects)) { + return; + } + + if (mSectionStack.Length() > 0) { + // We need to end the query since we're starting a new section and restore it + // when this section is finished. + aGL->fEndQuery(LOCAL_GL_TIME_ELAPSED); + Top().mCpuTimeEnd = TimeStamp::Now(); + } + + ContextState newSection(aSectionName); + + GLuint queryObject; + aGL->fGenQueries(1, &queryObject); + newSection.mStartQueryHandle = queryObject; + newSection.mCpuTimeStart = TimeStamp::Now(); + + aGL->fBeginQuery(LOCAL_GL_TIME_ELAPSED_EXT, queryObject); + + mSectionStack.AppendElement(newSection); +} + +void +ContextStateTrackerOGL::PopOGLSection(GLContext* aGL, const char* aSectionName) +{ + // We might have ignored a section start if we started profiling + // in the middle section. If so we will ignore this unmatched end. + if (mSectionStack.Length() == 0) { + return; + } + + int i = mSectionStack.Length() - 1; + MOZ_ASSERT(strcmp(mSectionStack[i].mSectionName, aSectionName) == 0); + aGL->fEndQuery(LOCAL_GL_TIME_ELAPSED); + mSectionStack[i].mCpuTimeEnd = TimeStamp::Now(); + mCompletedSections.AppendElement(mSectionStack[i]); + mSectionStack.RemoveElementAt(i); + + if (i - 1 >= 0) { + const char* sectionToRestore = Top().mSectionName; + + // We need to restore the outer section + // Well do this by completing this section and adding a new + // one with the same name + mCompletedSections.AppendElement(Top()); + mSectionStack.RemoveElementAt(i - 1); + + ContextState newSection(sectionToRestore); + + GLuint queryObject; + aGL->fGenQueries(1, &queryObject); + newSection.mStartQueryHandle = queryObject; + newSection.mCpuTimeStart = TimeStamp::Now(); + + aGL->fBeginQuery(LOCAL_GL_TIME_ELAPSED_EXT, queryObject); + + mSectionStack.AppendElement(newSection); + } + + Flush(aGL); +} + +void +ContextStateTrackerOGL::Flush(GLContext* aGL) +{ + TimeStamp now = TimeStamp::Now(); + + while (mCompletedSections.Length() != 0) { + // On mac we see QUERY_RESULT_AVAILABLE cause a GL flush if we query it + // too early. For profiling we rather have the last 200ms of data missing + // while causing let's measurement distortions. + if (mCompletedSections[0].mCpuTimeEnd + TimeDuration::FromMilliseconds(200) > now) { + break; + } + + GLuint handle = mCompletedSections[0].mStartQueryHandle; + + // We've waiting 200ms, content rendering at > 20 FPS will be ready. We + // shouldn't see any flushes now. + GLuint returned = 0; + aGL->fGetQueryObjectuiv(handle, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned); + + if (!returned) { + break; + } + + GLuint gpuTime = 0; + aGL->fGetQueryObjectuiv(handle, LOCAL_GL_QUERY_RESULT, &gpuTime); + + aGL->fDeleteQueries(1, &handle); + +#ifdef MOZ_ENABLE_PROFILER_SPS + PROFILER_MARKER_PAYLOAD("gpu_timer_query", new GPUMarkerPayload( + mCompletedSections[0].mCpuTimeStart, + mCompletedSections[0].mCpuTimeEnd, + 0, + gpuTime + )); +#endif + + mCompletedSections.RemoveElementAt(0); + } +} + +void +ContextStateTrackerOGL::DestroyOGL(GLContext* aGL) +{ + while (mCompletedSections.Length() != 0) { + GLuint handle = (GLuint)mCompletedSections[0].mStartQueryHandle; + aGL->fDeleteQueries(1, &handle); + mCompletedSections.RemoveElementAt(0); + } +} + +} // namespace mozilla + |