Roll src/third_party/WebKit b944946:201fd41 (svn 192400:192407)
[chromium-blink-merge.git] / ui / gl / gpu_timing.cc
bloba84d3f76497bffe19efabfe78a30ecaab3a2f35c
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 glDeleteQueries(2, queries_);
50 void GPUTimer::Start() {
51 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
52 case GPUTiming::kTimerTypeARB:
53 case GPUTiming::kTimerTypeDisjoint:
54 // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
55 glQueryCounter(queries_[0], GL_TIMESTAMP);
56 break;
57 case GPUTiming::kTimerTypeEXT:
58 glBeginQuery(GL_TIME_ELAPSED_EXT, queries_[0]);
59 break;
60 default:
61 NOTREACHED();
65 void GPUTimer::End() {
66 end_requested_ = true;
67 DCHECK(gpu_timing_client_->gpu_timing_);
68 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
69 case GPUTiming::kTimerTypeARB:
70 case GPUTiming::kTimerTypeDisjoint:
71 offset_ = gpu_timing_client_->CalculateTimerOffset();
72 glQueryCounter(queries_[1], GL_TIMESTAMP);
73 break;
74 case GPUTiming::kTimerTypeEXT:
75 glEndQuery(GL_TIME_ELAPSED_EXT);
76 break;
77 default:
78 NOTREACHED();
82 bool GPUTimer::IsAvailable() {
83 if (!gpu_timing_client_->IsAvailable() || !end_requested_) {
84 return false;
86 GLint done = 0;
87 glGetQueryObjectiv(queries_[1] ? queries_[1] : queries_[0],
88 GL_QUERY_RESULT_AVAILABLE, &done);
89 return done != 0;
92 void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) {
93 DCHECK(start && end);
94 DCHECK(IsAvailable());
95 DCHECK(gpu_timing_client_->gpu_timing_);
96 DCHECK(gpu_timing_client_->gpu_timing_->timer_type_ !=
97 GPUTiming::kTimerTypeEXT);
98 GLuint64 begin_stamp = 0;
99 GLuint64 end_stamp = 0;
100 // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
101 // We need to detect if the end is less then the start and correct for the
102 // wrapping.
103 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
104 glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);
106 *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
107 *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
110 int64 GPUTimer::GetDeltaElapsed() {
111 DCHECK(gpu_timing_client_->gpu_timing_);
112 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
113 case GPUTiming::kTimerTypeARB:
114 case GPUTiming::kTimerTypeDisjoint: {
115 int64 start = 0;
116 int64 end = 0;
117 GetStartEndTimestamps(&start, &end);
118 return end - start;
119 } break;
120 case GPUTiming::kTimerTypeEXT: {
121 GLuint64 delta = 0;
122 glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &delta);
123 return static_cast<int64>(delta / base::Time::kNanosecondsPerMicrosecond);
124 } break;
125 default:
126 NOTREACHED();
128 return 0;
131 GPUTimer::GPUTimer(scoped_refptr<GPUTimingClient> gpu_timing_client)
132 : gpu_timing_client_(gpu_timing_client) {
133 DCHECK(gpu_timing_client_);
134 memset(queries_, 0, sizeof(queries_));
135 int queries = 0;
136 DCHECK(gpu_timing_client_->gpu_timing_);
137 switch (gpu_timing_client_->gpu_timing_->timer_type_) {
138 case GPUTiming::kTimerTypeARB:
139 case GPUTiming::kTimerTypeDisjoint:
140 queries = 2;
141 break;
142 case GPUTiming::kTimerTypeEXT:
143 queries = 1;
144 break;
145 default:
146 NOTREACHED();
148 glGenQueries(queries, queries_);
151 GPUTimingClient::GPUTimingClient(GPUTiming* gpu_timing)
152 : gpu_timing_(gpu_timing) {
153 if (gpu_timing) {
154 timer_type_ = gpu_timing->GetTimerType();
155 disjoint_counter_ = gpu_timing_->GetDisjointCount();
159 scoped_ptr<GPUTimer> GPUTimingClient::CreateGPUTimer() {
160 return make_scoped_ptr(new GPUTimer(this));
163 bool GPUTimingClient::IsAvailable() {
164 return timer_type_ != GPUTiming::kTimerTypeInvalid;
167 bool GPUTimingClient::IsTimerOffsetAvailable() {
168 return timer_type_ == GPUTiming::kTimerTypeARB ||
169 timer_type_ == GPUTiming::kTimerTypeDisjoint;
172 const char* GPUTimingClient::GetTimerTypeName() const {
173 switch (timer_type_) {
174 case GPUTiming::kTimerTypeDisjoint:
175 return "GL_EXT_disjoint_timer_query";
176 case GPUTiming::kTimerTypeARB:
177 return "GL_ARB_timer_query";
178 case GPUTiming::kTimerTypeEXT:
179 return "GL_EXT_timer_query";
180 default:
181 return "Unknown";
185 bool GPUTimingClient::CheckAndResetTimerErrors() {
186 if (timer_type_ == GPUTiming::kTimerTypeDisjoint) {
187 DCHECK(gpu_timing_ != nullptr);
188 const uint32_t total_disjoint_count = gpu_timing_->GetDisjointCount();
189 const bool disjoint_triggered = total_disjoint_count != disjoint_counter_;
190 disjoint_counter_ = total_disjoint_count;
191 return disjoint_triggered;
193 return false;
196 int64 GPUTimingClient::CalculateTimerOffset() {
197 DCHECK(IsTimerOffsetAvailable());
198 if (!offset_valid_) {
199 GLint64 gl_now = 0;
200 glGetInteger64v(GL_TIMESTAMP, &gl_now);
201 int64 now =
202 cpu_time_for_testing_.is_null()
203 ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue()
204 : cpu_time_for_testing_.Run();
205 offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond;
206 offset_valid_ = timer_type_ == GPUTiming::kTimerTypeARB;
208 return offset_;
211 void GPUTimingClient::InvalidateTimerOffset() {
212 offset_valid_ = false;
215 void GPUTimingClient::SetCpuTimeForTesting(
216 const base::Callback<int64(void)>& cpu_time) {
217 cpu_time_for_testing_ = cpu_time;
220 GPUTimingClient::~GPUTimingClient() {
223 } // namespace gfx