Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / gl / gpu_timing.cc
blobee9049093471973237c85fada92bd5f66300fca4
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gl/gpu_timing.h"
7 #include "base/time/time.h"
8 #include "ui/gl/gl_bindings.h"
9 #include "ui/gl/gl_context.h"
10 #include "ui/gl/gl_version_info.h"
12 namespace gfx {
14 GPUTiming::GPUTiming(GLContextReal* context) {
15 DCHECK(context);
16 const GLVersionInfo* version_info = context->GetVersionInfo();
17 DCHECK(version_info);
18 if (version_info->is_es3 && // glGetInteger64v is supported under ES3.
19 context->HasExtension("GL_EXT_disjoint_timer_query")) {
20 timer_type_ = kTimerTypeDisjoint;
21 } else if (context->HasExtension("GL_ARB_timer_query")) {
22 timer_type_ = kTimerTypeARB;
23 } else if (context->HasExtension("GL_EXT_timer_query")) {
24 timer_type_ = kTimerTypeEXT;
28 GPUTiming::~GPUTiming() {
31 scoped_refptr<GPUTimingClient> GPUTiming::CreateGPUTimingClient() {
32 return new GPUTimingClient(this);
35 uint32_t GPUTiming::GetDisjointCount() {
36 if (timer_type_ == kTimerTypeDisjoint) {
37 GLint disjoint_value = 0;
38 glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
39 if (disjoint_value) {
40 disjoint_counter_++;
43 return disjoint_counter_;
46 GPUTimer::~GPUTimer() {
47 // Destroy() must be called before the destructor.
48 DCHECK(queries_[0] == 0);
49 DCHECK(queries_[1] == 0);
52 void GPUTimer::Destroy(bool have_context) {
53 if (have_context) {
54 glDeleteQueries(2, queries_);
56 memset(queries_, 0, sizeof(queries_));
59 void GPUTimer::Start() {
60 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
61 case GPUTiming::kTimerTypeARB:
62 case GPUTiming::kTimerTypeDisjoint:
63 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
64 glQueryCounter(queries_[0], GL_TIMESTAMP);
65 break;
66 case GPUTiming::kTimerTypeEXT:
67 glBeginQuery(GL_TIME_ELAPSED_EXT, queries_[0]);
68 break;
69 default:
70 NOTREACHED();
74 void GPUTimer::End() {
75 end_requested_ = true;
76 DCHECK(gpu_timing_client_->gpu_timing_);
77 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
78 case GPUTiming::kTimerTypeARB:
79 case GPUTiming::kTimerTypeDisjoint:
80 offset_ = gpu_timing_client_->CalculateTimerOffset();
81 glQueryCounter(queries_[1], GL_TIMESTAMP);
82 break;
83 case GPUTiming::kTimerTypeEXT:
84 glEndQuery(GL_TIME_ELAPSED_EXT);
85 break;
86 default:
87 NOTREACHED();
91 bool GPUTimer::IsAvailable() {
92 if (!gpu_timing_client_->IsAvailable() || !end_requested_) {
93 return false;
95 GLint done = 0;
96 glGetQueryObjectiv(queries_[1] ? queries_[1] : queries_[0],
97 GL_QUERY_RESULT_AVAILABLE, &done);
98 return done != 0;
101 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) {
102 DCHECK(start && end);
103 DCHECK(IsAvailable());
104 DCHECK(gpu_timing_client_->gpu_timing_);
105 DCHECK(gpu_timing_client_->gpu_timing_->timer_type_ !=
106 GPUTiming::kTimerTypeEXT);
107 GLuint64 begin_stamp = 0;
108 GLuint64 end_stamp = 0;
109 // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
110 // We need to detect if the end is less then the start and correct for the
111 // wrapping.
112 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
113 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);
115 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
116 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
119 int64 GPUTimer::GetDeltaElapsed() {
120 DCHECK(gpu_timing_client_->gpu_timing_);
121 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
122 case GPUTiming::kTimerTypeARB:
123 case GPUTiming::kTimerTypeDisjoint: {
124 int64 start = 0;
125 int64 end = 0;
126 GetStartEndTimestamps(&start, &end);
127 return end - start;
128 } break;
129 case GPUTiming::kTimerTypeEXT: {
130 GLuint64 delta = 0;
131 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &delta);
132 return static_cast<int64>(delta / base::Time::kNanosecondsPerMicrosecond);
133 } break;
134 default:
135 NOTREACHED();
137 return 0;
140 GPUTimer::GPUTimer(scoped_refptr<GPUTimingClient> gpu_timing_client)
141 : gpu_timing_client_(gpu_timing_client) {
142 DCHECK(gpu_timing_client_);
143 memset(queries_, 0, sizeof(queries_));
144 int queries = 0;
145 DCHECK(gpu_timing_client_->gpu_timing_);
146 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
147 case GPUTiming::kTimerTypeARB:
148 case GPUTiming::kTimerTypeDisjoint:
149 queries = 2;
150 break;
151 case GPUTiming::kTimerTypeEXT:
152 queries = 1;
153 break;
154 default:
155 NOTREACHED();
157 glGenQueries(queries, queries_);
160 GPUTimingClient::GPUTimingClient(GPUTiming* gpu_timing)
161 : gpu_timing_(gpu_timing) {
162 if (gpu_timing) {
163 timer_type_ = gpu_timing->GetTimerType();
164 disjoint_counter_ = gpu_timing_->GetDisjointCount();
168 scoped_ptr<GPUTimer> GPUTimingClient::CreateGPUTimer() {
169 return make_scoped_ptr(new GPUTimer(this));
172 bool GPUTimingClient::IsAvailable() {
173 return timer_type_ != GPUTiming::kTimerTypeInvalid;
176 bool GPUTimingClient::IsTimerOffsetAvailable() {
177 return timer_type_ == GPUTiming::kTimerTypeARB ||
178 timer_type_ == GPUTiming::kTimerTypeDisjoint;
181 const char* GPUTimingClient::GetTimerTypeName() const {
182 switch (timer_type_) {
183 case GPUTiming::kTimerTypeDisjoint:
184 return "GL_EXT_disjoint_timer_query";
185 case GPUTiming::kTimerTypeARB:
186 return "GL_ARB_timer_query";
187 case GPUTiming::kTimerTypeEXT:
188 return "GL_EXT_timer_query";
189 default:
190 return "Unknown";
194 bool GPUTimingClient::CheckAndResetTimerErrors() {
195 if (timer_type_ == GPUTiming::kTimerTypeDisjoint) {
196 DCHECK(gpu_timing_ != nullptr);
197 const uint32_t total_disjoint_count = gpu_timing_->GetDisjointCount();
198 const bool disjoint_triggered = total_disjoint_count != disjoint_counter_;
199 disjoint_counter_ = total_disjoint_count;
200 return disjoint_triggered;
202 return false;
205 int64 GPUTimingClient::CalculateTimerOffset() {
206 DCHECK(IsTimerOffsetAvailable());
207 if (!offset_valid_) {
208 GLint64 gl_now = 0;
209 glGetInteger64v(GL_TIMESTAMP, &gl_now);
210 int64 now =
211 cpu_time_for_testing_.is_null()
212 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue()
213 : cpu_time_for_testing_.Run();
214 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond;
215 offset_valid_ = timer_type_ == GPUTiming::kTimerTypeARB;
217 return offset_;
220 void GPUTimingClient::InvalidateTimerOffset() {
221 offset_valid_ = false;
224 void GPUTimingClient::SetCpuTimeForTesting(
225 const base::Callback<int64(void)>& cpu_time) {
226 cpu_time_for_testing_ = cpu_time;
229 GPUTimingClient::~GPUTimingClient() {
232 } // namespace gfx