/* -*- 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" 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); 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