1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "ContextStateTracker.h"
7 #include "GLContext.h"
8 #ifdef MOZ_ENABLE_PROFILER_SPS
9 #include "ProfilerMarkers.h"
10 #endif
11 
12 namespace mozilla {
13 
14 void
PushOGLSection(GLContext * aGL,const char * aSectionName)15 ContextStateTrackerOGL::PushOGLSection(GLContext* aGL, const char* aSectionName)
16 {
17   if (!profiler_feature_active("gpu")) {
18     return;
19   }
20 
21   if (!aGL->IsSupported(gl::GLFeature::query_objects)) {
22     return;
23   }
24 
25   if (mSectionStack.Length() > 0) {
26     // We need to end the query since we're starting a new section and restore it
27     // when this section is finished.
28     aGL->fEndQuery(LOCAL_GL_TIME_ELAPSED);
29     Top().mCpuTimeEnd = TimeStamp::Now();
30   }
31 
32   ContextState newSection(aSectionName);
33 
34   GLuint queryObject;
35   aGL->fGenQueries(1, &queryObject);
36   newSection.mStartQueryHandle = queryObject;
37   newSection.mCpuTimeStart = TimeStamp::Now();
38 
39   aGL->fBeginQuery(LOCAL_GL_TIME_ELAPSED_EXT, queryObject);
40 
41   mSectionStack.AppendElement(newSection);
42 }
43 
44 void
PopOGLSection(GLContext * aGL,const char * aSectionName)45 ContextStateTrackerOGL::PopOGLSection(GLContext* aGL, const char* aSectionName)
46 {
47   // We might have ignored a section start if we started profiling
48   // in the middle section. If so we will ignore this unmatched end.
49   if (mSectionStack.Length() == 0) {
50     return;
51   }
52 
53   int i = mSectionStack.Length() - 1;
54   MOZ_ASSERT(strcmp(mSectionStack[i].mSectionName, aSectionName) == 0);
55   aGL->fEndQuery(LOCAL_GL_TIME_ELAPSED);
56   mSectionStack[i].mCpuTimeEnd = TimeStamp::Now();
57   mCompletedSections.AppendElement(mSectionStack[i]);
58   mSectionStack.RemoveElementAt(i);
59 
60   if (i - 1 >= 0) {
61     const char* sectionToRestore = Top().mSectionName;
62 
63     // We need to restore the outer section
64     // Well do this by completing this section and adding a new
65     // one with the same name
66     mCompletedSections.AppendElement(Top());
67     mSectionStack.RemoveElementAt(i - 1);
68 
69     ContextState newSection(sectionToRestore);
70 
71     GLuint queryObject;
72     aGL->fGenQueries(1, &queryObject);
73     newSection.mStartQueryHandle = queryObject;
74     newSection.mCpuTimeStart = TimeStamp::Now();
75 
76     aGL->fBeginQuery(LOCAL_GL_TIME_ELAPSED_EXT, queryObject);
77 
78     mSectionStack.AppendElement(newSection);
79   }
80 
81   Flush(aGL);
82 }
83 
84 void
Flush(GLContext * aGL)85 ContextStateTrackerOGL::Flush(GLContext* aGL)
86 {
87   TimeStamp now = TimeStamp::Now();
88 
89   while (mCompletedSections.Length() != 0) {
90     // On mac we see QUERY_RESULT_AVAILABLE cause a GL flush if we query it
91     // too early. For profiling we rather have the last 200ms of data missing
92     // while causing let's measurement distortions.
93     if (mCompletedSections[0].mCpuTimeEnd + TimeDuration::FromMilliseconds(200) > now) {
94       break;
95     }
96 
97     GLuint handle = mCompletedSections[0].mStartQueryHandle;
98 
99     // We've waiting 200ms, content rendering at > 20 FPS will be ready. We
100     // shouldn't see any flushes now.
101     GLuint returned = 0;
102     aGL->fGetQueryObjectuiv(handle, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
103 
104     if (!returned) {
105       break;
106     }
107 
108     GLuint gpuTime = 0;
109     aGL->fGetQueryObjectuiv(handle, LOCAL_GL_QUERY_RESULT, &gpuTime);
110 
111     aGL->fDeleteQueries(1, &handle);
112 
113 #ifdef MOZ_ENABLE_PROFILER_SPS
114     PROFILER_MARKER_PAYLOAD("gpu_timer_query", new GPUMarkerPayload(
115       mCompletedSections[0].mCpuTimeStart,
116       mCompletedSections[0].mCpuTimeEnd,
117       0,
118       gpuTime
119     ));
120 #endif
121 
122     mCompletedSections.RemoveElementAt(0);
123   }
124 }
125 
126 void
DestroyOGL(GLContext * aGL)127 ContextStateTrackerOGL::DestroyOGL(GLContext* aGL)
128 {
129   while (mCompletedSections.Length() != 0) {
130     GLuint handle = (GLuint)mCompletedSections[0].mStartQueryHandle;
131     aGL->fDeleteQueries(1, &handle);
132     mCompletedSections.RemoveElementAt(0);
133   }
134 }
135 
136 } // namespace mozilla
137 
138