summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/ContextStateTracker.cpp
blob: e3659e5fc3df3de75e2624e9c97c3c596620c491 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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